@an5/adapters 0.2.5 → 0.2.9
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 +283 -305
- package/dist/an5Adapter.d.ts +142 -7
- package/dist/an5Adapter.js +998 -68
- package/dist/base/metadata.d.ts +10 -0
- package/dist/base/metadata.js +107 -0
- package/dist/base/sql.d.ts +19 -1
- package/dist/base/sql.js +152 -24
- package/dist/base/types.d.ts +10 -1
- package/dist/browser.d.ts +4 -1
- package/dist/browser.js +9 -2
- package/dist/googlesheets/adapter.d.ts +1 -0
- package/dist/googlesheets/adapter.js +9 -2
- package/dist/googlesheets/config.d.ts +4 -4
- package/dist/googlesheets/helpers.js +2 -0
- package/dist/googlesheets/parseConnectionString.js +5 -2
- package/dist/googlesheets/sqlExecutor.js +29 -24
- package/dist/googlesheets/tableClient.js +14 -5
- package/dist/index.d.ts +5 -1
- package/dist/index.js +15 -1
- package/dist/mssql/engine.js +8 -4
- package/dist/mysql/engine.js +1 -1
- package/dist/nbase/client.d.ts +92 -0
- package/dist/nbase/client.js +147 -0
- package/dist/nbase/index.d.ts +47 -0
- package/dist/nbase/index.js +80 -0
- package/dist/postgres/engine.js +1 -1
- package/dist/sqlite/browserEngine.d.ts +27 -0
- package/dist/sqlite/browserEngine.js +161 -0
- package/dist/sqlite/engine.js +15 -3
- package/dist/sqlite/index.d.ts +1 -0
- package/dist/sqlite/index.js +1 -0
- package/dist/typed.d.ts +5 -0
- package/dist/typed.js +2 -0
- package/dotnet/An5Adapter.cs +1112 -275
- package/dotnet/Base/Core.cs +380 -82
- package/dotnet/Mssql/MssqlEngine.cs +145 -144
- package/dotnet/Postgres/PostgresEngine.cs +149 -121
- package/dotnet/Sqlite/SqliteEngine.cs +214 -0
- package/golang/an5_adapter.go +314 -0
- package/golang/base/base.go +100 -0
- package/golang/base/metadata.go +116 -0
- package/golang/base/where.go +311 -0
- package/golang/go.mod +3 -0
- package/golang/mssql/mssql.go +32 -0
- package/golang/postgres/postgres.go +37 -0
- package/golang/sqlite/sqlite.go +14 -0
- package/golang/sqlite_test.go +42 -0
- package/golang/table_client.go +1329 -0
- package/package.json +26 -9
- package/python/an5_adapter.py +184 -97
- package/python/base/__init__.py +3 -3
- package/python/base/dialects.py +11 -8
- package/python/base/metadata.py +59 -10
- package/python/base/sql.py +202 -121
- package/python/mssql/__init__.py +1 -1
- package/python/mssql/provider.py +62 -62
- package/python/postgres/__init__.py +1 -1
- package/python/postgres/provider.py +15 -15
- package/python/sqlite/__init__.py +3 -0
- package/python/sqlite/provider.py +83 -0
- package/python/table_client.py +636 -216
- package/rust/Cargo.toml +31 -0
- package/rust/README.md +71 -0
- package/rust/src/adapter.rs +1312 -0
- package/rust/src/base/dialect.rs +172 -0
- package/rust/src/base/metadata.rs +134 -0
- package/rust/src/base/mod.rs +17 -0
- package/rust/src/base/where_builder.rs +405 -0
- package/rust/src/lib.rs +75 -0
- package/typescript/src/an5Adapter.ts +1515 -505
- package/typescript/src/base/index.ts +3 -3
- package/typescript/src/base/metadata.ts +148 -28
- package/typescript/src/base/sql.ts +264 -98
- package/typescript/src/base/types.ts +33 -24
- package/typescript/src/browser.ts +10 -6
- package/typescript/src/config.ts +95 -95
- package/typescript/src/googlesheets/adapter.ts +269 -259
- package/typescript/src/googlesheets/an5SheetsAdapter.ts +3 -3
- package/typescript/src/googlesheets/config.ts +47 -47
- package/typescript/src/googlesheets/helpers.ts +144 -143
- package/typescript/src/googlesheets/index.ts +3 -3
- package/typescript/src/googlesheets/parseConnectionString.ts +48 -46
- package/typescript/src/googlesheets/retry.ts +126 -126
- package/typescript/src/googlesheets/sqlExecutor.ts +304 -301
- package/typescript/src/googlesheets/tableClient.ts +461 -455
- package/typescript/src/googlesheets/types.ts +6 -6
- package/typescript/src/index.ts +48 -27
- package/typescript/src/mssql/engine.ts +134 -132
- package/typescript/src/mssql/index.ts +1 -1
- package/typescript/src/mysql/engine.ts +80 -80
- package/typescript/src/mysql/index.ts +1 -1
- package/typescript/src/nbase/client.ts +214 -0
- package/typescript/src/nbase/index.ts +104 -0
- package/typescript/src/postgres/engine.ts +87 -87
- package/typescript/src/postgres/index.ts +1 -1
- package/typescript/src/sqlite/browserEngine.ts +192 -0
- package/typescript/src/sqlite/engine.ts +66 -55
- package/typescript/src/sqlite/index.ts +3 -1
- package/typescript/src/typed.ts +52 -0
|
@@ -46,9 +46,9 @@ function matchRowSQL(row, whereText, values) {
|
|
|
46
46
|
const m = part.match(/^(.+?)\s*(=|!=|<>|>|<|>=|<=|LIKE|CONTAINS)\s*(.+)$/i);
|
|
47
47
|
if (!m)
|
|
48
48
|
continue;
|
|
49
|
-
const field = m[1].trim().replace(/[[\]]/g, '');
|
|
50
|
-
const op = m[2].toUpperCase();
|
|
51
|
-
const valRef = m[3].trim();
|
|
49
|
+
const field = (m[1] ?? '').trim().replace(/[[\]]/g, '');
|
|
50
|
+
const op = (m[2] ?? '').toUpperCase();
|
|
51
|
+
const valRef = (m[3] ?? '').trim();
|
|
52
52
|
const val = valRef.startsWith('?') ? values[parseInt(valRef.slice(1))] : valRef.replace(/^['"]|['"]$/g, '');
|
|
53
53
|
const cell = row[field];
|
|
54
54
|
switch (op) {
|
|
@@ -94,20 +94,26 @@ function extractColsAndVals(sql, params) {
|
|
|
94
94
|
const vals = [];
|
|
95
95
|
const colMatch = sql.match(/\(([^)]+)\)\s*VALUES/i);
|
|
96
96
|
if (colMatch) {
|
|
97
|
-
const rawCols = colMatch[1].split(',').map(c => c.trim().replace(/[[\]]/g, ''));
|
|
97
|
+
const rawCols = (colMatch[1] ?? '').split(',').map(c => c.trim().replace(/[[\]]/g, ''));
|
|
98
98
|
// Find actual values
|
|
99
|
-
const valMatch = sql.substring(colMatch.index + colMatch[0].length).match(/\(([^)]+)\)/);
|
|
99
|
+
const valMatch = sql.substring((colMatch.index ?? 0) + colMatch[0].length).match(/\(([^)]+)\)/);
|
|
100
100
|
if (valMatch) {
|
|
101
|
-
const rawVals = valMatch[1].split(',').map(v => v.trim());
|
|
101
|
+
const rawVals = (valMatch[1] ?? '').split(',').map(v => v.trim());
|
|
102
102
|
for (let i = 0; i < rawCols.length; i++) {
|
|
103
|
-
|
|
103
|
+
const col = rawCols[i];
|
|
104
|
+
if (col === undefined)
|
|
105
|
+
continue;
|
|
106
|
+
cols.push(col);
|
|
104
107
|
const rv = rawVals[i];
|
|
105
|
-
if (rv.startsWith('@') && params && params[rv.slice(1)] !== undefined) {
|
|
108
|
+
if (rv !== undefined && rv.startsWith('@') && params && params[rv.slice(1)] !== undefined) {
|
|
106
109
|
vals.push(params[rv.slice(1)]);
|
|
107
110
|
}
|
|
108
|
-
else {
|
|
111
|
+
else if (rv !== undefined) {
|
|
109
112
|
vals.push(rv.replace(/^['"]|['"]$/g, ''));
|
|
110
113
|
}
|
|
114
|
+
else {
|
|
115
|
+
vals.push(null);
|
|
116
|
+
}
|
|
111
117
|
}
|
|
112
118
|
}
|
|
113
119
|
}
|
|
@@ -125,13 +131,13 @@ async function execSelect(adapter, query, params) {
|
|
|
125
131
|
return obj;
|
|
126
132
|
});
|
|
127
133
|
}
|
|
128
|
-
const sheetName = m[2]
|
|
134
|
+
const sheetName = m[2] ?? m[3] ?? m[4] ?? '';
|
|
129
135
|
const whereClause = m[5];
|
|
130
136
|
const raw = await adapter.readRange((0, helpers_1.esc)(sheetName) + '!A:ZZ');
|
|
131
137
|
if (raw.length < 1)
|
|
132
138
|
return [];
|
|
133
139
|
const headers = raw[0];
|
|
134
|
-
const fieldList = m[1].trim();
|
|
140
|
+
const fieldList = (m[1] ?? '*').trim();
|
|
135
141
|
const selectAll = fieldList === '*';
|
|
136
142
|
const rows = raw.slice(1).map(row => {
|
|
137
143
|
const obj = {};
|
|
@@ -139,16 +145,15 @@ async function execSelect(adapter, query, params) {
|
|
|
139
145
|
return obj;
|
|
140
146
|
});
|
|
141
147
|
if (!whereClause)
|
|
142
|
-
return selectAll ? rows : rows.map(r => pickFields(r, fieldList
|
|
143
|
-
const { text, values } = substParams(query, params);
|
|
148
|
+
return selectAll ? rows : rows.map(r => pickFields(r, fieldList));
|
|
144
149
|
// Extract just the WHERE part
|
|
145
150
|
const whereParts = query.match(/WHERE\s+(.+)$/i);
|
|
146
|
-
const whereText = whereParts
|
|
151
|
+
const whereText = whereParts?.[1] ?? '';
|
|
147
152
|
const { text: whereSubst, values: whereVals } = substParams(whereText, params);
|
|
148
153
|
const result = rows.filter(r => matchRowSQL(r, whereSubst, whereVals));
|
|
149
|
-
return selectAll ? result : result.map(r => pickFields(r, fieldList
|
|
154
|
+
return selectAll ? result : result.map(r => pickFields(r, fieldList));
|
|
150
155
|
}
|
|
151
|
-
function pickFields(row, fieldList
|
|
156
|
+
function pickFields(row, fieldList) {
|
|
152
157
|
const fields = fieldList.split(',').map(f => f.trim().replace(/[[\]]/g, ''));
|
|
153
158
|
const obj = {};
|
|
154
159
|
fields.forEach(f => { obj[f] = row[f]; });
|
|
@@ -158,7 +163,7 @@ async function execInsert(adapter, query, params) {
|
|
|
158
163
|
const m = query.match(/INSERT\s+INTO\s+(?:'([^']+)'|"([^"]+)"|(\S+))\s*(.*)/i);
|
|
159
164
|
if (!m)
|
|
160
165
|
throw new Error('Invalid INSERT syntax');
|
|
161
|
-
const sheetName = m[1]
|
|
166
|
+
const sheetName = m[1] ?? m[2] ?? m[3] ?? '';
|
|
162
167
|
const { cols, vals } = extractColsAndVals(query, params);
|
|
163
168
|
if (cols.length === 0)
|
|
164
169
|
throw new Error('Cannot extract columns from INSERT');
|
|
@@ -198,8 +203,8 @@ async function execUpdate(adapter, query, params) {
|
|
|
198
203
|
const m = query.match(/UPDATE\s+(?:'([^']+)'|"([^"]+)"|(\S+))\s+SET\s+(.+?)(?:\s+WHERE\s+(.+))?$/i);
|
|
199
204
|
if (!m)
|
|
200
205
|
throw new Error('Invalid UPDATE syntax');
|
|
201
|
-
const sheetName = m[1]
|
|
202
|
-
const setClause = m[4];
|
|
206
|
+
const sheetName = m[1] ?? m[2] ?? m[3] ?? '';
|
|
207
|
+
const setClause = m[4] ?? '';
|
|
203
208
|
const whereClause = m[5];
|
|
204
209
|
// Parse SET clause
|
|
205
210
|
const setPairs = setClause.split(',').map(p => p.trim());
|
|
@@ -209,8 +214,8 @@ async function execUpdate(adapter, query, params) {
|
|
|
209
214
|
const sm = pair.match(/^(\w+)\s*=\s*(.+)$/i);
|
|
210
215
|
if (!sm)
|
|
211
216
|
continue;
|
|
212
|
-
setFields.push(sm[1].replace(/[[\]]/g, ''));
|
|
213
|
-
const rv = sm[2].trim();
|
|
217
|
+
setFields.push((sm[1] ?? '').replace(/[[\]]/g, ''));
|
|
218
|
+
const rv = (sm[2] ?? '').trim();
|
|
214
219
|
if (rv.startsWith('@') && params && params[rv.slice(1)] !== undefined) {
|
|
215
220
|
setVals.push(params[rv.slice(1)]);
|
|
216
221
|
}
|
|
@@ -230,7 +235,7 @@ async function execUpdate(adapter, query, params) {
|
|
|
230
235
|
let count = 0;
|
|
231
236
|
for (let i = 0; i < rows.length; i++) {
|
|
232
237
|
const row = {};
|
|
233
|
-
headers.forEach((h, j) => { row[h] = rows[i][j] ?? null; });
|
|
238
|
+
headers.forEach((h, j) => { row[h] = rows[i]?.[j] ?? null; });
|
|
234
239
|
row.__row = i + 2;
|
|
235
240
|
if (whereClause && !matchRowSQL(row, whereSubst, whereVals))
|
|
236
241
|
continue;
|
|
@@ -253,7 +258,7 @@ async function execDelete(adapter, query, params) {
|
|
|
253
258
|
const m = query.match(/DELETE\s+FROM\s+(?:'([^']+)'|"([^"]+)"|(\S+))\s*(?:WHERE\s+(.+))?$/i);
|
|
254
259
|
if (!m)
|
|
255
260
|
throw new Error('Invalid DELETE syntax');
|
|
256
|
-
const sheetName = m[1]
|
|
261
|
+
const sheetName = m[1] ?? m[2] ?? m[3] ?? '';
|
|
257
262
|
const whereClause = m[4];
|
|
258
263
|
const meta = await adapter.getSheetMeta(sheetName);
|
|
259
264
|
if (!meta)
|
|
@@ -282,7 +287,7 @@ async function execDelete(adapter, query, params) {
|
|
|
282
287
|
const toDelete = [];
|
|
283
288
|
for (let i = 1; i < raw.length; i++) {
|
|
284
289
|
const row = {};
|
|
285
|
-
headers.forEach((h, j) => { row[h] = raw[i][j] ?? null; });
|
|
290
|
+
headers.forEach((h, j) => { row[h] = raw[i]?.[j] ?? null; });
|
|
286
291
|
if (matchRowSQL(row, whereSubst, whereVals)) {
|
|
287
292
|
toDelete.push(i + 1);
|
|
288
293
|
}
|
|
@@ -54,7 +54,10 @@ class SheetsTableClient {
|
|
|
54
54
|
for (let i = 1; i < values.length; i++) {
|
|
55
55
|
const row = { __row: i + 1 };
|
|
56
56
|
for (let j = 0; j < headers.length; j++) {
|
|
57
|
-
|
|
57
|
+
const h = headers[j];
|
|
58
|
+
if (h === undefined)
|
|
59
|
+
continue;
|
|
60
|
+
row[h] = (0, helpers_1.coerceCell)(values[i]?.[j], this.fields[h]);
|
|
58
61
|
}
|
|
59
62
|
rows.push(row);
|
|
60
63
|
}
|
|
@@ -222,6 +225,8 @@ class SheetsTableClient {
|
|
|
222
225
|
if (matching.length === 0)
|
|
223
226
|
throw new Error('No record found matching where clause');
|
|
224
227
|
const target = matching[0];
|
|
228
|
+
if (target === undefined)
|
|
229
|
+
throw new Error('No record found matching where clause');
|
|
225
230
|
const updated = { ...target, ...args.data, __row: target.__row };
|
|
226
231
|
await this.adapter.writeRange(`${this.escSheetName}!A${target.__row}`, [
|
|
227
232
|
this.rowToValues(updated, headers),
|
|
@@ -256,6 +261,8 @@ class SheetsTableClient {
|
|
|
256
261
|
if (matching.length === 0)
|
|
257
262
|
throw new Error('No record found matching where clause');
|
|
258
263
|
const target = matching[0];
|
|
264
|
+
if (target === undefined)
|
|
265
|
+
throw new Error('No record found matching where clause');
|
|
259
266
|
const meta = await this.adapter.getSheetMeta(this.sheetName);
|
|
260
267
|
if (!meta)
|
|
261
268
|
throw new Error(`Sheet "${this.sheetName}" not found`);
|
|
@@ -395,14 +402,16 @@ class SheetsTableClient {
|
|
|
395
402
|
continue;
|
|
396
403
|
let dot = 0, m1 = 0, m2 = 0;
|
|
397
404
|
for (let i = 0; i < args.vector.length; i++) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
405
|
+
const av = args.vector[i] ?? 0;
|
|
406
|
+
const bv = vec[i] ?? 0;
|
|
407
|
+
dot += av * bv;
|
|
408
|
+
m1 += av ** 2;
|
|
409
|
+
m2 += bv ** 2;
|
|
401
410
|
}
|
|
402
411
|
const cosine = m1 && m2 ? dot / (Math.sqrt(m1) * Math.sqrt(m2)) : 0;
|
|
403
412
|
const dist = metric === 'cosine' ? 1 - cosine
|
|
404
413
|
: metric === 'dot' ? -dot
|
|
405
|
-
: Math.sqrt(args.vector.reduce((s, v, i) => s + (v - vec[i]) ** 2, 0));
|
|
414
|
+
: Math.sqrt(args.vector.reduce((s, v, i) => s + (v - (vec[i] ?? 0)) ** 2, 0));
|
|
406
415
|
scored.push({ row, dist });
|
|
407
416
|
}
|
|
408
417
|
scored.sort((a, b) => a.dist - b.dist);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export { An5Adapter, AdapterTableClient, createAn5Adapter, setAdapterMetadata, } from './an5Adapter';
|
|
1
|
+
export { An5Adapter, AdapterTableClient, createAn5Adapter, createAdapterProxy, executorFromAdapter, setAdapterMetadata, } from './an5Adapter';
|
|
2
|
+
export { parseWhere, buildOrderBy, quote } from './base/sql';
|
|
3
|
+
export { NBaseVectorClient, NBaseError, createNBaseVectorClient, createNBaseClient, parseNBaseConnectionString, buildVectorId, parseVectorId, } from './nbase';
|
|
4
|
+
export type { NBaseAdapterConfig, NBaseClientConfig, NBaseVector, NBaseSearchOptions, NBaseSearchResult, NBaseStats, } from './nbase';
|
|
2
5
|
export type { An5AdapterConfig, AdapterMetadata, Dialect, } from './an5Adapter';
|
|
6
|
+
export type { TypedAn5Adapter, AdapterAPI } from './typed';
|
|
3
7
|
export { getLlmConfig, setLlmConfig, getEmbeddingConfig, setEmbeddingConfig, resetAdapter, } from './config';
|
|
4
8
|
export type { LlmConfigData, EmbeddingConfigData, } from './config';
|
|
5
9
|
export { An5SheetsAdapter, SheetsTableClient, createAn5SheetsAdapter, parseSheetsConnectionString, } from './googlesheets';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseSheetsConnectionString = exports.createAn5SheetsAdapter = exports.SheetsTableClient = exports.An5SheetsAdapter = exports.resetAdapter = exports.setEmbeddingConfig = exports.getEmbeddingConfig = exports.setLlmConfig = exports.getLlmConfig = exports.setAdapterMetadata = exports.createAn5Adapter = exports.AdapterTableClient = exports.An5Adapter = void 0;
|
|
3
|
+
exports.parseSheetsConnectionString = exports.createAn5SheetsAdapter = exports.SheetsTableClient = exports.An5SheetsAdapter = exports.resetAdapter = exports.setEmbeddingConfig = exports.getEmbeddingConfig = exports.setLlmConfig = exports.getLlmConfig = exports.parseVectorId = exports.buildVectorId = exports.parseNBaseConnectionString = exports.createNBaseClient = exports.createNBaseVectorClient = exports.NBaseError = exports.NBaseVectorClient = exports.quote = exports.buildOrderBy = exports.parseWhere = exports.setAdapterMetadata = exports.executorFromAdapter = exports.createAdapterProxy = exports.createAn5Adapter = exports.AdapterTableClient = exports.An5Adapter = void 0;
|
|
4
4
|
var an5Adapter_1 = require("./an5Adapter");
|
|
5
5
|
Object.defineProperty(exports, "An5Adapter", { enumerable: true, get: function () { return an5Adapter_1.An5Adapter; } });
|
|
6
6
|
Object.defineProperty(exports, "AdapterTableClient", { enumerable: true, get: function () { return an5Adapter_1.AdapterTableClient; } });
|
|
7
7
|
Object.defineProperty(exports, "createAn5Adapter", { enumerable: true, get: function () { return an5Adapter_1.createAn5Adapter; } });
|
|
8
|
+
Object.defineProperty(exports, "createAdapterProxy", { enumerable: true, get: function () { return an5Adapter_1.createAdapterProxy; } });
|
|
9
|
+
Object.defineProperty(exports, "executorFromAdapter", { enumerable: true, get: function () { return an5Adapter_1.executorFromAdapter; } });
|
|
8
10
|
Object.defineProperty(exports, "setAdapterMetadata", { enumerable: true, get: function () { return an5Adapter_1.setAdapterMetadata; } });
|
|
11
|
+
var sql_1 = require("./base/sql");
|
|
12
|
+
Object.defineProperty(exports, "parseWhere", { enumerable: true, get: function () { return sql_1.parseWhere; } });
|
|
13
|
+
Object.defineProperty(exports, "buildOrderBy", { enumerable: true, get: function () { return sql_1.buildOrderBy; } });
|
|
14
|
+
Object.defineProperty(exports, "quote", { enumerable: true, get: function () { return sql_1.quote; } });
|
|
15
|
+
var nbase_1 = require("./nbase");
|
|
16
|
+
Object.defineProperty(exports, "NBaseVectorClient", { enumerable: true, get: function () { return nbase_1.NBaseVectorClient; } });
|
|
17
|
+
Object.defineProperty(exports, "NBaseError", { enumerable: true, get: function () { return nbase_1.NBaseError; } });
|
|
18
|
+
Object.defineProperty(exports, "createNBaseVectorClient", { enumerable: true, get: function () { return nbase_1.createNBaseVectorClient; } });
|
|
19
|
+
Object.defineProperty(exports, "createNBaseClient", { enumerable: true, get: function () { return nbase_1.createNBaseClient; } });
|
|
20
|
+
Object.defineProperty(exports, "parseNBaseConnectionString", { enumerable: true, get: function () { return nbase_1.parseNBaseConnectionString; } });
|
|
21
|
+
Object.defineProperty(exports, "buildVectorId", { enumerable: true, get: function () { return nbase_1.buildVectorId; } });
|
|
22
|
+
Object.defineProperty(exports, "parseVectorId", { enumerable: true, get: function () { return nbase_1.parseVectorId; } });
|
|
9
23
|
var config_1 = require("./config");
|
|
10
24
|
Object.defineProperty(exports, "getLlmConfig", { enumerable: true, get: function () { return config_1.getLlmConfig; } });
|
|
11
25
|
Object.defineProperty(exports, "setLlmConfig", { enumerable: true, get: function () { return config_1.setLlmConfig; } });
|
package/dist/mssql/engine.js
CHANGED
|
@@ -12,7 +12,7 @@ function parseMssqlConnectionString(url) {
|
|
|
12
12
|
// Strip scheme prefix
|
|
13
13
|
cleanUrl = cleanUrl.replace(/^(?:sqlserver|mssql):\/\//i, '');
|
|
14
14
|
const parts = cleanUrl.split(';');
|
|
15
|
-
const firstPart = parts[0].trim();
|
|
15
|
+
const firstPart = (parts[0] ?? '').trim();
|
|
16
16
|
// host:port or host,port (SQL Server native style)
|
|
17
17
|
let server = firstPart;
|
|
18
18
|
let port = 1433;
|
|
@@ -35,7 +35,10 @@ function parseMssqlConnectionString(url) {
|
|
|
35
35
|
connectionTimeout: 15000,
|
|
36
36
|
};
|
|
37
37
|
for (let i = 1; i < parts.length; i++) {
|
|
38
|
-
const
|
|
38
|
+
const rawPart = parts[i];
|
|
39
|
+
if (rawPart === undefined)
|
|
40
|
+
continue;
|
|
41
|
+
const part = rawPart.trim();
|
|
39
42
|
if (!part)
|
|
40
43
|
continue;
|
|
41
44
|
const eqIdx = part.indexOf('=');
|
|
@@ -52,7 +55,8 @@ function parseMssqlConnectionString(url) {
|
|
|
52
55
|
else if (key === 'server' || key === 'data source') {
|
|
53
56
|
// SERVER=host,port style (key-value form)
|
|
54
57
|
const [s, p] = value.split(',');
|
|
55
|
-
|
|
58
|
+
if (s !== undefined)
|
|
59
|
+
config.server = s.trim();
|
|
56
60
|
if (p)
|
|
57
61
|
config.port = parseInt(p.trim(), 10) || 1433;
|
|
58
62
|
}
|
|
@@ -70,7 +74,7 @@ class MssqlEngine {
|
|
|
70
74
|
constructor(adapterConfig) {
|
|
71
75
|
this.dialect = 'mssql';
|
|
72
76
|
this.pool = null;
|
|
73
|
-
this.config = parseMssqlConnectionString(adapterConfig.connectionString);
|
|
77
|
+
this.config = parseMssqlConnectionString(adapterConfig.connectionString ?? '');
|
|
74
78
|
if (adapterConfig.poolMax)
|
|
75
79
|
this.config.pool = { ...this.config.pool, max: adapterConfig.poolMax };
|
|
76
80
|
if (adapterConfig.requestTimeout)
|
package/dist/mysql/engine.js
CHANGED
|
@@ -14,7 +14,7 @@ class MysqlEngine {
|
|
|
14
14
|
if (!Mysql2)
|
|
15
15
|
throw new Error('mysql2 package is required for MySQL support. Run: npm install mysql2');
|
|
16
16
|
this.pool = Mysql2.createPool({
|
|
17
|
-
uri: adapterConfig.connectionString,
|
|
17
|
+
uri: adapterConfig.connectionString ?? '',
|
|
18
18
|
connectionLimit: adapterConfig.poolMax ?? 10,
|
|
19
19
|
connectTimeout: adapterConfig.connectionTimeout ?? 15000,
|
|
20
20
|
});
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NBase — Neural Vector Database client.
|
|
3
|
+
*
|
|
4
|
+
* NBase is a vector database with HNSW/LSH/KNN indexing exposed over a REST
|
|
5
|
+
* API. an5 uses it to move similarity search out of the database process: the
|
|
6
|
+
* vectors live in NBase, the rows stay in the relational table, and the search
|
|
7
|
+
* results are hydrated from the table by the id kept in vector metadata.
|
|
8
|
+
*
|
|
9
|
+
* The client only uses the global `fetch`, so it works in Node 18+ and in the
|
|
10
|
+
* browser without pulling in a dependency.
|
|
11
|
+
*/
|
|
12
|
+
export interface NBaseVector {
|
|
13
|
+
id: string | number;
|
|
14
|
+
vector: number[];
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface NBaseSearchOptions {
|
|
18
|
+
/** Number of neighbours to return. */
|
|
19
|
+
k?: number;
|
|
20
|
+
/** Distance metric; NBase accepts `cosine` and `euclidean`. */
|
|
21
|
+
distanceMetric?: 'cosine' | 'euclidean';
|
|
22
|
+
/** `hnsw` uses the graph index, anything else uses the clustered path. */
|
|
23
|
+
method?: 'hnsw' | 'clustered';
|
|
24
|
+
efSearch?: number;
|
|
25
|
+
filters?: Record<string, unknown> | Array<Record<string, unknown>>;
|
|
26
|
+
includeMetadata?: boolean;
|
|
27
|
+
includeVectors?: boolean;
|
|
28
|
+
skipCache?: boolean;
|
|
29
|
+
searchTimeoutMs?: number;
|
|
30
|
+
rerank?: boolean;
|
|
31
|
+
rerankingMethod?: string;
|
|
32
|
+
rerankLambda?: number;
|
|
33
|
+
partitionIds?: string[];
|
|
34
|
+
}
|
|
35
|
+
export interface NBaseSearchResult {
|
|
36
|
+
id: string | number;
|
|
37
|
+
/** Distance from the query vector. Lower is more similar. */
|
|
38
|
+
dist: number;
|
|
39
|
+
metadata?: Record<string, unknown>;
|
|
40
|
+
vector?: number[];
|
|
41
|
+
dimension?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface NBaseClientConfig {
|
|
44
|
+
/** Base URL, e.g. `http://localhost:1307`. */
|
|
45
|
+
url: string;
|
|
46
|
+
/** Optional bearer token, for deployments behind an auth proxy. */
|
|
47
|
+
token?: string;
|
|
48
|
+
/** Per-request timeout in milliseconds. */
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
/** Injectable for tests and for runtimes without a global fetch. */
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
}
|
|
53
|
+
export interface NBaseStats {
|
|
54
|
+
vectorCount?: number;
|
|
55
|
+
metadataCount?: number;
|
|
56
|
+
memoryUsage?: number;
|
|
57
|
+
[key: string]: unknown;
|
|
58
|
+
}
|
|
59
|
+
export declare class NBaseError extends Error {
|
|
60
|
+
readonly status?: number | undefined;
|
|
61
|
+
readonly body?: unknown;
|
|
62
|
+
constructor(message: string, status?: number | undefined, body?: unknown);
|
|
63
|
+
}
|
|
64
|
+
export declare class NBaseVectorClient {
|
|
65
|
+
private readonly config;
|
|
66
|
+
private readonly baseUrl;
|
|
67
|
+
private readonly fetchImpl;
|
|
68
|
+
private readonly timeoutMs;
|
|
69
|
+
constructor(config: NBaseClientConfig);
|
|
70
|
+
private request;
|
|
71
|
+
/** Liveness probe. NBase mounts its status routes at the server root. */
|
|
72
|
+
health(): Promise<{
|
|
73
|
+
status: string;
|
|
74
|
+
version?: string;
|
|
75
|
+
}>;
|
|
76
|
+
/** Vector count, memory use and other database statistics. */
|
|
77
|
+
stats(): Promise<NBaseStats>;
|
|
78
|
+
/** Adds or replaces vectors. NBase accepts a single vector or a bulk array. */
|
|
79
|
+
addVectors(vectors: NBaseVector[]): Promise<{
|
|
80
|
+
count: number;
|
|
81
|
+
ids?: Array<string | number>;
|
|
82
|
+
}>;
|
|
83
|
+
/** Nearest-neighbour search. Results are ordered by ascending `dist`. */
|
|
84
|
+
search(vector: number[], options?: NBaseSearchOptions): Promise<NBaseSearchResult[]>;
|
|
85
|
+
/** Reads a single vector. Returns undefined when the id is unknown. */
|
|
86
|
+
get(id: string | number): Promise<NBaseSearchResult | undefined>;
|
|
87
|
+
exists(id: string | number): Promise<boolean>;
|
|
88
|
+
delete(id: string | number): Promise<boolean>;
|
|
89
|
+
updateMetadata(id: string | number, metadata: Record<string, unknown>): Promise<boolean>;
|
|
90
|
+
}
|
|
91
|
+
/** Creates an NBase vector client. */
|
|
92
|
+
export declare function createNBaseVectorClient(config: NBaseClientConfig): NBaseVectorClient;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* NBase — Neural Vector Database client.
|
|
4
|
+
*
|
|
5
|
+
* NBase is a vector database with HNSW/LSH/KNN indexing exposed over a REST
|
|
6
|
+
* API. an5 uses it to move similarity search out of the database process: the
|
|
7
|
+
* vectors live in NBase, the rows stay in the relational table, and the search
|
|
8
|
+
* results are hydrated from the table by the id kept in vector metadata.
|
|
9
|
+
*
|
|
10
|
+
* The client only uses the global `fetch`, so it works in Node 18+ and in the
|
|
11
|
+
* browser without pulling in a dependency.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.NBaseVectorClient = exports.NBaseError = void 0;
|
|
15
|
+
exports.createNBaseVectorClient = createNBaseVectorClient;
|
|
16
|
+
const DEFAULT_TIMEOUT_MS = 30000;
|
|
17
|
+
class NBaseError extends Error {
|
|
18
|
+
constructor(message, status, body) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.status = status;
|
|
21
|
+
this.body = body;
|
|
22
|
+
this.name = 'NBaseError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.NBaseError = NBaseError;
|
|
26
|
+
class NBaseVectorClient {
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.config = config;
|
|
29
|
+
this.baseUrl = String(config.url).replace(/\/+$/, '');
|
|
30
|
+
const impl = config.fetchImpl ?? globalThis.fetch;
|
|
31
|
+
if (!impl) {
|
|
32
|
+
throw new NBaseError('No fetch implementation available. Node 18+ or a fetch polyfill is required.');
|
|
33
|
+
}
|
|
34
|
+
this.fetchImpl = impl;
|
|
35
|
+
this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
36
|
+
}
|
|
37
|
+
async request(path, init) {
|
|
38
|
+
const controller = new AbortController();
|
|
39
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
40
|
+
try {
|
|
41
|
+
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
42
|
+
...init,
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
headers: {
|
|
45
|
+
'content-type': 'application/json',
|
|
46
|
+
...(this.config.token ? { authorization: `Bearer ${this.config.token}` } : {}),
|
|
47
|
+
...init?.headers,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const text = await response.text();
|
|
51
|
+
let body;
|
|
52
|
+
try {
|
|
53
|
+
body = text ? JSON.parse(text) : undefined;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
body = text;
|
|
57
|
+
}
|
|
58
|
+
if (!response.ok) {
|
|
59
|
+
const message = (body && typeof body === 'object' && 'error' in body
|
|
60
|
+
? String(body.error)
|
|
61
|
+
: undefined) ?? `HTTP ${response.status}`;
|
|
62
|
+
throw new NBaseError(`NBase request ${path} failed: ${message}`, response.status, body);
|
|
63
|
+
}
|
|
64
|
+
return body;
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
if (err instanceof NBaseError)
|
|
68
|
+
throw err;
|
|
69
|
+
if (err?.name === 'AbortError') {
|
|
70
|
+
throw new NBaseError(`NBase request ${path} timed out after ${this.timeoutMs}ms`);
|
|
71
|
+
}
|
|
72
|
+
throw new NBaseError(`Could not reach NBase at ${this.baseUrl}: ${err instanceof Error ? err.message : String(err)}`);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Liveness probe. NBase mounts its status routes at the server root. */
|
|
79
|
+
async health() {
|
|
80
|
+
return this.request('/health');
|
|
81
|
+
}
|
|
82
|
+
/** Vector count, memory use and other database statistics. */
|
|
83
|
+
async stats() {
|
|
84
|
+
return this.request('/stats');
|
|
85
|
+
}
|
|
86
|
+
/** Adds or replaces vectors. NBase accepts a single vector or a bulk array. */
|
|
87
|
+
async addVectors(vectors) {
|
|
88
|
+
if (vectors.length === 0)
|
|
89
|
+
return { count: 0 };
|
|
90
|
+
const result = await this.request('/api/vectors', { method: 'POST', body: JSON.stringify({ vectors: vectors.length === 1 ? vectors[0] : vectors }) });
|
|
91
|
+
return { count: result.count ?? vectors.length, ...(result.addedIds ? { ids: result.addedIds } : {}) };
|
|
92
|
+
}
|
|
93
|
+
/** Nearest-neighbour search. Results are ordered by ascending `dist`. */
|
|
94
|
+
async search(vector, options = {}) {
|
|
95
|
+
const body = await this.request('/api/search', {
|
|
96
|
+
method: 'POST',
|
|
97
|
+
body: JSON.stringify({
|
|
98
|
+
query: vector,
|
|
99
|
+
k: options.k ?? 10,
|
|
100
|
+
...(options.distanceMetric ? { distanceMetric: options.distanceMetric } : {}),
|
|
101
|
+
...(options.method ? { method: options.method } : {}),
|
|
102
|
+
...(options.efSearch !== undefined ? { efSearch: options.efSearch } : {}),
|
|
103
|
+
...(options.filters ? { filters: options.filters } : {}),
|
|
104
|
+
...(options.includeMetadata !== undefined ? { includeMetadata: options.includeMetadata } : {}),
|
|
105
|
+
...(options.includeVectors !== undefined ? { includeVectors: options.includeVectors } : {}),
|
|
106
|
+
...(options.skipCache !== undefined ? { skipCache: options.skipCache } : {}),
|
|
107
|
+
...(options.searchTimeoutMs !== undefined ? { searchTimeoutMs: options.searchTimeoutMs } : {}),
|
|
108
|
+
...(options.rerank !== undefined ? { rerank: options.rerank } : {}),
|
|
109
|
+
...(options.rerankingMethod ? { rerankingMethod: options.rerankingMethod } : {}),
|
|
110
|
+
...(options.rerankLambda !== undefined ? { rerankLambda: options.rerankLambda } : {}),
|
|
111
|
+
...(options.partitionIds ? { partitionIds: options.partitionIds } : {}),
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
return body.results ?? [];
|
|
115
|
+
}
|
|
116
|
+
/** Reads a single vector. Returns undefined when the id is unknown. */
|
|
117
|
+
async get(id) {
|
|
118
|
+
try {
|
|
119
|
+
return await this.request(`/api/vectors/${encodeURIComponent(String(id))}`);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (err instanceof NBaseError && err.status === 404)
|
|
123
|
+
return undefined;
|
|
124
|
+
throw err;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async exists(id) {
|
|
128
|
+
const result = await this.request(`/api/vectors/${encodeURIComponent(String(id))}/exists`);
|
|
129
|
+
return result.exists === true;
|
|
130
|
+
}
|
|
131
|
+
async delete(id) {
|
|
132
|
+
await this.request(`/api/vectors/${encodeURIComponent(String(id))}`, { method: 'DELETE' });
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
async updateMetadata(id, metadata) {
|
|
136
|
+
await this.request(`/api/vectors/${encodeURIComponent(String(id))}/metadata`, {
|
|
137
|
+
method: 'PATCH',
|
|
138
|
+
body: JSON.stringify(metadata),
|
|
139
|
+
});
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
exports.NBaseVectorClient = NBaseVectorClient;
|
|
144
|
+
/** Creates an NBase vector client. */
|
|
145
|
+
function createNBaseVectorClient(config) {
|
|
146
|
+
return new NBaseVectorClient(config);
|
|
147
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NBase connection-string and adapter configuration.
|
|
3
|
+
*
|
|
4
|
+
* NBase is configured through the connection string alone:
|
|
5
|
+
*
|
|
6
|
+
* createAn5Adapter({ connectionString: 'nbase://localhost:1307' })
|
|
7
|
+
*
|
|
8
|
+
* Accepted forms are `nbase://host:port`, `nbase:host:port` and an explicit
|
|
9
|
+
* scheme, with optional `?token=…&timeoutMs=…&method=…` options. An adapter
|
|
10
|
+
* created this way is vector-only: it has no relational database, so a search
|
|
11
|
+
* returns the NBase hits instead of table rows.
|
|
12
|
+
*/
|
|
13
|
+
import { NBaseVectorClient, NBaseError, createNBaseVectorClient, type NBaseClientConfig, type NBaseVector, type NBaseSearchOptions, type NBaseSearchResult, type NBaseStats } from './client';
|
|
14
|
+
export interface NBaseAdapterConfig extends NBaseClientConfig {
|
|
15
|
+
url: string;
|
|
16
|
+
/**
|
|
17
|
+
* Metadata key that holds the relational row id. `an5Id` by default, which
|
|
18
|
+
* is what `indexTableVectors` writes.
|
|
19
|
+
*/
|
|
20
|
+
idField?: string;
|
|
21
|
+
/** Metadata key holding the model name, used to keep collections apart. */
|
|
22
|
+
modelField?: string;
|
|
23
|
+
/** Force the search method instead of letting NBase choose. */
|
|
24
|
+
method?: 'hnsw' | 'clustered';
|
|
25
|
+
}
|
|
26
|
+
/** True when the whole connection string points at NBase. */
|
|
27
|
+
export declare function isNBaseConnectionString(connectionString: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Parses an NBase connection string.
|
|
30
|
+
*
|
|
31
|
+
* Accepts `nbase:http://host:port`, `nbase://host:port` and
|
|
32
|
+
* `nbase:host:port`, with optional `?token=…&timeoutMs=…` options.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseNBaseConnectionString(connectionString: string): NBaseAdapterConfig;
|
|
35
|
+
/** Builds the vector id used to link a NBase vector back to a relational row. */
|
|
36
|
+
export declare function buildVectorId(model: string, id: string | number): string;
|
|
37
|
+
/** Splits a vector id produced by {@link buildVectorId}. */
|
|
38
|
+
export declare function parseVectorId(vectorId: string | number): {
|
|
39
|
+
model: string;
|
|
40
|
+
id: string;
|
|
41
|
+
};
|
|
42
|
+
export declare function createNBaseClient(config: NBaseAdapterConfig | string): {
|
|
43
|
+
client: NBaseVectorClient;
|
|
44
|
+
options: NBaseAdapterConfig;
|
|
45
|
+
};
|
|
46
|
+
export { NBaseVectorClient, NBaseError, createNBaseVectorClient };
|
|
47
|
+
export type { NBaseClientConfig, NBaseVector, NBaseSearchOptions, NBaseSearchResult, NBaseStats };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNBaseVectorClient = exports.NBaseError = exports.NBaseVectorClient = void 0;
|
|
4
|
+
exports.isNBaseConnectionString = isNBaseConnectionString;
|
|
5
|
+
exports.parseNBaseConnectionString = parseNBaseConnectionString;
|
|
6
|
+
exports.buildVectorId = buildVectorId;
|
|
7
|
+
exports.parseVectorId = parseVectorId;
|
|
8
|
+
exports.createNBaseClient = createNBaseClient;
|
|
9
|
+
/**
|
|
10
|
+
* NBase connection-string and adapter configuration.
|
|
11
|
+
*
|
|
12
|
+
* NBase is configured through the connection string alone:
|
|
13
|
+
*
|
|
14
|
+
* createAn5Adapter({ connectionString: 'nbase://localhost:1307' })
|
|
15
|
+
*
|
|
16
|
+
* Accepted forms are `nbase://host:port`, `nbase:host:port` and an explicit
|
|
17
|
+
* scheme, with optional `?token=…&timeoutMs=…&method=…` options. An adapter
|
|
18
|
+
* created this way is vector-only: it has no relational database, so a search
|
|
19
|
+
* returns the NBase hits instead of table rows.
|
|
20
|
+
*/
|
|
21
|
+
const client_1 = require("./client");
|
|
22
|
+
Object.defineProperty(exports, "NBaseVectorClient", { enumerable: true, get: function () { return client_1.NBaseVectorClient; } });
|
|
23
|
+
Object.defineProperty(exports, "NBaseError", { enumerable: true, get: function () { return client_1.NBaseError; } });
|
|
24
|
+
Object.defineProperty(exports, "createNBaseVectorClient", { enumerable: true, get: function () { return client_1.createNBaseVectorClient; } });
|
|
25
|
+
/** Matches `nbase:`, `nbase://` and `nbase=http(s)://` at the start of a value. */
|
|
26
|
+
const NBASE_PREFIX = /^nbase:(?:\/\/)?/i;
|
|
27
|
+
/** True when the whole connection string points at NBase. */
|
|
28
|
+
function isNBaseConnectionString(connectionString) {
|
|
29
|
+
return NBASE_PREFIX.test(connectionString.trim());
|
|
30
|
+
}
|
|
31
|
+
/** Builds options from a URL and an optional query string. */
|
|
32
|
+
function buildOptions(url, query) {
|
|
33
|
+
const params = new URLSearchParams(query ?? '');
|
|
34
|
+
const trimmed = url.trim().replace(/\/+$/, '');
|
|
35
|
+
// `nbase://host:port` is shorthand for the same host over HTTP; an explicit
|
|
36
|
+
// scheme is used as-is so https deployments work.
|
|
37
|
+
const withScheme = !trimmed
|
|
38
|
+
? 'http://localhost:1307'
|
|
39
|
+
: /^[a-z]+:\/\//i.test(trimmed)
|
|
40
|
+
? trimmed
|
|
41
|
+
: `http://${trimmed}`;
|
|
42
|
+
return {
|
|
43
|
+
url: withScheme,
|
|
44
|
+
...(params.get('token') ? { token: params.get('token') } : {}),
|
|
45
|
+
...(params.get('timeoutMs') ? { timeoutMs: Number(params.get('timeoutMs')) } : {}),
|
|
46
|
+
...(params.get('idField') ? { idField: params.get('idField') } : {}),
|
|
47
|
+
...(params.get('modelField') ? { modelField: params.get('modelField') } : {}),
|
|
48
|
+
...(params.get('method') ? { method: params.get('method') } : {}),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parses an NBase connection string.
|
|
53
|
+
*
|
|
54
|
+
* Accepts `nbase:http://host:port`, `nbase://host:port` and
|
|
55
|
+
* `nbase:host:port`, with optional `?token=…&timeoutMs=…` options.
|
|
56
|
+
*/
|
|
57
|
+
function parseNBaseConnectionString(connectionString) {
|
|
58
|
+
const raw = connectionString.trim();
|
|
59
|
+
if (!isNBaseConnectionString(raw)) {
|
|
60
|
+
throw new Error(`Not an NBase connection string: ${raw}`);
|
|
61
|
+
}
|
|
62
|
+
const [url, query] = raw.replace(NBASE_PREFIX, '').split('?');
|
|
63
|
+
return buildOptions(url ?? '', query);
|
|
64
|
+
}
|
|
65
|
+
/** Builds the vector id used to link a NBase vector back to a relational row. */
|
|
66
|
+
function buildVectorId(model, id) {
|
|
67
|
+
return `${model}:${id}`;
|
|
68
|
+
}
|
|
69
|
+
/** Splits a vector id produced by {@link buildVectorId}. */
|
|
70
|
+
function parseVectorId(vectorId) {
|
|
71
|
+
const raw = String(vectorId);
|
|
72
|
+
const separator = raw.indexOf(':');
|
|
73
|
+
if (separator === -1)
|
|
74
|
+
return { model: '', id: raw };
|
|
75
|
+
return { model: raw.slice(0, separator), id: raw.slice(separator + 1) };
|
|
76
|
+
}
|
|
77
|
+
function createNBaseClient(config) {
|
|
78
|
+
const options = typeof config === 'string' ? parseNBaseConnectionString(config) : config;
|
|
79
|
+
return { client: (0, client_1.createNBaseVectorClient)(options), options };
|
|
80
|
+
}
|
package/dist/postgres/engine.js
CHANGED
|
@@ -14,7 +14,7 @@ class PostgresEngine {
|
|
|
14
14
|
if (!PgPool)
|
|
15
15
|
throw new Error('pg package is required for PostgreSQL support. Run: npm install pg');
|
|
16
16
|
this.pool = new PgPool({
|
|
17
|
-
connectionString: adapterConfig.connectionString,
|
|
17
|
+
connectionString: adapterConfig.connectionString ?? '',
|
|
18
18
|
max: adapterConfig.poolMax ?? 10,
|
|
19
19
|
});
|
|
20
20
|
}
|