hlquery-node-client 1.0.0 → 1.0.1
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 +64 -241
- 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 +11 -0
- package/lib/SAM.js +71 -0
- package/lib/conformance.js +3 -0
- package/package.json +4 -12
package/README.md
CHANGED
|
@@ -4,30 +4,40 @@
|
|
|
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.
|
|
22
|
+
|
|
23
|
+
### Why use it?
|
|
24
|
+
|
|
25
|
+
- Familiar modular layout such as `client.collections()`, `client.documents()`, and `client.sam()`.
|
|
26
|
+
- Consistent auth, params, and parsed responses.
|
|
27
|
+
- Good default coverage for common hlquery workflows.
|
|
28
|
+
- Raw request access for custom routes.
|
|
29
|
+
|
|
30
|
+
### Why choose it over raw HTTP?
|
|
31
|
+
|
|
32
|
+
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.
|
|
33
|
+
|
|
34
|
+
### Install
|
|
21
35
|
|
|
22
36
|
```bash
|
|
23
37
|
npm install hlquery-node-client
|
|
24
38
|
```
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
const Client = require('hlquery-node-client');
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
For local development in this repository:
|
|
40
|
+
For local development inside this repository:
|
|
31
41
|
|
|
32
42
|
```javascript
|
|
33
43
|
const Client = require('./lib/Client');
|
|
@@ -38,9 +48,9 @@ const Client = require('./lib/Client');
|
|
|
38
48
|
```javascript
|
|
39
49
|
const Client = require('hlquery-node-client');
|
|
40
50
|
|
|
41
|
-
const client = new Client(process.env.HLQ_BASE_URL || 'http://localhost:9200', {
|
|
51
|
+
const client = new Client(process.env.HLQ_BASE_URL || process.env.HLQUERY_BASE_URL || 'http://localhost:9200', {
|
|
42
52
|
token: process.env.HLQ_TOKEN,
|
|
43
|
-
auth_method: 'bearer'
|
|
53
|
+
auth_method: 'bearer'
|
|
44
54
|
});
|
|
45
55
|
|
|
46
56
|
const health = await client.system().health();
|
|
@@ -48,269 +58,82 @@ console.log('status:', health.getStatusCode());
|
|
|
48
58
|
|
|
49
59
|
const collections = await client.collections().list(0, 10);
|
|
50
60
|
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
61
|
```
|
|
72
62
|
|
|
73
|
-
|
|
63
|
+
### Auth
|
|
74
64
|
|
|
75
65
|
```javascript
|
|
76
|
-
client
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
### API Surface
|
|
81
|
-
|
|
82
|
-
Use nested API objects: `client -> resource -> action`, for example `client.collections().create(...)`.
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
client.system().health();
|
|
86
|
-
client.system().stats();
|
|
87
|
-
client.system().info();
|
|
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
|
-
```
|
|
125
|
-
|
|
126
|
-
### Collections
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
const collections = client.collections();
|
|
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
|
-
]
|
|
66
|
+
const client = new Client('http://localhost:9200', {
|
|
67
|
+
token: 'your_token_here',
|
|
68
|
+
auth_method: 'bearer'
|
|
137
69
|
});
|
|
138
70
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await collections.update('books', schema);
|
|
142
|
-
await collections.delete('books');
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Documents
|
|
146
|
-
|
|
147
|
-
```javascript
|
|
148
|
-
const documents = client.documents();
|
|
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.'
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
await documents.update('books', 'book-1', { title: 'DDIA' });
|
|
157
|
-
await documents.delete('books', 'book-1');
|
|
158
|
-
|
|
159
|
-
await documents.import('books', [
|
|
160
|
-
{ id: 'book-2', title: 'Database Internals', content: 'Storage engines and indexes.' }
|
|
161
|
-
]);
|
|
162
|
-
|
|
163
|
-
await documents.addCSV('reports', './files/metrics.csv', {
|
|
164
|
-
id: 'metrics_q1',
|
|
165
|
-
document: { source_type: 'csv' }
|
|
166
|
-
});
|
|
71
|
+
client.setAuthToken('your_token_here', 'bearer');
|
|
72
|
+
client.setAuthToken('your_api_key_here', 'api-key');
|
|
167
73
|
```
|
|
168
74
|
|
|
169
|
-
|
|
75
|
+
### SAM
|
|
170
76
|
|
|
171
|
-
|
|
77
|
+
SAM is separate from vector search. It performs term and intent-style lookup, not vector similarity search.
|
|
172
78
|
|
|
173
79
|
```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
|
-
]);
|
|
80
|
+
const sam = client.sam();
|
|
190
81
|
|
|
191
|
-
await
|
|
192
|
-
|
|
193
|
-
|
|
82
|
+
const status = await sam.status('books');
|
|
83
|
+
const history = await sam.history('books', 5);
|
|
84
|
+
const results = await sam.search('books', 'distributed systems', {
|
|
194
85
|
limit: 10
|
|
195
86
|
});
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Common search parameters:
|
|
199
87
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
- `facet_by`: facet fields.
|
|
205
|
-
- `limit` / `offset`: pagination.
|
|
206
|
-
- `page` / `per_page`: alternate pagination.
|
|
88
|
+
console.log(status.getBody());
|
|
89
|
+
console.log(history.getBody());
|
|
90
|
+
console.log(results.getBody());
|
|
91
|
+
```
|
|
207
92
|
|
|
208
93
|
### SQL
|
|
209
94
|
|
|
210
|
-
SQL queries are supported through the search API and through the interactive talk shell.
|
|
211
|
-
|
|
212
95
|
```javascript
|
|
213
|
-
const
|
|
214
|
-
'products',
|
|
215
|
-
'SELECT id, title, price FROM products ORDER BY price DESC LIMIT 5;'
|
|
216
|
-
);
|
|
96
|
+
const sql = client.sql();
|
|
217
97
|
|
|
218
|
-
const rows =
|
|
98
|
+
const rows = await sql.query('SHOW COLLECTIONS;');
|
|
99
|
+
const books = await sql.search(
|
|
100
|
+
'books',
|
|
101
|
+
'SELECT id, title FROM books ORDER BY title ASC LIMIT 3;'
|
|
102
|
+
);
|
|
219
103
|
|
|
220
|
-
|
|
221
|
-
|
|
104
|
+
console.log(rows.getBody());
|
|
105
|
+
console.log(books.getBody());
|
|
222
106
|
```
|
|
223
107
|
|
|
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
|
-
```
|
|
108
|
+
### Reduce Text Example
|
|
240
109
|
|
|
241
|
-
|
|
110
|
+
Use the raw request helper for custom module routes:
|
|
242
111
|
|
|
243
112
|
```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']
|
|
113
|
+
const response = await client.executeRequest('GET', '/modules/<name>/<route>', null, {
|
|
114
|
+
q: 'example query'
|
|
254
115
|
});
|
|
255
116
|
|
|
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
|
-
});
|
|
117
|
+
console.log(response.getBody());
|
|
263
118
|
```
|
|
264
119
|
|
|
265
|
-
###
|
|
120
|
+
### Contributing
|
|
266
121
|
|
|
267
|
-
All
|
|
122
|
+
We welcome contributions from the community! All contributions must be released under the BSD 3-Clause license.
|
|
268
123
|
|
|
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
|
-
```
|
|
124
|
+
### How to Contribute
|
|
279
125
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
try {
|
|
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
|
-
```
|
|
126
|
+
- Check existing [issues](https://github.com/hlquery/hlquery/issues) or create new ones
|
|
127
|
+
- Contribute to client libraries (Node.js, Go, Java, Python, PHP, Ruby, Rust, Perl, C++)
|
|
128
|
+
- Test and report bugs
|
|
129
|
+
- Improve documentation
|
|
302
130
|
|
|
303
|
-
###
|
|
131
|
+
### Community
|
|
304
132
|
|
|
305
|
-
-
|
|
306
|
-
-
|
|
133
|
+
- 📖 [Documentation](https://docs.hlquery.com)
|
|
134
|
+
- 🐦 [X (Twitter)](https://x.com/hlquery)
|
|
135
|
+
- 📦 [GitHub](https://github.com/hlquery/hlquery)
|
|
307
136
|
|
|
308
|
-
###
|
|
137
|
+
### License
|
|
309
138
|
|
|
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.
|
|
139
|
+
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,15 @@ 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
|
+
|
|
465
476
|
/**
|
|
466
477
|
* Get aliases API instance
|
|
467
478
|
*
|
package/lib/SAM.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
async search(collectionName, query, params = {}) {
|
|
20
|
+
Validator.validateCollectionName(collectionName);
|
|
21
|
+
|
|
22
|
+
if (typeof query !== 'string' || query.trim() === '') {
|
|
23
|
+
throw new Error('SAM query must be a non-empty string');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
27
|
+
throw new Error('SAM search params must be an object');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return await this.request.execute('GET', '/sam/search', null, {
|
|
31
|
+
...params,
|
|
32
|
+
collection: collectionName,
|
|
33
|
+
q: query
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async status(collectionName = null, params = {}) {
|
|
38
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
39
|
+
throw new Error('SAM status params must be an object');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const queryParams = { ...params };
|
|
43
|
+
|
|
44
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
45
|
+
Validator.validateCollectionName(collectionName);
|
|
46
|
+
queryParams.collection = collectionName;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return await this.request.execute('GET', '/sam/status', null, queryParams);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async history(collectionName = null, limit = 100, params = {}) {
|
|
53
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
54
|
+
throw new Error('SAM history params must be an object');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const queryParams = {
|
|
58
|
+
...params,
|
|
59
|
+
limit: Number(limit)
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (collectionName !== null && collectionName !== undefined && collectionName !== '') {
|
|
63
|
+
Validator.validateCollectionName(collectionName);
|
|
64
|
+
queryParams.collection = collectionName;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return await this.request.execute('GET', '/sam/history', null, queryParams);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = SAM;
|
package/lib/conformance.js
CHANGED
|
@@ -44,6 +44,9 @@ 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: '/sam/search', methods: ['GET'], status: 'supported', client: 'sam.search' },
|
|
48
|
+
{ path: '/sam/status', methods: ['GET'], status: 'supported', client: 'sam.status' },
|
|
49
|
+
{ path: '/sam/history', methods: ['GET'], status: 'supported', client: 'sam.history' },
|
|
47
50
|
{ path: '/collections/{name}/documents/facet_counts', methods: ['GET', 'POST'], status: 'supported', client: 'documents.facetCounts' },
|
|
48
51
|
{ path: '/collections/{name}/documents/export', methods: ['GET', 'POST'], status: 'supported', client: 'documents.export' },
|
|
49
52
|
{ path: '/collections/{name}/synonyms', methods: ['GET'], status: 'supported', client: 'synonyms.list' },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hlquery-node-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
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
|
}
|