@infino-ai/infino 0.3.1 → 0.4.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/infino/index.d.ts +8 -3
- package/infino/index.js +72 -23
- package/package.json +7 -7
package/infino/index.d.ts
CHANGED
|
@@ -152,8 +152,9 @@ export interface QueryOptions {
|
|
|
152
152
|
/** A table handle. Obtain one from {@link Connection.createTable} or {@link Connection.openTable}. */
|
|
153
153
|
export declare class Table {
|
|
154
154
|
private inner;
|
|
155
|
+
private remote;
|
|
155
156
|
/** @hidden */
|
|
156
|
-
constructor(inner: any);
|
|
157
|
+
constructor(inner: any, remote?: boolean);
|
|
157
158
|
/** The table's Arrow schema. */
|
|
158
159
|
schema(): arrow.Schema;
|
|
159
160
|
/**
|
|
@@ -224,8 +225,9 @@ export declare class Table {
|
|
|
224
225
|
/** A catalog connection. Create one with {@link connect}. */
|
|
225
226
|
export declare class Connection {
|
|
226
227
|
private inner;
|
|
228
|
+
private remote;
|
|
227
229
|
/** @hidden */
|
|
228
|
-
constructor(inner: any);
|
|
230
|
+
constructor(inner: any, remote?: boolean);
|
|
229
231
|
/**
|
|
230
232
|
* Provision the database this connection targets. On the hosted service this
|
|
231
233
|
* registers the database (throws if it already exists); on a local backend the
|
|
@@ -254,7 +256,10 @@ export declare class Connection {
|
|
|
254
256
|
* For a hosted (`https://`) target, authenticate with an API key: pass
|
|
255
257
|
* {@link ConnectOptions.apiKey}, or set the `INFINO_API_KEY` environment
|
|
256
258
|
* variable. Storage and cache tuning the URI can't carry also goes in
|
|
257
|
-
* `options` (see {@link ConnectOptions}).
|
|
259
|
+
* `options` (see {@link ConnectOptions}). An operation failure the hosted
|
|
260
|
+
* API reported carries the HTTP status it returned as `status` on the
|
|
261
|
+
* thrown Error (`409` create conflict, `404` missing, `503` transient —
|
|
262
|
+
* retry with backoff); errors on local connections have no `status`.
|
|
258
263
|
*
|
|
259
264
|
* ```ts
|
|
260
265
|
* // local
|
package/infino/index.js
CHANGED
|
@@ -121,7 +121,10 @@ function schemaToIpc(schema) {
|
|
|
121
121
|
// built by hand. The schema here is ours (from the addon), so its types
|
|
122
122
|
// are same-instance.
|
|
123
123
|
function buildColumn(field, rows) {
|
|
124
|
-
|
|
124
|
+
// An omitted key reads as `undefined`, which `vectorFromArray` would
|
|
125
|
+
// coerce to the type's zero value (0, "", NaN, false) rather than null —
|
|
126
|
+
// its null set is `[null]` only. Normalize so omitted == explicit null.
|
|
127
|
+
const values = rows.map((r) => r[field.name] ?? null);
|
|
125
128
|
const t = field.type;
|
|
126
129
|
if (t && typeof t.listSize === "number") {
|
|
127
130
|
const flat = Float32Array.from(values.flat());
|
|
@@ -189,17 +192,54 @@ function decode(buf, asArrow) {
|
|
|
189
192
|
return obj;
|
|
190
193
|
});
|
|
191
194
|
}
|
|
195
|
+
// --- hosted-API error status ---
|
|
196
|
+
// The hosted transport types a few statuses before the number itself is
|
|
197
|
+
// lost (the message keeps a stable prefix); every other HTTP failure it
|
|
198
|
+
// reports as "<op>: server returned NNN: <body>". Both let the status be
|
|
199
|
+
// recovered here. This table goes away once the transport carries the
|
|
200
|
+
// status structurally.
|
|
201
|
+
const PREFIX_STATUS = [
|
|
202
|
+
["NotFound: ", 404],
|
|
203
|
+
["AlreadyExists: ", 409],
|
|
204
|
+
["ConflictError: ", 412],
|
|
205
|
+
];
|
|
206
|
+
const SERVER_STATUS = /\bserver returned (\d{3}): /;
|
|
207
|
+
/**
|
|
208
|
+
* Run a native call. On a hosted (Infino Cloud) connection, a failure is
|
|
209
|
+
* rethrown as-is but tagged with `status` — the HTTP status the API
|
|
210
|
+
* actually returned — so callers can branch (e.g. `409` = already exists,
|
|
211
|
+
* `503` = transient, retry) without parsing message text. Local
|
|
212
|
+
* connections rethrow untouched.
|
|
213
|
+
*/
|
|
214
|
+
function guard(remote, fn) {
|
|
215
|
+
if (!remote)
|
|
216
|
+
return fn();
|
|
217
|
+
try {
|
|
218
|
+
return fn();
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
if (e instanceof Error && e.status === undefined) {
|
|
222
|
+
const prefixed = PREFIX_STATUS.find(([prefix]) => e.message.startsWith(prefix));
|
|
223
|
+
const status = prefixed ? prefixed[1] : Number(SERVER_STATUS.exec(e.message)?.[1]);
|
|
224
|
+
if (Number.isFinite(status))
|
|
225
|
+
e.status = status;
|
|
226
|
+
}
|
|
227
|
+
throw e;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
192
230
|
// --- friendly handles ---
|
|
193
231
|
/** A table handle. Obtain one from {@link Connection.createTable} or {@link Connection.openTable}. */
|
|
194
232
|
class Table {
|
|
195
233
|
inner;
|
|
234
|
+
remote;
|
|
196
235
|
/** @hidden */
|
|
197
|
-
constructor(inner) {
|
|
236
|
+
constructor(inner, remote = false) {
|
|
198
237
|
this.inner = inner;
|
|
238
|
+
this.remote = remote;
|
|
199
239
|
}
|
|
200
240
|
/** The table's Arrow schema. */
|
|
201
241
|
schema() {
|
|
202
|
-
return arrow.tableFromIPC(this.inner.schema()).schema;
|
|
242
|
+
return arrow.tableFromIPC(guard(this.remote, () => this.inner.schema())).schema;
|
|
203
243
|
}
|
|
204
244
|
/**
|
|
205
245
|
* Append rows. Accepts an array of objects, an apache-arrow
|
|
@@ -207,45 +247,47 @@ class Table {
|
|
|
207
247
|
* append == one commit.
|
|
208
248
|
*/
|
|
209
249
|
append(data) {
|
|
210
|
-
|
|
250
|
+
const ipc = dataToIpc(data, () => this.schema());
|
|
251
|
+
guard(this.remote, () => this.inner.append(ipc));
|
|
211
252
|
}
|
|
212
253
|
bm25Search(column, query, k, opts = {}) {
|
|
213
|
-
const buf = this.inner.bm25Search(column, query, k, opts.mode, opts.stats, opts.projection);
|
|
254
|
+
const buf = guard(this.remote, () => this.inner.bm25Search(column, query, k, opts.mode, opts.stats, opts.projection));
|
|
214
255
|
return decode(buf, opts.arrow);
|
|
215
256
|
}
|
|
216
257
|
vectorSearch(column, query, k, opts = {}) {
|
|
217
258
|
const q = query instanceof Float32Array ? query : Float32Array.from(query);
|
|
218
|
-
const buf = this.inner.vectorSearch(column, q, k, opts.nprobe, opts.rerankMult, opts.projection, opts.filter);
|
|
259
|
+
const buf = guard(this.remote, () => this.inner.vectorSearch(column, q, k, opts.nprobe, opts.rerankMult, opts.projection, opts.filter));
|
|
219
260
|
return decode(buf, opts.arrow);
|
|
220
261
|
}
|
|
221
262
|
hybridSearch(textColumn, textQuery, vectorColumn, vectorQuery, k, opts = {}) {
|
|
222
263
|
const q = vectorQuery instanceof Float32Array ? vectorQuery : Float32Array.from(vectorQuery);
|
|
223
|
-
const buf = this.inner.hybridSearch(textColumn, textQuery, vectorColumn, q, k, opts.mode, opts.nprobe, opts.projection);
|
|
264
|
+
const buf = guard(this.remote, () => this.inner.hybridSearch(textColumn, textQuery, vectorColumn, q, k, opts.mode, opts.nprobe, opts.projection));
|
|
224
265
|
return decode(buf, opts.arrow);
|
|
225
266
|
}
|
|
226
267
|
tokenMatch(column, query, opts = {}) {
|
|
227
|
-
const buf = this.inner.tokenMatch(column, query, opts.mode, opts.projection);
|
|
268
|
+
const buf = guard(this.remote, () => this.inner.tokenMatch(column, query, opts.mode, opts.projection));
|
|
228
269
|
return decode(buf, opts.arrow);
|
|
229
270
|
}
|
|
230
271
|
exactMatch(column, value, opts = {}) {
|
|
231
|
-
const buf = this.inner.exactMatch(column, value, opts.projection);
|
|
272
|
+
const buf = guard(this.remote, () => this.inner.exactMatch(column, value, opts.projection));
|
|
232
273
|
return decode(buf, opts.arrow);
|
|
233
274
|
}
|
|
234
275
|
/** Count rows matching a BM25 keyword `query` over `column`, without
|
|
235
276
|
* fetching them. `mode` is `"or"` (default) or `"and"`. */
|
|
236
277
|
count(column, query, opts = {}) {
|
|
237
|
-
return this.inner.count(column, query, opts.mode);
|
|
278
|
+
return guard(this.remote, () => this.inner.count(column, query, opts.mode));
|
|
238
279
|
}
|
|
239
280
|
/** Replace rows matching a SQL predicate (e.g. `"status = 'spam'"`) with
|
|
240
281
|
* `data` (same shapes as `append`), 1:1 — the matched count must equal the
|
|
241
282
|
* replacement-row count. Requires durable storage (not `memory://`). */
|
|
242
283
|
update(predicate, data) {
|
|
243
|
-
|
|
284
|
+
const ipc = dataToIpc(data, () => this.schema());
|
|
285
|
+
return guard(this.remote, () => this.inner.update(predicate, ipc));
|
|
244
286
|
}
|
|
245
287
|
/** Delete rows matching a SQL predicate (e.g. `"status = 'spam'"`).
|
|
246
288
|
* Requires durable storage (not `memory://`). */
|
|
247
289
|
delete(predicate) {
|
|
248
|
-
return this.inner.delete(predicate);
|
|
290
|
+
return guard(this.remote, () => this.inner.delete(predicate));
|
|
249
291
|
}
|
|
250
292
|
/**
|
|
251
293
|
* Merge small / underfilled superfiles into larger ones (omit `settings`
|
|
@@ -255,7 +297,7 @@ class Table {
|
|
|
255
297
|
* so calling this on a hosted (`https://…`) connection throws.
|
|
256
298
|
*/
|
|
257
299
|
optimize(settings) {
|
|
258
|
-
this.inner.optimize(settings);
|
|
300
|
+
guard(this.remote, () => this.inner.optimize(settings));
|
|
259
301
|
}
|
|
260
302
|
/**
|
|
261
303
|
* Delete orphaned storage objects left by compaction or interrupted writes.
|
|
@@ -266,16 +308,18 @@ class Table {
|
|
|
266
308
|
* calling this on a hosted connection throws.
|
|
267
309
|
*/
|
|
268
310
|
gc(graceSecs) {
|
|
269
|
-
return this.inner.gc(graceSecs);
|
|
311
|
+
return guard(this.remote, () => this.inner.gc(graceSecs));
|
|
270
312
|
}
|
|
271
313
|
}
|
|
272
314
|
exports.Table = Table;
|
|
273
315
|
/** A catalog connection. Create one with {@link connect}. */
|
|
274
316
|
class Connection {
|
|
275
317
|
inner;
|
|
318
|
+
remote;
|
|
276
319
|
/** @hidden */
|
|
277
|
-
constructor(inner) {
|
|
320
|
+
constructor(inner, remote = false) {
|
|
278
321
|
this.inner = inner;
|
|
322
|
+
this.remote = remote;
|
|
279
323
|
}
|
|
280
324
|
/**
|
|
281
325
|
* Provision the database this connection targets. On the hosted service this
|
|
@@ -283,23 +327,24 @@ class Connection {
|
|
|
283
327
|
* catalog root is the database, so it is a no-op success.
|
|
284
328
|
*/
|
|
285
329
|
createDatabase() {
|
|
286
|
-
this.inner.createDatabase();
|
|
330
|
+
guard(this.remote, () => this.inner.createDatabase());
|
|
287
331
|
}
|
|
288
332
|
/** Create a table from an apache-arrow `Schema` or `{ column: type }`. */
|
|
289
333
|
createTable(name, schema, indexes) {
|
|
290
|
-
|
|
334
|
+
const ipc = schemaToIpc(schema);
|
|
335
|
+
return new Table(guard(this.remote, () => this.inner.createTable(name, ipc, indexes)), this.remote);
|
|
291
336
|
}
|
|
292
337
|
openTable(name) {
|
|
293
|
-
return new Table(this.inner.openTable(name));
|
|
338
|
+
return new Table(guard(this.remote, () => this.inner.openTable(name)), this.remote);
|
|
294
339
|
}
|
|
295
340
|
dropTable(name, purge) {
|
|
296
|
-
this.inner.dropTable(name, purge);
|
|
341
|
+
guard(this.remote, () => this.inner.dropTable(name, purge));
|
|
297
342
|
}
|
|
298
343
|
listTables() {
|
|
299
|
-
return this.inner.listTables();
|
|
344
|
+
return guard(this.remote, () => this.inner.listTables());
|
|
300
345
|
}
|
|
301
346
|
querySql(sql, opts = {}) {
|
|
302
|
-
return decode(this.inner.querySql(sql), opts.arrow);
|
|
347
|
+
return decode(guard(this.remote, () => this.inner.querySql(sql)), opts.arrow);
|
|
303
348
|
}
|
|
304
349
|
}
|
|
305
350
|
exports.Connection = Connection;
|
|
@@ -314,7 +359,10 @@ exports.Connection = Connection;
|
|
|
314
359
|
* For a hosted (`https://`) target, authenticate with an API key: pass
|
|
315
360
|
* {@link ConnectOptions.apiKey}, or set the `INFINO_API_KEY` environment
|
|
316
361
|
* variable. Storage and cache tuning the URI can't carry also goes in
|
|
317
|
-
* `options` (see {@link ConnectOptions}).
|
|
362
|
+
* `options` (see {@link ConnectOptions}). An operation failure the hosted
|
|
363
|
+
* API reported carries the HTTP status it returned as `status` on the
|
|
364
|
+
* thrown Error (`409` create conflict, `404` missing, `503` transient —
|
|
365
|
+
* retry with backoff); errors on local connections have no `status`.
|
|
318
366
|
*
|
|
319
367
|
* ```ts
|
|
320
368
|
* // local
|
|
@@ -324,5 +372,6 @@ exports.Connection = Connection;
|
|
|
324
372
|
* ```
|
|
325
373
|
*/
|
|
326
374
|
function connect(uri, options) {
|
|
327
|
-
|
|
375
|
+
const remote = /^https?:\/\//.test(uri);
|
|
376
|
+
return new Connection(guard(remote, () => (0, native_js_1.connect)(uri, options)), remote);
|
|
328
377
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@infino-ai/infino",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Fast search on object storage — SQL, full-text, and vector search.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -82,12 +82,12 @@
|
|
|
82
82
|
"apache-arrow": "^17"
|
|
83
83
|
},
|
|
84
84
|
"optionalDependencies": {
|
|
85
|
-
"infx-darwin-x64": "0.
|
|
86
|
-
"infx-darwin-arm64": "0.
|
|
87
|
-
"infx-linux-x64-gnu": "0.
|
|
88
|
-
"infx-linux-arm64-gnu": "0.
|
|
89
|
-
"infx-linux-x64-musl": "0.
|
|
90
|
-
"infx-linux-arm64-musl": "0.
|
|
85
|
+
"infx-darwin-x64": "0.4.1",
|
|
86
|
+
"infx-darwin-arm64": "0.4.1",
|
|
87
|
+
"infx-linux-x64-gnu": "0.4.1",
|
|
88
|
+
"infx-linux-arm64-gnu": "0.4.1",
|
|
89
|
+
"infx-linux-x64-musl": "0.4.1",
|
|
90
|
+
"infx-linux-arm64-musl": "0.4.1"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@napi-rs/cli": "^2.18.0",
|