hlquery-node-client 1.0.0 → 1.0.2
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/README.md +106 -229
- package/example.js +32 -1
- package/examples/sam.js +39 -0
- package/examples/sql.js +31 -0
- package/index.js +1 -0
- package/lib/Client.js +55 -0
- package/lib/SAM.js +161 -0
- package/lib/conformance.js +13 -0
- package/package.json +4 -12
- package/test/offline-smoke.js +79 -0
package/README.md
CHANGED
|
@@ -4,30 +4,39 @@
|
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
|
-
**A modular Node.js client library for hlquery.**
|
|
7
|
+
**A modular Node.js client library for hlquery, designed with a familiar and intuitive API structure.**
|
|
8
8
|
|
|
9
9
|
[](https://x.com/hlquery)
|
|
10
10
|
[](https://github.com/hlquery/node-api/pulse)
|
|
11
|
-
[](https://github.com/hlquery/node-api/stargazers)
|
|
12
|
+
[](https://github.com/hlquery/hlquery/stargazers)
|
|
12
13
|
[](https://opensource.org/licenses/BSD-3-Clause)
|
|
13
14
|
|
|
14
15
|
</div>
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
### What is the hlquery Node.js API?
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
The hlquery Node.js API is the official Node.js client for hlquery. It wraps the REST interface in a modular service-style client with helpers for collections, documents, search, SQL, and SAM.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
It is a good fit for backend services, scripts, dashboards, and apps that want hlquery integration without repeating request code.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
npm install hlquery-node-client
|
|
24
|
-
```
|
|
23
|
+
### Why use it?
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
Use the Node.js client when you want hlquery calls to read like regular application code. The client is organized around familiar modules such as `client.collections()`, `client.documents()`, and `client.sam()`, so collection management, document indexing, search, SQL, and SAM workflows stay easy to find.
|
|
26
|
+
|
|
27
|
+
It also keeps the repetitive parts in one place: authentication, request parameters, endpoint paths, and parsed responses are handled consistently across the client. Common hlquery workflows are covered by default, while raw request access is still available when you need a custom route.
|
|
28
|
+
|
|
29
|
+
### Why choose it over raw HTTP?
|
|
30
|
+
|
|
31
|
+
Choose the Node.js client over raw HTTP when you want less repetitive `fetch` or `axios` boilerplate, cleaner handling for auth headers and endpoint paths, and search or indexing code that stays easier to read.
|
|
32
|
+
|
|
33
|
+
### Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
$ npm install hlquery-node-client
|
|
28
37
|
```
|
|
29
38
|
|
|
30
|
-
For local development
|
|
39
|
+
For local development inside this repository:
|
|
31
40
|
|
|
32
41
|
```javascript
|
|
33
42
|
const Client = require('./lib/Client');
|
|
@@ -38,279 +47,147 @@ const Client = require('./lib/Client');
|
|
|
38
47
|
```javascript
|
|
39
48
|
const Client = require('hlquery-node-client');
|
|
40
49
|
|
|
41
|
-
const client = new Client(process.env.HLQ_BASE_URL || 'http://localhost:9200', {
|
|
50
|
+
const client = new Client(process.env.HLQ_BASE_URL || process.env.HLQUERY_BASE_URL || 'http://localhost:9200', {
|
|
42
51
|
token: process.env.HLQ_TOKEN,
|
|
43
|
-
auth_method: 'bearer'
|
|
52
|
+
auth_method: 'bearer'
|
|
44
53
|
});
|
|
45
54
|
|
|
46
55
|
const health = await client.system().health();
|
|
56
|
+
/* Print the HTTP status code from the health response. */
|
|
47
57
|
console.log('status:', health.getStatusCode());
|
|
48
58
|
|
|
49
59
|
const collections = await client.collections().list(0, 10);
|
|
60
|
+
/* Print the collection list response body. */
|
|
50
61
|
console.log(collections.getBody());
|
|
51
|
-
|
|
52
|
-
await client.collections().create('books', {
|
|
53
|
-
fields: [
|
|
54
|
-
{ name: 'title', type: 'string' },
|
|
55
|
-
{ name: 'content', type: 'string' }
|
|
56
|
-
]
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
await client.documents().add('books', {
|
|
60
|
-
id: 'book-1',
|
|
61
|
-
title: 'Designing Data-Intensive Applications',
|
|
62
|
-
content: 'Distributed systems, data models, replication, and indexing.'
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const results = await client.searchApi().search('books', {
|
|
66
|
-
q: 'distributed systems',
|
|
67
|
-
query_by: 'title,content',
|
|
68
|
-
limit: 10
|
|
69
|
-
});
|
|
70
|
-
console.log(results.getBody());
|
|
71
62
|
```
|
|
72
63
|
|
|
73
|
-
|
|
64
|
+
### Auth
|
|
74
65
|
|
|
75
66
|
```javascript
|
|
67
|
+
const client = new Client('http://localhost:9200', {
|
|
68
|
+
token: 'your_token_here',
|
|
69
|
+
auth_method: 'bearer'
|
|
70
|
+
});
|
|
71
|
+
|
|
76
72
|
client.setAuthToken('your_token_here', 'bearer');
|
|
77
73
|
client.setAuthToken('your_api_key_here', 'api-key');
|
|
78
74
|
```
|
|
79
75
|
|
|
80
|
-
###
|
|
76
|
+
### Operational routes
|
|
81
77
|
|
|
82
|
-
|
|
78
|
+
The client includes wrappers for the common server and cluster routes used by dashboards, scripts, and maintenance jobs:
|
|
83
79
|
|
|
84
80
|
```javascript
|
|
85
|
-
client.
|
|
86
|
-
client.
|
|
87
|
-
client.
|
|
88
|
-
client.system().status();
|
|
89
|
-
client.system().metrics();
|
|
90
|
-
client.system().connections();
|
|
91
|
-
client.system().rocksdb();
|
|
92
|
-
|
|
93
|
-
client.collections().list(offset, limit);
|
|
94
|
-
client.collections().get(name);
|
|
95
|
-
client.collections().create(name, schema);
|
|
96
|
-
client.collections().update(name, schema);
|
|
97
|
-
client.collections().delete(name);
|
|
98
|
-
client.collections().getFields(name);
|
|
99
|
-
|
|
100
|
-
client.documents().list(collection, params);
|
|
101
|
-
client.documents().get(collection, id);
|
|
102
|
-
client.documents().add(collection, document);
|
|
103
|
-
client.documents().update(collection, id, document);
|
|
104
|
-
client.documents().delete(collection, id);
|
|
105
|
-
client.documents().import(collection, documents);
|
|
106
|
-
client.documents().export(collection, params);
|
|
107
|
-
client.documents().facetCounts(collection, params);
|
|
108
|
-
client.documents().addCSV(collection, filePath, options);
|
|
109
|
-
|
|
110
|
-
client.searchApi().search(collection, params);
|
|
111
|
-
client.searchApi().vectorSearch(collection, params);
|
|
112
|
-
client.searchApi().multiSearch(searches);
|
|
113
|
-
client.searchApi().globalSearch(params);
|
|
114
|
-
client.searchApi().sql(collection, sql);
|
|
115
|
-
|
|
116
|
-
client.aliases().create(name, params);
|
|
117
|
-
client.aliases().update(name, params);
|
|
118
|
-
client.aliases().delete(name);
|
|
119
|
-
client.synonyms().create(collection, id, synonym);
|
|
120
|
-
client.stopwords().create(collection, params);
|
|
121
|
-
client.overrides().create(collection, id, override);
|
|
122
|
-
client.keys().create(params);
|
|
123
|
-
client.executeRequest(method, path, body, query);
|
|
124
|
-
```
|
|
81
|
+
const status = await client.status();
|
|
82
|
+
const health = await client.health();
|
|
83
|
+
const etc = await client.etc();
|
|
125
84
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
await collections.create('books', {
|
|
132
|
-
fields: [
|
|
133
|
-
{ name: 'title', type: 'string' },
|
|
134
|
-
{ name: 'content', type: 'string' },
|
|
135
|
-
{ name: 'category', type: 'string', facet: true }
|
|
136
|
-
]
|
|
137
|
-
});
|
|
85
|
+
const links = await client.links();
|
|
86
|
+
const ping = await client.linksPing();
|
|
87
|
+
const connect = await client.linksConnect('http://node-b:9200');
|
|
88
|
+
const disconnect = await client.linksDisconnect('http://node-b:9200');
|
|
138
89
|
|
|
139
|
-
await
|
|
140
|
-
await collections.getFields('books');
|
|
141
|
-
await collections.update('books', schema);
|
|
142
|
-
await collections.delete('books');
|
|
90
|
+
const flush = await client.flush();
|
|
143
91
|
```
|
|
144
92
|
|
|
145
|
-
|
|
93
|
+
Routes that do not have a dedicated wrapper can still be called through `executeRequest()`:
|
|
146
94
|
|
|
147
95
|
```javascript
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
await documents.add('books', {
|
|
151
|
-
id: 'book-1',
|
|
152
|
-
title: 'Designing Data-Intensive Applications',
|
|
153
|
-
content: 'Distributed systems, data models, replication, and indexing.'
|
|
96
|
+
const response = await client.executeRequest('GET', '/modules/<name>/<route>', null, {
|
|
97
|
+
q: 'example query'
|
|
154
98
|
});
|
|
155
99
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
100
|
+
/* Print the server status response body. */
|
|
101
|
+
console.log(status.getBody());
|
|
102
|
+
/* Print the health response body. */
|
|
103
|
+
console.log(health.getBody());
|
|
104
|
+
/* Print the runtime configuration response body. */
|
|
105
|
+
console.log(etc.getBody());
|
|
106
|
+
/* Print the configured cluster links response body. */
|
|
107
|
+
console.log(links.getBody());
|
|
108
|
+
/* Print the link ping response body. */
|
|
109
|
+
console.log(ping.getBody());
|
|
110
|
+
/* Print the link connect response body. */
|
|
111
|
+
console.log(connect.getBody());
|
|
112
|
+
/* Print the link disconnect response body. */
|
|
113
|
+
console.log(disconnect.getBody());
|
|
114
|
+
/* Print the flush response body. */
|
|
115
|
+
console.log(flush.getBody());
|
|
116
|
+
/* Print the custom route response body. */
|
|
117
|
+
console.log(response.getBody());
|
|
167
118
|
```
|
|
168
119
|
|
|
169
|
-
|
|
120
|
+
### SAM
|
|
170
121
|
|
|
171
|
-
|
|
122
|
+
SAM is separate from vector search. It performs term and intent-style lookup, not vector similarity search.
|
|
172
123
|
|
|
173
124
|
```javascript
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
await search.search('books', {
|
|
177
|
-
q: 'title:database OR content:index*',
|
|
178
|
-
query_by: 'title,content',
|
|
179
|
-
filter_by: 'category:technical',
|
|
180
|
-
sort_by: '_text_match:desc',
|
|
181
|
-
facet_by: 'category',
|
|
182
|
-
limit: 10,
|
|
183
|
-
offset: 0
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
await search.multiSearch([
|
|
187
|
-
{ collection: 'books', q: 'database', query_by: 'title,content' },
|
|
188
|
-
{ collection: 'articles', q: 'database', query_by: 'title,body' }
|
|
189
|
-
]);
|
|
125
|
+
const sam = client.sam();
|
|
190
126
|
|
|
191
|
-
await
|
|
192
|
-
|
|
193
|
-
|
|
127
|
+
const status = await sam.status('books');
|
|
128
|
+
const history = await sam.history('books', 5);
|
|
129
|
+
const results = await sam.search('books', 'distributed systems', {
|
|
194
130
|
limit: 10
|
|
195
131
|
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Common search parameters:
|
|
199
132
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
133
|
+
/* Print the SAM status response body. */
|
|
134
|
+
console.log(status.getBody());
|
|
135
|
+
/* Print the SAM search history response body. */
|
|
136
|
+
console.log(history.getBody());
|
|
137
|
+
/* Print the SAM search results response body. */
|
|
138
|
+
console.log(results.getBody());
|
|
139
|
+
```
|
|
207
140
|
|
|
208
141
|
### SQL
|
|
209
142
|
|
|
210
|
-
SQL queries are supported through the search API and through the interactive talk shell.
|
|
211
|
-
|
|
212
143
|
```javascript
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
144
|
+
const rows = await client.sql('SHOW COLLECTIONS;');
|
|
145
|
+
const execResult = await client.execSql(
|
|
146
|
+
"INSERT INTO logs_archive (id, title) VALUES ('row-1', 'warm cache');"
|
|
147
|
+
);
|
|
148
|
+
const books = await client.sqlSearch(
|
|
149
|
+
'books',
|
|
150
|
+
'SELECT id, title FROM books ORDER BY title ASC LIMIT 3;'
|
|
216
151
|
);
|
|
217
152
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
153
|
+
/* Print the SQL query response body. */
|
|
154
|
+
console.log(rows.getBody());
|
|
155
|
+
/* Print the SQL execution response body. */
|
|
156
|
+
console.log(execResult.getBody());
|
|
157
|
+
/* Print the collection SQL search response body. */
|
|
158
|
+
console.log(books.getBody());
|
|
222
159
|
```
|
|
223
160
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
```text
|
|
227
|
-
localhost:9200> sql: select title,id from music LIMIT 2;
|
|
228
|
-
|
|
229
|
-
SQL rows for `select title,id from music LIMIT 2;`:
|
|
230
|
-
+--------------------------------+------------------------------------------+
|
|
231
|
-
| id | title |
|
|
232
|
-
+--------------------------------+------------------------------------------+
|
|
233
|
-
| music_artist-profile-beyonce | Artist Profile: Beyonce |
|
|
234
|
-
| music_artist-profile-kendrick- | Artist Profile: Kendrick Lamar |
|
|
235
|
-
| lamar | |
|
|
236
|
-
+--------------------------------+------------------------------------------+
|
|
237
|
-
2 results shown.
|
|
238
|
-
Search completed in 19 ms.
|
|
239
|
-
```
|
|
161
|
+
### Reduce Text Example
|
|
240
162
|
|
|
241
|
-
|
|
163
|
+
Use the raw request helper for custom module routes:
|
|
242
164
|
|
|
243
165
|
```javascript
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
const stopwords = client.stopwords();
|
|
247
|
-
const overrides = client.overrides();
|
|
248
|
-
|
|
249
|
-
await aliases.create('books_current', { collection_name: 'books_v2' });
|
|
250
|
-
|
|
251
|
-
await synonyms.create('books', 'cars', {
|
|
252
|
-
root: 'car',
|
|
253
|
-
synonyms: ['auto', 'automobile']
|
|
166
|
+
const response = await client.executeRequest('GET', '/modules/<name>/<route>', null, {
|
|
167
|
+
q: 'example query'
|
|
254
168
|
});
|
|
255
169
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
await overrides.create('books', 'boost_featured', {
|
|
259
|
-
rule: { query: 'featured', match: 'exact' },
|
|
260
|
-
includes: [{ id: 'doc-1', position: 1 }],
|
|
261
|
-
excludes: []
|
|
262
|
-
});
|
|
170
|
+
/* Print the custom module route response body. */
|
|
171
|
+
console.log(response.getBody());
|
|
263
172
|
```
|
|
264
173
|
|
|
265
|
-
###
|
|
174
|
+
### Contributing
|
|
266
175
|
|
|
267
|
-
All
|
|
176
|
+
We welcome contributions from the community! All contributions must be released under the BSD 3-Clause license.
|
|
268
177
|
|
|
269
|
-
|
|
270
|
-
const response = await client.system().health();
|
|
271
|
-
|
|
272
|
-
response.getStatusCode();
|
|
273
|
-
response.getBody();
|
|
274
|
-
response.isSuccess();
|
|
275
|
-
response.isError();
|
|
276
|
-
response.getError();
|
|
277
|
-
response.toArray();
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
### Errors
|
|
178
|
+
### How to Contribute
|
|
281
179
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const result = await client.searchApi().search('books', { q: 'test' });
|
|
287
|
-
if (result.isError()) {
|
|
288
|
-
console.log(result.getError());
|
|
289
|
-
}
|
|
290
|
-
} catch (error) {
|
|
291
|
-
if (error instanceof RequestException) {
|
|
292
|
-
console.log('request failed:', error.message, error.statusCode);
|
|
293
|
-
} else if (error instanceof AuthenticationException) {
|
|
294
|
-
console.log('auth failed:', error.message);
|
|
295
|
-
} else if (error instanceof ValidationException) {
|
|
296
|
-
console.log('validation failed:', error.message);
|
|
297
|
-
} else {
|
|
298
|
-
throw error;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
```
|
|
180
|
+
- Check existing [issues](https://github.com/hlquery/hlquery/issues) or create new ones
|
|
181
|
+
- Contribute to client libraries (Node.js, Go, Java, Python, PHP, Ruby, Rust, Perl, C++)
|
|
182
|
+
- Test and report bugs
|
|
183
|
+
- Improve documentation
|
|
302
184
|
|
|
303
|
-
###
|
|
185
|
+
### Community
|
|
304
186
|
|
|
305
|
-
-
|
|
306
|
-
-
|
|
187
|
+
- 📖 [Documentation](https://docs.hlquery.com)
|
|
188
|
+
- 🐦 [X (Twitter)](https://x.com/hlquery)
|
|
189
|
+
- 📦 [GitHub](https://github.com/hlquery/hlquery)
|
|
307
190
|
|
|
308
|
-
###
|
|
191
|
+
### License
|
|
309
192
|
|
|
310
|
-
|
|
311
|
-
- Bearer token and X-API-Key authentication.
|
|
312
|
-
- Flexible parameter formats.
|
|
313
|
-
- Automatic searchable-field detection when fields are not specified.
|
|
314
|
-
- SQL helpers for collection-bound and top-level SQL execution.
|
|
315
|
-
- Response wrapper with status, body, and error helpers.
|
|
316
|
-
- Built-in validation and async/await support.
|
|
193
|
+
hlquery is licensed under the [BSD 3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
|
package/example.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* Commands:
|
|
15
15
|
* cols - Run collections API examples
|
|
16
16
|
* docs - Run documents API examples
|
|
17
|
+
* sql - Run SQL API examples
|
|
17
18
|
* open - List and open collections (interactive)
|
|
18
19
|
* status - Show server health and status information
|
|
19
20
|
* help - Show this help message
|
|
@@ -34,7 +35,7 @@ let collectionName = null;
|
|
|
34
35
|
|
|
35
36
|
if (process.argv.length > 2) {
|
|
36
37
|
const firstArg = process.argv[2];
|
|
37
|
-
if (['cols', 'docs', 'open', 'status', 'help', 'all'].includes(firstArg)) {
|
|
38
|
+
if (['cols', 'docs', 'sql', 'open', 'status', 'help', 'all'].includes(firstArg)) {
|
|
38
39
|
command = firstArg;
|
|
39
40
|
// Parse pagination for cols command: cols [offset] [limit] [token]
|
|
40
41
|
if (command === 'cols' && process.argv.length >= 4) {
|
|
@@ -84,6 +85,7 @@ if (command === 'help') {
|
|
|
84
85
|
console.log(' docs - Run documents API examples');
|
|
85
86
|
console.log(' Usage: docs [collection_name] [token]');
|
|
86
87
|
console.log(' Example: docs my_collection');
|
|
88
|
+
console.log(' sql - Run SQL API examples');
|
|
87
89
|
console.log(' open - List and open collections (interactive)');
|
|
88
90
|
console.log(' status - Show server health and status information');
|
|
89
91
|
console.log(' help - Show this help message');
|
|
@@ -221,6 +223,34 @@ async function main() {
|
|
|
221
223
|
process.exit(0);
|
|
222
224
|
}
|
|
223
225
|
|
|
226
|
+
// ----------------------------------------------------------------====================================
|
|
227
|
+
// SQL API
|
|
228
|
+
// ----------------------------------------------------------------====================================
|
|
229
|
+
if (command === 'all' || command === 'sql') {
|
|
230
|
+
console.log('\n' + '#'.repeat(70));
|
|
231
|
+
console.log('# SQL API');
|
|
232
|
+
console.log('#'.repeat(70) + '\n');
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
// GET /sql
|
|
236
|
+
printResult('GET /sql (SHOW COLLECTIONS)', await client.sql('SHOW COLLECTIONS;'));
|
|
237
|
+
|
|
238
|
+
// Collection-bound SQL SELECT through /collections/{name}/documents/search
|
|
239
|
+
const sqlCollection = await getFirstCollection(client);
|
|
240
|
+
if (!sqlCollection) {
|
|
241
|
+
console.log('No collections available - skipping collection-bound SQL test\n');
|
|
242
|
+
} else {
|
|
243
|
+
const query = `SELECT id FROM ${sqlCollection} LIMIT 5;`;
|
|
244
|
+
printResult(
|
|
245
|
+
'GET /collections/{name}/documents/search (SQL SELECT)',
|
|
246
|
+
await client.sqlSearch(sqlCollection, query)
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
} catch (error) {
|
|
250
|
+
console.log(`Error in SQL API: ${error.message}\n`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
224
254
|
// ----------------------------------------------------------------====================================
|
|
225
255
|
// System APIs (only for 'all' command)
|
|
226
256
|
// ----------------------------------------------------------------====================================
|
|
@@ -621,6 +651,7 @@ async function main() {
|
|
|
621
651
|
console.log(' docs - Run documents API examples');
|
|
622
652
|
console.log(' Usage: docs [collection_name] [token]');
|
|
623
653
|
console.log(' Example: docs my_collection');
|
|
654
|
+
console.log(' sql - Run SQL API examples');
|
|
624
655
|
console.log(' open - List and open collections');
|
|
625
656
|
console.log(' status - Show server health and status information');
|
|
626
657
|
console.log(' help - Show help message');
|
package/examples/sam.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic SAM example for the hlquery Node.js client.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const Client = require('../index');
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
const baseUrl = process.env.HLQ_BASE_URL || process.env.HLQUERY_BASE_URL || 'http://localhost:9200';
|
|
9
|
+
const token = process.argv[2] || null;
|
|
10
|
+
const collection = process.argv[3] || 'music';
|
|
11
|
+
const query = process.argv[4] || 'queen of pop';
|
|
12
|
+
|
|
13
|
+
const client = new Client(baseUrl);
|
|
14
|
+
|
|
15
|
+
if (token) {
|
|
16
|
+
client.setAuthToken(token, 'bearer');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sam = client.sam();
|
|
20
|
+
|
|
21
|
+
const status = await sam.status(collection);
|
|
22
|
+
console.log('=== SAM STATUS ===');
|
|
23
|
+
console.log(status.getBody());
|
|
24
|
+
console.log('');
|
|
25
|
+
|
|
26
|
+
const history = await sam.history(collection, 5);
|
|
27
|
+
console.log('=== SAM HISTORY ===');
|
|
28
|
+
console.log(history.getBody());
|
|
29
|
+
console.log('');
|
|
30
|
+
|
|
31
|
+
const results = await sam.search(collection, query, { limit: 10 });
|
|
32
|
+
console.log('=== SAM SEARCH ===');
|
|
33
|
+
console.log(results.getBody());
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main().catch((error) => {
|
|
37
|
+
console.error(error);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
package/examples/sql.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL Examples
|
|
3
|
+
*
|
|
4
|
+
* Demonstrates top-level and collection-bound SQL usage with the hlquery Node.js client
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const Client = require('../lib/Client');
|
|
8
|
+
|
|
9
|
+
async function main() {
|
|
10
|
+
const client = new Client('http://localhost:9200');
|
|
11
|
+
|
|
12
|
+
// Top-level SQL through /sql
|
|
13
|
+
const rows = await client.sql('SHOW COLLECTIONS;');
|
|
14
|
+
console.log('SHOW COLLECTIONS:', rows.getBody());
|
|
15
|
+
|
|
16
|
+
// Top-level SQL statement execution through POST /sql
|
|
17
|
+
const execResult = await client.execSql(
|
|
18
|
+
"INSERT INTO logs_archive (id, title) VALUES ('row-1', 'warm cache');"
|
|
19
|
+
);
|
|
20
|
+
console.log('Exec result:', execResult.getBody());
|
|
21
|
+
|
|
22
|
+
// Collection-bound SQL SELECT through /collections/{name}/documents/search
|
|
23
|
+
const products = await client.sqlSearch(
|
|
24
|
+
'products',
|
|
25
|
+
'SELECT id, title, price FROM products WHERE price > 100 ORDER BY price DESC LIMIT 3;',
|
|
26
|
+
{ highlight: false }
|
|
27
|
+
);
|
|
28
|
+
console.log('Products SQL results:', products.getBody());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
main().catch(console.error);
|
package/index.js
CHANGED
|
@@ -24,6 +24,7 @@ module.exports.Overrides = require('./lib/Overrides');
|
|
|
24
24
|
module.exports.Synonyms = require('./lib/Synonyms');
|
|
25
25
|
module.exports.Stopwords = require('./lib/Stopwords');
|
|
26
26
|
module.exports.System = require('./lib/System');
|
|
27
|
+
module.exports.SAM = require('./lib/SAM');
|
|
27
28
|
|
|
28
29
|
// Export exceptions
|
|
29
30
|
module.exports.Exceptions = require('./lib/Exceptions');
|
package/lib/Client.js
CHANGED
|
@@ -17,6 +17,7 @@ const Overrides = require('./Overrides');
|
|
|
17
17
|
const Synonyms = require('./Synonyms');
|
|
18
18
|
const Stopwords = require('./Stopwords');
|
|
19
19
|
const System = require('./System');
|
|
20
|
+
const SAM = require('./SAM');
|
|
20
21
|
const Config = require('../utils/Config');
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -49,6 +50,7 @@ class Client {
|
|
|
49
50
|
this._synonyms = new Synonyms(this.request);
|
|
50
51
|
this._stopwords = new Stopwords(this.request);
|
|
51
52
|
this._system = new System(this.request);
|
|
53
|
+
this._sam = new SAM(this.request);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -462,6 +464,59 @@ class Client {
|
|
|
462
464
|
return this._search;
|
|
463
465
|
}
|
|
464
466
|
|
|
467
|
+
/**
|
|
468
|
+
* Get SAM API instance
|
|
469
|
+
*
|
|
470
|
+
* @returns {SAM}
|
|
471
|
+
*/
|
|
472
|
+
sam() {
|
|
473
|
+
return this._sam;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async samSearch(collectionName, query, params = {}) {
|
|
477
|
+
return await this._sam.search(collectionName, query, params);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async samSearchAll(query, params = {}) {
|
|
481
|
+
return await this._sam.searchAll(query, params);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
async samRebuild(collectionName, params = {}) {
|
|
485
|
+
return await this._sam.rebuild(collectionName, params);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async samStatus(collectionName = null, params = {}) {
|
|
489
|
+
return await this._sam.status(collectionName, params);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async samDebug(collectionName = null, params = {}) {
|
|
493
|
+
return await this._sam.debug(collectionName, params);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async samHistory(collectionName = null, limit = 100, params = {}) {
|
|
497
|
+
return await this._sam.history(collectionName, limit, params);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async samPause(pauseUntilMs, params = {}) {
|
|
501
|
+
return await this._sam.pause(pauseUntilMs, params);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async samClearPause(params = {}) {
|
|
505
|
+
return await this._sam.clearPause(params);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async samDocuments(collectionName, offset = 0, limit = 20, params = {}) {
|
|
509
|
+
return await this._sam.listDocuments(collectionName, offset, limit, params);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async samDocument(collectionName, documentId, params = {}) {
|
|
513
|
+
return await this._sam.getDocument(collectionName, documentId, params);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async samOpenDocument(collectionName, documentId, interactionQuery = null, params = {}) {
|
|
517
|
+
return await this._sam.openDocument(collectionName, documentId, interactionQuery, params);
|
|
518
|
+
}
|
|
519
|
+
|
|
465
520
|
/**
|
|
466
521
|
* Get aliases API instance
|
|
467
522
|
*
|
package/lib/SAM.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* hlquery Node.js Client - SAM 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
|
+
* SAM API operations
|
|
13
|
+
*/
|
|
14
|
+
class SAM {
|
|
15
|
+
constructor(request) {
|
|
16
|
+
this.request = request;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
_validateParams(params, label) {
|
|
20
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
21
|
+
throw new Error(`${label} must be an object`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async search(collectionName, query, params = {}) {
|
|
26
|
+
if (typeof query !== 'string' || query.trim() === '') {
|
|
27
|
+
throw new Error('SAM query must be a non-empty string');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this._validateParams(params, 'SAM search params');
|
|
31
|
+
|
|
32
|
+
const queryParams = {
|
|
33
|
+
...params,
|
|
34
|
+
q: query
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
38
|
+
Validator.validateCollectionName(collectionName);
|
|
39
|
+
queryParams.collection = collectionName;
|
|
40
|
+
} else if (!queryParams.all && !queryParams.collections) {
|
|
41
|
+
throw new Error('Collection name is required unless all=true or collections is provided');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return await this.request.execute('GET', '/sam/search', null, queryParams);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async searchAll(query, params = {}) {
|
|
48
|
+
this._validateParams(params, 'SAM search params');
|
|
49
|
+
return await this.search(null, query, { ...params, all: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async rebuild(collectionName, params = {}) {
|
|
53
|
+
Validator.validateCollectionName(collectionName);
|
|
54
|
+
this._validateParams(params, 'SAM rebuild params');
|
|
55
|
+
|
|
56
|
+
return await this.request.execute('POST', '/sam/rebuild', null, {
|
|
57
|
+
...params,
|
|
58
|
+
collection: collectionName
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async status(collectionName = null, params = {}) {
|
|
63
|
+
this._validateParams(params, 'SAM status params');
|
|
64
|
+
|
|
65
|
+
const queryParams = { ...params };
|
|
66
|
+
|
|
67
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
68
|
+
Validator.validateCollectionName(collectionName);
|
|
69
|
+
queryParams.collection = collectionName;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return await this.request.execute('GET', '/sam/status', null, queryParams);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async debug(collectionName = null, params = {}) {
|
|
76
|
+
this._validateParams(params, 'SAM debug params');
|
|
77
|
+
|
|
78
|
+
const queryParams = { ...params };
|
|
79
|
+
|
|
80
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
81
|
+
Validator.validateCollectionName(collectionName);
|
|
82
|
+
queryParams.collection = collectionName;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return await this.request.execute('GET', '/sam/debug', null, queryParams);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async history(collectionName = null, limit = 100, params = {}) {
|
|
89
|
+
this._validateParams(params, 'SAM history params');
|
|
90
|
+
|
|
91
|
+
const queryParams = {
|
|
92
|
+
...params,
|
|
93
|
+
limit: Number(limit)
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
97
|
+
Validator.validateCollectionName(collectionName);
|
|
98
|
+
queryParams.collection = collectionName;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return await this.request.execute('GET', '/sam/history', null, queryParams);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async pause(pauseUntilMs, params = {}) {
|
|
105
|
+
this._validateParams(params, 'SAM pause params');
|
|
106
|
+
|
|
107
|
+
const pause = Number(pauseUntilMs);
|
|
108
|
+
if (!Number.isFinite(pause) || pause < 0) {
|
|
109
|
+
throw new Error('SAM pause value must be a non-negative unix millisecond timestamp, or 0 to clear');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return await this.request.execute('POST', '/sam/pause', null, {
|
|
113
|
+
...params,
|
|
114
|
+
pause
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async clearPause(params = {}) {
|
|
119
|
+
return await this.pause(0, params);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async listDocuments(collectionName, offset = 0, limit = 20, params = {}) {
|
|
123
|
+
Validator.validateCollectionName(collectionName);
|
|
124
|
+
this._validateParams(params, 'SAM document list params');
|
|
125
|
+
|
|
126
|
+
return await this.request.execute('GET', '/sam/documents', null, {
|
|
127
|
+
...params,
|
|
128
|
+
collection: collectionName,
|
|
129
|
+
offset: Number(offset),
|
|
130
|
+
limit: Number(limit)
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async getDocument(collectionName, documentId, params = {}) {
|
|
135
|
+
Validator.validateCollectionName(collectionName);
|
|
136
|
+
Validator.validateDocumentId(documentId);
|
|
137
|
+
this._validateParams(params, 'SAM document params');
|
|
138
|
+
|
|
139
|
+
return await this.request.execute(
|
|
140
|
+
'GET',
|
|
141
|
+
`/sam/documents/${encodeURIComponent(collectionName)}/${encodeURIComponent(documentId)}`,
|
|
142
|
+
null,
|
|
143
|
+
params
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async openDocument(collectionName, documentId, interactionQuery = null, params = {}) {
|
|
148
|
+
const queryParams = { ...params };
|
|
149
|
+
|
|
150
|
+
if (interactionQuery !== null && interactionQuery !== undefined && interactionQuery !== '') {
|
|
151
|
+
if (typeof interactionQuery !== 'string') {
|
|
152
|
+
throw new Error('SAM interaction query must be a string');
|
|
153
|
+
}
|
|
154
|
+
queryParams.interaction_query = interactionQuery;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return await this.getDocument(collectionName, documentId, queryParams);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
module.exports = SAM;
|
package/lib/conformance.js
CHANGED
|
@@ -44,6 +44,15 @@ const NODE_CLIENT_ROUTE_COVERAGE = [
|
|
|
44
44
|
{ path: '/collections/{name}/vector_search', methods: ['GET', 'POST'], status: 'supported', client: 'search.vectorSearch' },
|
|
45
45
|
{ path: '/multi_search', methods: ['GET', 'POST'], status: 'supported', client: 'search.multiSearch' },
|
|
46
46
|
{ path: '/search', methods: ['GET', 'POST'], status: 'supported', client: 'search.globalSearch' },
|
|
47
|
+
{ path: '/sql', methods: ['GET', 'POST'], status: 'supported', client: 'system.sql/execSql' },
|
|
48
|
+
{ path: '/sam/rebuild', methods: ['POST'], status: 'supported', client: 'sam.rebuild' },
|
|
49
|
+
{ path: '/sam/search', methods: ['GET'], status: 'supported', client: 'sam.search' },
|
|
50
|
+
{ path: '/sam/status', methods: ['GET'], status: 'supported', client: 'sam.status' },
|
|
51
|
+
{ path: '/sam/debug', methods: ['GET'], status: 'supported', client: 'sam.debug' },
|
|
52
|
+
{ path: '/sam/history', methods: ['GET'], status: 'supported', client: 'sam.history' },
|
|
53
|
+
{ path: '/sam/pause', methods: ['POST'], status: 'supported', client: 'sam.pause/clearPause' },
|
|
54
|
+
{ path: '/sam/documents', methods: ['GET'], status: 'supported', client: 'sam.listDocuments' },
|
|
55
|
+
{ path: '/sam/documents/{collection}/{id}', methods: ['GET'], status: 'supported', client: 'sam.getDocument/openDocument' },
|
|
47
56
|
{ path: '/collections/{name}/documents/facet_counts', methods: ['GET', 'POST'], status: 'supported', client: 'documents.facetCounts' },
|
|
48
57
|
{ path: '/collections/{name}/documents/export', methods: ['GET', 'POST'], status: 'supported', client: 'documents.export' },
|
|
49
58
|
{ path: '/collections/{name}/synonyms', methods: ['GET'], status: 'supported', client: 'synonyms.list' },
|
|
@@ -64,6 +73,10 @@ const NODE_CLIENT_ROUTE_COVERAGE = [
|
|
|
64
73
|
{ path: '/keys/{id}', methods: ['GET', 'PUT', 'DELETE'], status: 'supported', client: 'keys.get/update/delete' },
|
|
65
74
|
{ path: '/update-counters', methods: ['GET', 'POST'], status: 'omitted', reason: 'Internal maintenance endpoint; intentionally left off the public Node client.' },
|
|
66
75
|
{ path: '/query', methods: ['GET'], status: 'omitted', reason: 'Alias of /status; client exposes status() instead of duplicate naming.' },
|
|
76
|
+
{ path: '/search-config', methods: ['GET'], status: 'omitted', reason: 'Diagnostic configuration endpoint; stable client exposes raw executeRequest() for this route.' },
|
|
77
|
+
{ path: '/ready', methods: ['GET'], status: 'omitted', reason: 'Readiness alias; client exposes startup() and bootStatus() instead of duplicate naming.' },
|
|
78
|
+
{ path: '/llm', methods: ['GET', 'POST'], status: 'omitted', reason: 'LLM runtime endpoint is module/config dependent and not part of the stable SDK surface yet.' },
|
|
79
|
+
{ path: '/repair', methods: ['POST'], status: 'omitted', reason: 'Administrative repair endpoint; intentionally left off the public Node client.' },
|
|
67
80
|
{ path: '/modules', methods: ['GET'], status: 'omitted', reason: 'Module APIs are intentionally omitted until the module surface is documented and stabilized for SDKs.' },
|
|
68
81
|
{ path: '/modules/{name}', methods: ['ANY'], status: 'omitted', reason: 'Module-specific routes are dynamic and intentionally not wrapped in the stable Node client.' },
|
|
69
82
|
{ path: '/modules/{name}/syntax', methods: ['GET'], status: 'omitted', reason: 'Module-specific routes are dynamic and intentionally not wrapped in the stable Node client.' }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hlquery-node-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Node.js client library for hlquery search engine",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"test:conformance": "node ../tests/test_node_client_conformance.js",
|
|
10
10
|
"test:offline": "node test/offline-smoke.js",
|
|
11
11
|
"example": "node example.js",
|
|
12
|
+
"example:sql": "node examples/sql.js",
|
|
12
13
|
"example:pdf": "node examples/pdf.js",
|
|
13
14
|
"example:csv": "node examples/csv.js"
|
|
14
15
|
},
|
|
@@ -28,15 +29,6 @@
|
|
|
28
29
|
},
|
|
29
30
|
"repository": {
|
|
30
31
|
"type": "git",
|
|
31
|
-
"url": "
|
|
32
|
-
}
|
|
33
|
-
"directories": {
|
|
34
|
-
"example": "examples",
|
|
35
|
-
"lib": "lib",
|
|
36
|
-
"test": "test"
|
|
37
|
-
},
|
|
38
|
-
"bugs": {
|
|
39
|
-
"url": "https://github.com/cferry/hlquery/issues"
|
|
40
|
-
},
|
|
41
|
-
"homepage": "https://github.com/cferry/hlquery#readme"
|
|
32
|
+
"url": "https://github.com/cferry/hlquery"
|
|
33
|
+
}
|
|
42
34
|
}
|
package/test/offline-smoke.js
CHANGED
|
@@ -36,6 +36,48 @@ async function main() {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
if (req.url === '/status') {
|
|
40
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
41
|
+
res.end(JSON.stringify({ status: 'ready' }));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (req.url === '/etc') {
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
47
|
+
res.end(JSON.stringify({ protocol: 'http' }));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (req.url === '/links') {
|
|
52
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
53
|
+
res.end(JSON.stringify({ links: [] }));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (req.url === '/links/ping') {
|
|
58
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
59
|
+
res.end(JSON.stringify({ ok: true }));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (req.url === '/links/connect' && req.method === 'POST') {
|
|
64
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
65
|
+
res.end(JSON.stringify({ connected: true }));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (req.url === '/links/disconnect' && req.method === 'POST') {
|
|
70
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
71
|
+
res.end(JSON.stringify({ disconnected: true }));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (req.url === '/flush' && req.method === 'POST') {
|
|
76
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
77
|
+
res.end(JSON.stringify({ flushed: true }));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
39
81
|
if (req.url === '/echo-auth') {
|
|
40
82
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
41
83
|
res.end(JSON.stringify({
|
|
@@ -73,6 +115,43 @@ async function main() {
|
|
|
73
115
|
const clientHealth = await client.health();
|
|
74
116
|
assert.strictEqual(clientHealth.isSuccess(), true);
|
|
75
117
|
assert.deepStrictEqual(clientHealth.getBody(), { status: 'ok' });
|
|
118
|
+
|
|
119
|
+
const clientStatus = await client.status();
|
|
120
|
+
assert.deepStrictEqual(clientStatus.getBody(), { status: 'ready' });
|
|
121
|
+
|
|
122
|
+
const clientEtc = await client.etc();
|
|
123
|
+
assert.deepStrictEqual(clientEtc.getBody(), { protocol: 'http' });
|
|
124
|
+
|
|
125
|
+
const clientLinks = await client.links();
|
|
126
|
+
assert.deepStrictEqual(clientLinks.getBody(), { links: [] });
|
|
127
|
+
|
|
128
|
+
const clientLinksPing = await client.linksPing();
|
|
129
|
+
assert.deepStrictEqual(clientLinksPing.getBody(), { ok: true });
|
|
130
|
+
|
|
131
|
+
const clientLinksConnect = await client.linksConnect('http://node-b:9200');
|
|
132
|
+
assert.deepStrictEqual(clientLinksConnect.getBody(), { connected: true });
|
|
133
|
+
|
|
134
|
+
const clientLinksDisconnect = await client.linksDisconnect('http://node-b:9200');
|
|
135
|
+
assert.deepStrictEqual(clientLinksDisconnect.getBody(), { disconnected: true });
|
|
136
|
+
|
|
137
|
+
const clientFlush = await client.flush();
|
|
138
|
+
assert.deepStrictEqual(clientFlush.getBody(), { flushed: true });
|
|
139
|
+
|
|
140
|
+
assert.strictEqual(typeof client.executeRequest, 'function');
|
|
141
|
+
assert.strictEqual(typeof client.sql, 'function');
|
|
142
|
+
assert.strictEqual(typeof client.execSql, 'function');
|
|
143
|
+
assert.strictEqual(typeof client.sqlSearch, 'function');
|
|
144
|
+
assert.strictEqual(typeof client.sam().search, 'function');
|
|
145
|
+
assert.strictEqual(typeof client.sam().searchAll, 'function');
|
|
146
|
+
assert.strictEqual(typeof client.sam().rebuild, 'function');
|
|
147
|
+
assert.strictEqual(typeof client.sam().status, 'function');
|
|
148
|
+
assert.strictEqual(typeof client.sam().debug, 'function');
|
|
149
|
+
assert.strictEqual(typeof client.sam().history, 'function');
|
|
150
|
+
assert.strictEqual(typeof client.sam().pause, 'function');
|
|
151
|
+
assert.strictEqual(typeof client.sam().clearPause, 'function');
|
|
152
|
+
assert.strictEqual(typeof client.sam().listDocuments, 'function');
|
|
153
|
+
assert.strictEqual(typeof client.sam().getDocument, 'function');
|
|
154
|
+
assert.strictEqual(typeof client.sam().openDocument, 'function');
|
|
76
155
|
} finally {
|
|
77
156
|
await new Promise((resolve) => server.close(resolve));
|
|
78
157
|
}
|