hlquery-node-client 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/Request.js ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * hlquery Node.js Client - HTTP Request Handler
3
+ *
4
+ * Copyright (C) 2021-2026, Carlos F. Ferry <carlos.ferry@gmail.com>
5
+ *
6
+ * This file is part of hlquery, released under the BSD License version 3.
7
+ */
8
+
9
+ const https = require('https');
10
+ const http = require('http');
11
+ const { URL } = require('url');
12
+ const { RequestException, AuthenticationException, DemoModeException } = require('./Exceptions');
13
+ const Response = require('./Response');
14
+
15
+ /**
16
+ * HTTP request handler
17
+ */
18
+ class Request {
19
+ constructor(baseUrl, timeout = 30000, authToken = null, authMethod = 'bearer') {
20
+ this.baseUrl = baseUrl.replace(/\/$/, '');
21
+ this.timeout = timeout;
22
+ this.authToken = authToken;
23
+ this.authMethod = authMethod;
24
+ }
25
+
26
+ setAuthToken(token, method = 'bearer') {
27
+ this.authToken = token;
28
+ this.authMethod = method;
29
+ }
30
+
31
+ clearAuth() {
32
+ this.authToken = null;
33
+ }
34
+
35
+ /**
36
+ * Make HTTP request
37
+ *
38
+ * @param {string} method HTTP method
39
+ * @param {string} path API path
40
+ * @param {object|string|null} body Request body
41
+ * @param {object} queryParams Query parameters
42
+ * @returns {Promise<Response>}
43
+ * @throws {RequestException}
44
+ */
45
+ async execute(method, path, body = null, queryParams = {}) {
46
+ const url = new URL(this.baseUrl + path);
47
+
48
+ // Add query parameters
49
+ Object.keys(queryParams).forEach(key => {
50
+ if (queryParams[key] !== undefined && queryParams[key] !== null) {
51
+ url.searchParams.append(key, queryParams[key]);
52
+ }
53
+ });
54
+
55
+ const headers = {
56
+ 'Content-Type': 'application/json',
57
+ 'Accept': 'application/json'
58
+ };
59
+
60
+ // Prepare body string if present
61
+ let bodyStr = null;
62
+ if (body !== null) {
63
+ bodyStr = typeof body === 'string' ? body : JSON.stringify(body);
64
+ headers['Content-Length'] = Buffer.byteLength(bodyStr);
65
+ }
66
+
67
+ // Add authentication header if token is set
68
+ if (this.authToken !== null) {
69
+ if (this.authMethod === 'api-key') {
70
+ headers['X-API-Key'] = this.authToken;
71
+ } else {
72
+ headers['Authorization'] = `Bearer ${this.authToken}`;
73
+ }
74
+ }
75
+
76
+ const options = {
77
+ method: method,
78
+ headers: headers,
79
+ timeout: this.timeout
80
+ };
81
+
82
+ const client = url.protocol === 'https:' ? https : http;
83
+
84
+ return new Promise((resolve, reject) => {
85
+ const req = client.request(url, options, (res) => {
86
+ const responseHeaders = {};
87
+ Object.keys(res.headers).forEach(key => {
88
+ responseHeaders[key.toLowerCase()] = res.headers[key];
89
+ });
90
+
91
+ let data = '';
92
+
93
+ res.on('data', (chunk) => {
94
+ data += chunk;
95
+ });
96
+
97
+ res.on('end', () => {
98
+ let decoded;
99
+ try {
100
+ decoded = data ? JSON.parse(data) : null;
101
+ } catch (e) {
102
+ // If JSON parsing fails, return raw response
103
+ decoded = data;
104
+ }
105
+
106
+ // Check for demo mode errors
107
+ if (res.statusCode === 403 && decoded && typeof decoded === 'object') {
108
+ const errorMsg = decoded.error || decoded.message || '';
109
+ if (errorMsg.includes('Demo mode is enabled') ||
110
+ errorMsg.includes('Operation not allowed') ||
111
+ errorMsg.includes('Write operations are not allowed')) {
112
+ return reject(new DemoModeException(
113
+ `Demo mode is enabled on the server. Write operations are blocked. Only search and read operations are permitted. Server message: ${decoded.message || decoded.error}`
114
+ ));
115
+ }
116
+ // Check if server rejected token because auth is disabled
117
+ if (errorMsg.includes('Authentication is disabled') ||
118
+ errorMsg.includes('Tokens are not accepted when authentication is disabled')) {
119
+ return reject(new AuthenticationException(
120
+ `Authentication is disabled on the server. Remove the token from your client configuration. Server message: ${decoded.message || decoded.error}`
121
+ ));
122
+ }
123
+ }
124
+
125
+ resolve(new Response(res.statusCode, decoded, responseHeaders));
126
+ });
127
+ });
128
+
129
+ req.on('error', (error) => {
130
+ reject(new RequestException(`Request failed: ${error.message}`, 0));
131
+ });
132
+
133
+ req.on('timeout', () => {
134
+ req.destroy();
135
+ reject(new RequestException('Request timeout', 0));
136
+ });
137
+
138
+ if (bodyStr !== null) {
139
+ req.write(bodyStr);
140
+ }
141
+
142
+ req.end();
143
+ });
144
+ }
145
+ }
146
+
147
+ module.exports = Request;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * hlquery Node.js Client - Response Handler
3
+ *
4
+ * Copyright (C) 2021-2026, Carlos F. Ferry <carlos.ferry@gmail.com>
5
+ *
6
+ * This file is part of hlquery, released under the BSD License version 3.
7
+ */
8
+
9
+ /**
10
+ * Response wrapper for API responses
11
+ */
12
+ class Response {
13
+ constructor(statusCode, body, headers = {}) {
14
+ this.statusCode = statusCode;
15
+ this.body = body;
16
+ this.headers = headers;
17
+ }
18
+
19
+ getStatusCode() {
20
+ return this.statusCode;
21
+ }
22
+
23
+ getBody() {
24
+ return this.body;
25
+ }
26
+
27
+ getHeaders() {
28
+ return this.headers;
29
+ }
30
+
31
+ isSuccess() {
32
+ return this.statusCode >= 200 && this.statusCode < 300;
33
+ }
34
+
35
+ isError() {
36
+ return this.statusCode >= 400;
37
+ }
38
+
39
+ getError() {
40
+ if (this.isError() && typeof this.body === 'object' && this.body !== null) {
41
+ return this.body.error || this.body.message || 'Unknown error';
42
+ }
43
+ return null;
44
+ }
45
+
46
+ toArray() {
47
+ return {
48
+ status: this.statusCode,
49
+ body: this.body
50
+ };
51
+ }
52
+ }
53
+
54
+ module.exports = Response;
package/lib/Search.js ADDED
@@ -0,0 +1,350 @@
1
+ /**
2
+ * hlquery Node.js Client - Search API
3
+ *
4
+ * Copyright (C) 2021-2026, Carlos F. Ferry <carlos.ferry@gmail.com>
5
+ *
6
+ * This file is part of hlquery, released under the BSD License version 3.
7
+ */
8
+
9
+ const Validator = require('../utils/Validator');
10
+
11
+ /**
12
+ * Search API operations
13
+ */
14
+ class Search {
15
+ constructor(request, collections) {
16
+ this.request = request;
17
+ this.collections = collections;
18
+ }
19
+
20
+ /**
21
+ * Search documents
22
+ *
23
+ * @param {string} collectionName
24
+ * @param {object} params Search parameters
25
+ * @returns {Promise<Response>}
26
+ */
27
+ async search(collectionName, params = {}) {
28
+ return await this._searchCollection(collectionName, params, false);
29
+ }
30
+
31
+ /**
32
+ * Execute a collection-bound SQL SELECT through the search endpoint.
33
+ *
34
+ * @param {string} collectionName
35
+ * @param {string} sql
36
+ * @param {object} params
37
+ * @returns {Promise<Response>}
38
+ */
39
+ async sql(collectionName, sql, params = {}) {
40
+ Validator.validateCollectionName(collectionName);
41
+
42
+ if (typeof sql !== 'string' || sql.trim() === '') {
43
+ throw new Error('SQL query must be a non-empty string');
44
+ }
45
+
46
+ if (params === null || typeof params !== 'object' || Array.isArray(params)) {
47
+ throw new Error('SQL params must be an object');
48
+ }
49
+
50
+ const queryParams = { ...params, sql };
51
+
52
+ return await this.request.execute(
53
+ 'GET',
54
+ `/collections/${encodeURIComponent(collectionName)}/documents/search`,
55
+ null,
56
+ queryParams
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Search documents through the legacy /documents/search route.
62
+ *
63
+ * @param {string} collectionName
64
+ * @param {object} params
65
+ * @returns {Promise<Response>}
66
+ */
67
+ async searchLegacy(collectionName, params = {}) {
68
+ return await this._searchCollection(collectionName, params, true);
69
+ }
70
+
71
+ async _searchCollection(collectionName, params = {}, useLegacyPath = false) {
72
+ Validator.validateCollectionName(collectionName);
73
+ Validator.validateSearchParams(params);
74
+
75
+ const queryParams = {};
76
+
77
+ // Handle structured query object (Elasticsearch-like)
78
+ if (params.query) {
79
+ if (params.query.q) {
80
+ queryParams.q = params.query.q;
81
+ }
82
+ if (params.query.query_by) {
83
+ queryParams.query_by = Array.isArray(params.query.query_by)
84
+ ? params.query.query_by.join(',')
85
+ : params.query.query_by;
86
+ }
87
+ }
88
+
89
+ // Direct query parameters
90
+ if (params.q) {
91
+ queryParams.q = params.q;
92
+ }
93
+
94
+ // Fields to search in
95
+ if (params.query_by) {
96
+ queryParams.query_by = Array.isArray(params.query_by)
97
+ ? params.query_by.join(',')
98
+ : params.query_by;
99
+ } else if (params.q && params.q !== '') {
100
+ // Auto-detect searchable fields
101
+ const collection = await this.collections.get(collectionName);
102
+ if (collection.getStatusCode() === 200) {
103
+ const body = collection.getBody();
104
+ if (body.searchable_fields && body.searchable_fields.length > 0) {
105
+ queryParams.query_by = body.searchable_fields.join(',');
106
+ }
107
+ }
108
+ }
109
+
110
+ // Pagination
111
+ if (params.from !== undefined) {
112
+ queryParams.offset = params.from;
113
+ } else if (params.offset !== undefined) {
114
+ queryParams.offset = params.offset;
115
+ }
116
+
117
+ if (params.size !== undefined) {
118
+ queryParams.limit = params.size;
119
+ } else if (params.limit !== undefined) {
120
+ queryParams.limit = params.limit;
121
+ }
122
+
123
+ // Page-based pagination
124
+ if (params.page !== undefined) {
125
+ queryParams.page = params.page;
126
+ }
127
+ if (params.per_page !== undefined) {
128
+ queryParams.per_page = params.per_page;
129
+ }
130
+
131
+ // Filter
132
+ if (params.filter_by) {
133
+ queryParams.filter_by = params.filter_by;
134
+ } else if (params.filter) {
135
+ queryParams.filter_by = typeof params.filter === 'object'
136
+ ? JSON.stringify(params.filter)
137
+ : params.filter;
138
+ }
139
+
140
+ // Sort
141
+ if (params.sort) {
142
+ if (Array.isArray(params.sort)) {
143
+ const sortFields = [];
144
+ for (const sortItem of params.sort) {
145
+ if (typeof sortItem === 'object') {
146
+ for (const [field, order] of Object.entries(sortItem)) {
147
+ sortFields.push(order === 'desc' ? `-${field}` : field);
148
+ }
149
+ } else {
150
+ sortFields.push(sortItem);
151
+ }
152
+ }
153
+ queryParams.sort_by = sortFields.join(',');
154
+ } else {
155
+ queryParams.sort_by = params.sort;
156
+ }
157
+ } else if (params.sort_by) {
158
+ queryParams.sort_by = Array.isArray(params.sort_by)
159
+ ? params.sort_by.join(',')
160
+ : params.sort_by;
161
+ }
162
+
163
+ // Facets
164
+ if (params.facet_by) {
165
+ queryParams.facet_by = Array.isArray(params.facet_by)
166
+ ? params.facet_by.join(',')
167
+ : params.facet_by;
168
+ } else if (params.facets) {
169
+ queryParams.facet_by = Array.isArray(params.facets)
170
+ ? params.facets.join(',')
171
+ : params.facets;
172
+ }
173
+
174
+ // Additional search parameters
175
+ if (params.typo_tolerance !== undefined) {
176
+ queryParams.typo_tolerance = params.typo_tolerance;
177
+ }
178
+
179
+ if (params.num_typos !== undefined) {
180
+ queryParams.num_typos = params.num_typos;
181
+ }
182
+
183
+ // Highlighting parameters
184
+ if (params.highlight !== undefined) {
185
+ queryParams.highlight = params.highlight === true || params.highlight === 'true' ? 'true' : 'false';
186
+ }
187
+
188
+ if (params.highlight_fields !== undefined) {
189
+ queryParams.highlight_fields = Array.isArray(params.highlight_fields)
190
+ ? params.highlight_fields.join(',')
191
+ : params.highlight_fields;
192
+ }
193
+
194
+ if (params.highlight_full_fields !== undefined) {
195
+ queryParams.highlight_full_fields = Array.isArray(params.highlight_full_fields)
196
+ ? params.highlight_full_fields.join(',')
197
+ : params.highlight_full_fields;
198
+ }
199
+
200
+ // Determine HTTP method
201
+ const method = params.body ? 'POST' : 'GET';
202
+ const body = params.body || null;
203
+
204
+ const path = useLegacyPath
205
+ ? `/collections/${encodeURIComponent(collectionName)}/documents/search`
206
+ : `/collections/${encodeURIComponent(collectionName)}/search`;
207
+
208
+ return await this.request.execute(method, path, body, queryParams);
209
+ }
210
+
211
+ /**
212
+ * Multi-search across multiple collections
213
+ *
214
+ * @param {Array} searches Array of search requests
215
+ * @returns {Promise<Response>}
216
+ */
217
+ async multiSearch(searches) {
218
+ return await this.request.execute('POST', '/multi_search', { searches: searches });
219
+ }
220
+
221
+ /**
222
+ * Global search across collections.
223
+ *
224
+ * @param {object} params
225
+ * @returns {Promise<Response>}
226
+ */
227
+ async globalSearch(params = {}) {
228
+ Validator.validateSearchParams(params);
229
+
230
+ const method = params.body ? 'POST' : 'GET';
231
+ const body = params.body || (method === 'POST' ? params : null);
232
+ const queryParams = method === 'GET' ? params : {};
233
+
234
+ return await this.request.execute(method, '/search', body, queryParams);
235
+ }
236
+
237
+ /**
238
+ * Vector search
239
+ *
240
+ * @param {string} collectionName
241
+ * @param {object} params Vector search parameters:
242
+ * - vector_query: Array of floats or JSON string
243
+ * - vectorQuery: Array/object alias for vector_query
244
+ * - vector: Array of floats or JSON string (alias for vector_query)
245
+ * - embedding: Array of floats or JSON string (alias for vector_query)
246
+ * - field_name/field/fieldName: Field name to search in (default: 'embedding')
247
+ * - limit/topk/top_k/k/per_page: Number of results
248
+ * - threshold: Similarity threshold (default: 0.0)
249
+ * - normalize: Normalize vectors (default: true)
250
+ * - output_fields/outputFields, include_vector/includeVector, include_distance/includeDistance
251
+ * - radius/max_distance, range_filter/min_distance
252
+ * - query_params/queryParams/params, filter/filter_by/filterBy
253
+ * @returns {Promise<Response>}
254
+ */
255
+ async vectorSearch(collectionName, params = {}) {
256
+ Validator.validateCollectionName(collectionName);
257
+
258
+ const queryParams = {};
259
+ let forcePost = false;
260
+
261
+ // Handle vector query
262
+ if (params.vector_query) {
263
+ queryParams.vector_query = Array.isArray(params.vector_query)
264
+ ? JSON.stringify(params.vector_query)
265
+ : params.vector_query;
266
+ } else if (params.vectorQuery) {
267
+ queryParams.vector_query = Array.isArray(params.vectorQuery) || typeof params.vectorQuery === 'object'
268
+ ? JSON.stringify(params.vectorQuery)
269
+ : params.vectorQuery;
270
+ } else if (params.vector) {
271
+ queryParams.vector_query = Array.isArray(params.vector)
272
+ ? JSON.stringify(params.vector)
273
+ : params.vector;
274
+ } else if (params.embedding) {
275
+ queryParams.vector_query = Array.isArray(params.embedding)
276
+ ? JSON.stringify(params.embedding)
277
+ : params.embedding;
278
+ }
279
+
280
+ if (params.field_name || params.field || params.fieldName) {
281
+ queryParams.field_name = params.field_name || params.field || params.fieldName;
282
+ }
283
+
284
+ if (params.limit !== undefined || params.topk !== undefined || params.top_k !== undefined || params.topK !== undefined ||
285
+ params.k !== undefined || params.per_page !== undefined) {
286
+ queryParams.limit = params.limit ?? params.topk ?? params.top_k ?? params.topK ?? params.k ?? params.per_page;
287
+ }
288
+
289
+ if (params.threshold !== undefined) {
290
+ queryParams.threshold = params.threshold;
291
+ }
292
+
293
+ if (params.normalize !== undefined) {
294
+ queryParams.normalize = params.normalize ? 'true' : 'false';
295
+ }
296
+
297
+ if (params.output_fields !== undefined || params.outputFields !== undefined) {
298
+ const outputFields = params.output_fields ?? params.outputFields;
299
+ queryParams.output_fields = Array.isArray(outputFields)
300
+ ? outputFields.join(',')
301
+ : outputFields;
302
+ }
303
+
304
+ if (params.include_vector !== undefined || params.includeVector !== undefined) {
305
+ const includeVector = params.include_vector ?? params.includeVector;
306
+ queryParams.include_vector = includeVector ? 'true' : 'false';
307
+ }
308
+
309
+ if (params.include_distance !== undefined || params.includeDistance !== undefined) {
310
+ const includeDistance = params.include_distance ?? params.includeDistance;
311
+ queryParams.include_distance = includeDistance ? 'true' : 'false';
312
+ }
313
+
314
+ if (params.filter_by !== undefined) {
315
+ queryParams.filter_by = params.filter_by;
316
+ } else if (params.filterBy !== undefined) {
317
+ queryParams.filter_by = params.filterBy;
318
+ } else if (params.filter !== undefined) {
319
+ queryParams.filter_by = typeof params.filter === 'object'
320
+ ? JSON.stringify(params.filter)
321
+ : params.filter;
322
+ }
323
+
324
+ if (params.radius !== undefined) {
325
+ queryParams.radius = params.radius;
326
+ }
327
+ if (params.max_distance !== undefined || params.maxDistance !== undefined) {
328
+ queryParams.max_distance = params.max_distance ?? params.maxDistance;
329
+ }
330
+ if (params.range_filter !== undefined || params.rangeFilter !== undefined) {
331
+ queryParams.range_filter = params.range_filter ?? params.rangeFilter;
332
+ }
333
+ if (params.min_distance !== undefined || params.minDistance !== undefined) {
334
+ queryParams.min_distance = params.min_distance ?? params.minDistance;
335
+ }
336
+
337
+ if (params.query_params !== undefined || params.queryParams !== undefined || params.params !== undefined ||
338
+ params.vector_queries !== undefined || params.vectorQueries !== undefined || params.vectorQuery !== undefined) {
339
+ forcePost = true;
340
+ }
341
+
342
+ const path = `/collections/${encodeURIComponent(collectionName)}/vector_search`;
343
+ const method = params.body || forcePost ? 'POST' : 'GET';
344
+ const body = params.body || (forcePost ? params : null);
345
+
346
+ return await this.request.execute(method, path, body, queryParams);
347
+ }
348
+ }
349
+
350
+ module.exports = Search;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * hlquery Node.js Client - Stopwords API
3
+ *
4
+ * Copyright (C) 2021-2026, Carlos F. Ferry <carlos.ferry@gmail.com>
5
+ *
6
+ * This file is part of hlquery, released under the BSD License version 3.
7
+ */
8
+
9
+ const Validator = require('../utils/Validator');
10
+ const { ValidationException } = require('./Exceptions');
11
+
12
+ function validateWord(word, fieldName = 'word') {
13
+ if (!word || typeof word !== 'string' || word.trim() === '') {
14
+ throw new ValidationException(`${fieldName} must be a non-empty string`);
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Stopwords API operations
20
+ */
21
+ class Stopwords {
22
+ constructor(request) {
23
+ this.request = request;
24
+ }
25
+
26
+ async list(collectionName) {
27
+ Validator.validateCollectionName(collectionName);
28
+ return await this.request.execute('GET', `/collections/${encodeURIComponent(collectionName)}/stopwords`);
29
+ }
30
+
31
+ async create(collectionName, params) {
32
+ Validator.validateCollectionName(collectionName);
33
+ return await this.request.execute('POST', `/collections/${encodeURIComponent(collectionName)}/stopwords`, params);
34
+ }
35
+
36
+ async delete(collectionName, word) {
37
+ Validator.validateCollectionName(collectionName);
38
+ validateWord(word);
39
+ return await this.request.execute('DELETE', `/collections/${encodeURIComponent(collectionName)}/stopwords/${encodeURIComponent(word)}`);
40
+ }
41
+
42
+ async listAll() {
43
+ return await this.request.execute('GET', '/stopwords');
44
+ }
45
+
46
+ async listGlobal() {
47
+ return await this.request.execute('GET', '/stopwords/global');
48
+ }
49
+
50
+ async createGlobal(params) {
51
+ return await this.request.execute('POST', '/stopwords/global', params);
52
+ }
53
+
54
+ async deleteGlobal(word) {
55
+ validateWord(word);
56
+ return await this.request.execute('DELETE', `/stopwords/global/${encodeURIComponent(word)}`);
57
+ }
58
+ }
59
+
60
+ module.exports = Stopwords;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * hlquery Node.js Client - Synonyms API
3
+ *
4
+ * Copyright (C) 2021-2026, Carlos F. Ferry <carlos.ferry@gmail.com>
5
+ *
6
+ * This file is part of hlquery, released under the BSD License version 3.
7
+ */
8
+
9
+ const Validator = require('../utils/Validator');
10
+
11
+ /**
12
+ * Synonyms API operations
13
+ */
14
+ class Synonyms {
15
+ constructor(request) {
16
+ this.request = request;
17
+ }
18
+
19
+ async list(collectionName) {
20
+ Validator.validateCollectionName(collectionName);
21
+ return await this.request.execute('GET', `/collections/${encodeURIComponent(collectionName)}/synonyms`);
22
+ }
23
+
24
+ async get(collectionName, id) {
25
+ Validator.validateCollectionName(collectionName);
26
+ Validator.validateDocumentId(id);
27
+ return await this.request.execute('GET', `/collections/${encodeURIComponent(collectionName)}/synonyms/${encodeURIComponent(id)}`);
28
+ }
29
+
30
+ async create(collectionName, id, synonym) {
31
+ Validator.validateCollectionName(collectionName);
32
+ Validator.validateDocumentId(id);
33
+ return await this.request.execute('POST', `/collections/${encodeURIComponent(collectionName)}/synonyms/${encodeURIComponent(id)}`, synonym);
34
+ }
35
+
36
+ async update(collectionName, id, synonym) {
37
+ Validator.validateCollectionName(collectionName);
38
+ Validator.validateDocumentId(id);
39
+ return await this.request.execute('PUT', `/collections/${encodeURIComponent(collectionName)}/synonyms/${encodeURIComponent(id)}`, synonym);
40
+ }
41
+
42
+ async upsert(collectionName, id, synonym) {
43
+ return await this.create(collectionName, id, synonym);
44
+ }
45
+
46
+ async delete(collectionName, id) {
47
+ Validator.validateCollectionName(collectionName);
48
+ Validator.validateDocumentId(id);
49
+ return await this.request.execute('DELETE', `/collections/${encodeURIComponent(collectionName)}/synonyms/${encodeURIComponent(id)}`);
50
+ }
51
+
52
+ async listAll() {
53
+ return await this.request.execute('GET', '/synonyms');
54
+ }
55
+
56
+ async listGlobal() {
57
+ return await this.request.execute('GET', '/synonyms/global');
58
+ }
59
+
60
+ async getGlobal(id) {
61
+ Validator.validateDocumentId(id);
62
+ return await this.request.execute('GET', `/synonyms/global/${encodeURIComponent(id)}`);
63
+ }
64
+
65
+ async createGlobal(id, synonym) {
66
+ Validator.validateDocumentId(id);
67
+ return await this.request.execute('POST', `/synonyms/global/${encodeURIComponent(id)}`, synonym);
68
+ }
69
+
70
+ async updateGlobal(id, synonym) {
71
+ Validator.validateDocumentId(id);
72
+ return await this.request.execute('PUT', `/synonyms/global/${encodeURIComponent(id)}`, synonym);
73
+ }
74
+
75
+ async upsertGlobal(id, synonym) {
76
+ return await this.createGlobal(id, synonym);
77
+ }
78
+
79
+ async deleteGlobal(id) {
80
+ Validator.validateDocumentId(id);
81
+ return await this.request.execute('DELETE', `/synonyms/global/${encodeURIComponent(id)}`);
82
+ }
83
+ }
84
+
85
+ module.exports = Synonyms;