@an5/adapters 0.2.10 → 0.2.13
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 +163 -2
- package/dist/an5Adapter.d.ts +37 -0
- package/dist/an5Adapter.js +190 -65
- package/dist/base/metadata.d.ts +2 -0
- package/dist/base/metadata.js +10 -0
- package/dist/base/sql.d.ts +2 -0
- package/dist/base/sql.js +24 -25
- package/dist/base/types.d.ts +14 -0
- package/dist/googlesheets/adapter.js +16 -8
- package/dist/googlesheets/config.d.ts +13 -0
- package/dist/googlesheets/config.js +5 -1
- package/dist/googlesheets/oauth.d.ts +3 -0
- package/dist/googlesheets/oauth.js +43 -0
- package/dist/googlesheets/parseConnectionString.js +12 -0
- package/dist/googlesheets/tableClient.js +5 -23
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -1
- package/dist/sqlite/browserEngine.d.ts +13 -0
- package/dist/sqlite/browserEngine.js +13 -0
- package/dist/sqlite/engine.d.ts +5 -0
- package/dist/sqlite/engine.js +10 -0
- package/dist/sqlite/index.d.ts +1 -0
- package/dist/sqlite/index.js +1 -0
- package/dist/sqlite/vector.d.ts +155 -0
- package/dist/sqlite/vector.js +436 -0
- package/dotnet/An5Adapter.cs +85 -27
- package/dotnet/Base/Core.cs +14 -0
- package/dotnet/Mssql/MssqlEngine.cs +44 -1
- package/dotnet/Postgres/PostgresEngine.cs +2 -0
- package/dotnet/Sqlite/SqliteEngine.cs +82 -2
- package/dotnet/Sqlite/SqliteVectors.cs +401 -0
- package/golang/an5_adapter.go +84 -32
- package/golang/base/vectors.go +263 -0
- package/golang/sqlite/vector.go +248 -0
- package/golang/sqlite_vector_test.go +288 -0
- package/golang/table_client.go +67 -3
- package/java/pom.xml +177 -0
- package/java/src/main/java/an5/adapters/An5Adapter.java +374 -0
- package/java/src/main/java/an5/adapters/An5Aggregate.java +116 -0
- package/java/src/main/java/an5/adapters/An5GroupBy.java +97 -0
- package/java/src/main/java/an5/adapters/An5Query.java +100 -0
- package/java/src/main/java/an5/adapters/An5TableClient.java +1031 -0
- package/java/src/main/java/an5/adapters/An5ViewClient.java +107 -0
- package/java/src/main/java/an5/adapters/base/Dialect.java +103 -0
- package/java/src/main/java/an5/adapters/base/FieldMeta.java +42 -0
- package/java/src/main/java/an5/adapters/base/JdbcUrls.java +201 -0
- package/java/src/main/java/an5/adapters/base/Metadata.java +195 -0
- package/java/src/main/java/an5/adapters/base/RelationDef.java +26 -0
- package/java/src/main/java/an5/adapters/base/SqlBuilder.java +422 -0
- package/java/src/main/java/an5/adapters/base/SqliteVectors.java +375 -0
- package/java/src/main/java/an5/adapters/base/Vectors.java +123 -0
- package/java/src/test/java/An5AdaptersSmoke.java +733 -0
- package/java/src/test/java/Json.java +174 -0
- package/java/src/test/java/QuerySemantics.java +111 -0
- package/kotlin/build.gradle.kts +145 -0
- package/kotlin/settings.gradle.kts +10 -0
- package/kotlin/src/main/kotlin/an5/adapters/Aggregate.kt +89 -0
- package/kotlin/src/main/kotlin/an5/adapters/An5.kt +91 -0
- package/kotlin/src/main/kotlin/an5/adapters/Query.kt +130 -0
- package/kotlin/src/main/kotlin/an5/adapters/Rows.kt +166 -0
- package/kotlin/src/main/kotlin/an5/adapters/TableClient.kt +169 -0
- package/kotlin/src/main/kotlin/an5/adapters/Types.kt +77 -0
- package/kotlin/src/test/kotlin/an5/adapters/An5Smoke.kt +329 -0
- package/native/sqlite/CMakeLists.txt +12 -0
- package/native/sqlite/README.md +117 -0
- package/native/sqlite/an5_vector.c +209 -0
- package/package.json +40 -9
- package/python/an5_adapter.py +37 -6
- package/python/base/__init__.py +15 -0
- package/python/base/vectors.py +434 -0
- package/python/sqlite/__init__.py +2 -2
- package/python/sqlite/provider.py +21 -1
- package/python/table_client.py +129 -59
- package/rust/src/adapter.rs +342 -24
- package/rust/src/base/mod.rs +7 -0
- package/rust/src/base/vectors.rs +293 -0
- package/rust/src/lib.rs +3 -3
- package/scripts/sqlite-native-build.js +32 -0
- package/swift/Package.swift +22 -0
- package/swift/Sources/An5Adapters/An5Adapter.swift +160 -0
- package/swift/Sources/An5Adapters/Metadata.swift +183 -0
- package/swift/Sources/An5Adapters/Query.swift +105 -0
- package/swift/Sources/An5Adapters/Row+Accessors.swift +129 -0
- package/swift/Sources/An5Adapters/SQLBuilder.swift +359 -0
- package/swift/Sources/An5Adapters/SQLiteDriver.swift +301 -0
- package/swift/Sources/An5Adapters/SqliteVectors.swift +243 -0
- package/swift/Sources/An5Adapters/TableClient.swift +671 -0
- package/swift/Sources/An5Adapters/Types.swift +127 -0
- package/swift/Sources/An5Adapters/Vectors.swift +86 -0
- package/swift/Sources/An5Adapters/ViewClient.swift +50 -0
- package/swift/Sources/CSQLite/module.modulemap +8 -0
- package/swift/Sources/CSQLite/shim.h +9 -0
- package/swift/Tests/An5AdaptersTests/QuerySemanticsTests.swift +51 -0
- package/swift/Tests/An5AdaptersTests/RuntimeSmokeTests.swift +488 -0
- package/typescript/src/an5Adapter.ts +200 -58
- package/typescript/src/base/metadata.ts +8 -0
- package/typescript/src/base/sql.ts +23 -16
- package/typescript/src/base/types.ts +15 -0
- package/typescript/src/googlesheets/adapter.ts +17 -8
- package/typescript/src/googlesheets/config.ts +10 -1
- package/typescript/src/googlesheets/oauth.ts +31 -0
- package/typescript/src/googlesheets/parseConnectionString.ts +8 -0
- package/typescript/src/googlesheets/tableClient.ts +5 -19
- package/typescript/src/index.ts +13 -0
- package/typescript/src/sqlite/browserEngine.ts +24 -0
- package/typescript/src/sqlite/engine.ts +13 -0
- package/typescript/src/sqlite/index.ts +1 -1
- package/typescript/src/sqlite/vector.ts +541 -0
- package/golang/sqlite/sqlite.go +0 -14
|
@@ -3,27 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.An5SheetsAdapter = void 0;
|
|
4
4
|
exports.createAn5SheetsAdapter = createAn5SheetsAdapter;
|
|
5
5
|
const config_1 = require("./config");
|
|
6
|
+
const oauth_1 = require("./oauth");
|
|
6
7
|
const sqlExecutor_1 = require("./sqlExecutor");
|
|
7
8
|
const tableClient_1 = require("./tableClient");
|
|
8
9
|
const retry_1 = require("./retry");
|
|
9
10
|
const metadata_1 = require("../base/metadata");
|
|
10
11
|
// ─── Fetch-based API proxy for OAuth Access Token / API Key (browser-compatible) ──
|
|
11
|
-
function createFetchApi(spreadsheetId, accessToken, apiKey) {
|
|
12
|
+
function createFetchApi(spreadsheetId, accessToken, apiKey, oauth = { spreadsheetId }) {
|
|
12
13
|
const base = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}`;
|
|
13
14
|
const headers = { 'Content-Type': 'application/json' };
|
|
14
|
-
|
|
15
|
-
headers['Authorization'] = `Bearer ${accessToken}`;
|
|
16
|
-
}
|
|
15
|
+
const tokenProvider = (0, oauth_1.sheetsTokenProvider)({ ...oauth, ...(accessToken ? { accessToken } : {}) });
|
|
17
16
|
async function request(method, path, body) {
|
|
18
17
|
let url = path.startsWith('http') ? path : `${base}${path}`;
|
|
19
18
|
if (apiKey) {
|
|
20
19
|
const sep = url.includes('?') ? '&' : '?';
|
|
21
20
|
url += `${sep}key=${encodeURIComponent(apiKey)}`;
|
|
22
21
|
}
|
|
23
|
-
const
|
|
22
|
+
const token = await tokenProvider();
|
|
23
|
+
const opts = { method, headers: { ...headers, ...(token ? { Authorization: `Bearer ${token}` } : {}) } };
|
|
24
24
|
if (body)
|
|
25
25
|
opts.body = JSON.stringify(body);
|
|
26
|
-
|
|
26
|
+
let res = await fetch(url, opts);
|
|
27
|
+
if (res.status === 401 && oauth.refreshToken) {
|
|
28
|
+
const refreshed = await tokenProvider(true);
|
|
29
|
+
res = await fetch(url, { ...opts, headers: { ...headers, Authorization: `Bearer ${refreshed}` } });
|
|
30
|
+
}
|
|
27
31
|
if (!res.ok) {
|
|
28
32
|
const text = await res.text().catch(() => '');
|
|
29
33
|
const err = new Error(`Google Sheets API error (${res.status}): ${text}`);
|
|
@@ -79,17 +83,21 @@ class An5SheetsAdapter {
|
|
|
79
83
|
this.sheets = null;
|
|
80
84
|
this.fetchApi = null;
|
|
81
85
|
this.sheetsCache = null;
|
|
86
|
+
const browser = typeof window !== 'undefined' || (typeof self !== 'undefined' && typeof process === 'undefined');
|
|
87
|
+
if (browser && (config.refreshToken || config.oauthClientSecret || config.privateKey || config.credentials)) {
|
|
88
|
+
throw new Error('Browser Google Sheets connections require a user access token. Keep desktop OAuth refresh tokens and service account keys outside the browser.');
|
|
89
|
+
}
|
|
82
90
|
this.config = (0, config_1.resolveConfig)(config);
|
|
83
91
|
// Dynamic model access (`db.user` / `db.User`), same as An5Adapter.
|
|
84
92
|
return (0, metadata_1.createAdapterProxy)(this, (name) => this.table(name));
|
|
85
93
|
}
|
|
86
94
|
get isFetchMode() {
|
|
87
|
-
return !!this.config.accessToken || !!this.config.apiKey;
|
|
95
|
+
return !!this.config.accessToken || !!this.config.refreshToken || !!this.config.apiKey;
|
|
88
96
|
}
|
|
89
97
|
async getSheets() {
|
|
90
98
|
if (this.isFetchMode) {
|
|
91
99
|
if (!this.fetchApi) {
|
|
92
|
-
this.fetchApi = createFetchApi(this.config.spreadsheetId, this.config.accessToken, this.config.apiKey);
|
|
100
|
+
this.fetchApi = createFetchApi(this.config.spreadsheetId, this.config.accessToken, this.config.apiKey, this.config);
|
|
93
101
|
}
|
|
94
102
|
return this.fetchApi;
|
|
95
103
|
}
|
|
@@ -11,6 +11,11 @@ export interface An5SheetsAdapterConfig {
|
|
|
11
11
|
* When provided, the adapter uses raw fetch() instead of googleapis JWT, making it compatible
|
|
12
12
|
* with browser environments. Mutually exclusive with clientEmail/privateKey/credentials. */
|
|
13
13
|
accessToken?: string;
|
|
14
|
+
/** Offline desktop OAuth credentials. Keep these in secure storage, never source control. */
|
|
15
|
+
refreshToken?: string;
|
|
16
|
+
oauthClientId?: string;
|
|
17
|
+
oauthClientSecret?: string;
|
|
18
|
+
tokenExpiresAt?: number;
|
|
14
19
|
/** Google API key for browser-based API access. */
|
|
15
20
|
apiKey?: string;
|
|
16
21
|
}
|
|
@@ -18,12 +23,20 @@ export declare function normalizeKey(key: string): string;
|
|
|
18
23
|
export declare function resolveConfig(config: An5SheetsAdapterConfig): {
|
|
19
24
|
spreadsheetId: string;
|
|
20
25
|
accessToken: string | undefined;
|
|
26
|
+
refreshToken: string | undefined;
|
|
27
|
+
oauthClientId: string | undefined;
|
|
28
|
+
oauthClientSecret: string | undefined;
|
|
29
|
+
tokenExpiresAt: number | undefined;
|
|
21
30
|
apiKey: string | undefined;
|
|
22
31
|
sheetMapping: Record<string, string> | undefined;
|
|
23
32
|
clientEmail?: never;
|
|
24
33
|
privateKey?: never;
|
|
25
34
|
} | {
|
|
26
35
|
accessToken?: never;
|
|
36
|
+
refreshToken?: never;
|
|
37
|
+
oauthClientId?: never;
|
|
38
|
+
oauthClientSecret?: never;
|
|
39
|
+
tokenExpiresAt?: never;
|
|
27
40
|
apiKey?: never;
|
|
28
41
|
spreadsheetId: string;
|
|
29
42
|
clientEmail: string;
|
|
@@ -12,10 +12,14 @@ function normalizeKey(key) {
|
|
|
12
12
|
return `-----BEGIN PRIVATE KEY-----\n${lines}\n-----END PRIVATE KEY-----`;
|
|
13
13
|
}
|
|
14
14
|
function resolveConfig(config) {
|
|
15
|
-
if (config.accessToken || config.apiKey) {
|
|
15
|
+
if (config.accessToken || config.refreshToken || config.apiKey) {
|
|
16
16
|
return {
|
|
17
17
|
spreadsheetId: config.spreadsheetId,
|
|
18
18
|
accessToken: config.accessToken,
|
|
19
|
+
refreshToken: config.refreshToken,
|
|
20
|
+
oauthClientId: config.oauthClientId,
|
|
21
|
+
oauthClientSecret: config.oauthClientSecret,
|
|
22
|
+
tokenExpiresAt: config.tokenExpiresAt,
|
|
19
23
|
apiKey: config.apiKey,
|
|
20
24
|
sheetMapping: config.sheetMapping,
|
|
21
25
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sheetsTokenProvider = sheetsTokenProvider;
|
|
4
|
+
/** Deduplicate refresh requests within an adapter; do not expose token responses. */
|
|
5
|
+
function sheetsTokenProvider(config) {
|
|
6
|
+
let token = config.accessToken;
|
|
7
|
+
let expiresAt = config.tokenExpiresAt;
|
|
8
|
+
let pending;
|
|
9
|
+
return async (force = false) => {
|
|
10
|
+
if (token && !force && (expiresAt === undefined || expiresAt > Date.now() + 60000))
|
|
11
|
+
return token;
|
|
12
|
+
if (!config.refreshToken || !config.oauthClientId) {
|
|
13
|
+
if (force || expiresAt !== undefined)
|
|
14
|
+
throw new Error('Google access expired. Reconnect your Google account.');
|
|
15
|
+
return token;
|
|
16
|
+
}
|
|
17
|
+
if (!pending)
|
|
18
|
+
pending = (async () => {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch('https://oauth2.googleapis.com/token', {
|
|
21
|
+
method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
22
|
+
body: new URLSearchParams({ grant_type: 'refresh_token', client_id: config.oauthClientId, refresh_token: config.refreshToken, ...(config.oauthClientSecret ? { client_secret: config.oauthClientSecret } : {}) }),
|
|
23
|
+
signal: AbortSignal.timeout(20000),
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok)
|
|
26
|
+
throw new Error();
|
|
27
|
+
const result = await response.json();
|
|
28
|
+
if (!result.access_token || typeof result.access_token !== 'string' || typeof result.expires_in !== 'number' || !Number.isFinite(result.expires_in) || result.expires_in <= 0)
|
|
29
|
+
throw new Error();
|
|
30
|
+
token = result.access_token;
|
|
31
|
+
expiresAt = Date.now() + result.expires_in * 1000;
|
|
32
|
+
return token;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error('Google access expired or was revoked. Reconnect your Google account.');
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
pending = undefined;
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
return pending;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -36,6 +36,18 @@ function parseSheetsConnectionString(url) {
|
|
|
36
36
|
result.privateKey = config.privatekey;
|
|
37
37
|
if (config.accesstoken)
|
|
38
38
|
result.accessToken = config.accesstoken;
|
|
39
|
+
if (config.refreshtoken)
|
|
40
|
+
result.refreshToken = config.refreshtoken;
|
|
41
|
+
if (config.oauthclientid)
|
|
42
|
+
result.oauthClientId = config.oauthclientid;
|
|
43
|
+
if (config.oauthclientsecret)
|
|
44
|
+
result.oauthClientSecret = config.oauthclientsecret;
|
|
45
|
+
if (config.tokenexpiresat) {
|
|
46
|
+
const expiry = Number(config.tokenexpiresat);
|
|
47
|
+
if (!Number.isFinite(expiry) || expiry < 0)
|
|
48
|
+
throw new Error('Invalid OAuth token expiry.');
|
|
49
|
+
result.tokenExpiresAt = expiry;
|
|
50
|
+
}
|
|
39
51
|
if (config.apikey)
|
|
40
52
|
result.apiKey = config.apikey;
|
|
41
53
|
if (config.sheetmapping) {
|
|
@@ -6,11 +6,6 @@ const metadata_1 = require("../base/metadata");
|
|
|
6
6
|
const helpers_1 = require("./helpers");
|
|
7
7
|
const retry_1 = require("./retry");
|
|
8
8
|
// ─── Utility ──────────────────────────────────────────────────────────────────
|
|
9
|
-
function resolveIdField(fields) {
|
|
10
|
-
if (Object.prototype.hasOwnProperty.call(fields, 'id'))
|
|
11
|
-
return 'id';
|
|
12
|
-
return Object.keys(fields).find(name => name.endsWith('_id') || name.endsWith('Id') || name.toLowerCase() === 'id');
|
|
13
|
-
}
|
|
14
9
|
// ─── Table Client ─────────────────────────────────────────────────────────────
|
|
15
10
|
class SheetsTableClient {
|
|
16
11
|
constructor(adapter, modelName, sheetMapping) {
|
|
@@ -156,7 +151,7 @@ class SheetsTableClient {
|
|
|
156
151
|
return rows.length;
|
|
157
152
|
}
|
|
158
153
|
assignId(data, fields) {
|
|
159
|
-
const idFieldName = resolveIdField(fields);
|
|
154
|
+
const idFieldName = (0, metadata_1.resolveIdField)(fields);
|
|
160
155
|
if (!idFieldName)
|
|
161
156
|
return;
|
|
162
157
|
const fieldDef = fields[idFieldName];
|
|
@@ -201,23 +196,10 @@ class SheetsTableClient {
|
|
|
201
196
|
}
|
|
202
197
|
return this.rowToValues(data, headers);
|
|
203
198
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
if (!args.skipDuplicates)
|
|
210
|
-
throw e;
|
|
211
|
-
let count = 0;
|
|
212
|
-
for (const row of args.data) {
|
|
213
|
-
try {
|
|
214
|
-
await this.create({ data: row });
|
|
215
|
-
count++;
|
|
216
|
-
}
|
|
217
|
-
catch { /* skip */ }
|
|
218
|
-
}
|
|
219
|
-
return { count };
|
|
220
|
-
}
|
|
199
|
+
// Sheets has no unique constraints. An append failure must propagate;
|
|
200
|
+
// retrying individual rows could duplicate a batch the service accepted.
|
|
201
|
+
await this.adapter.appendRange(`${this.escSheetName}!A:A`, batchValues);
|
|
202
|
+
return { count: batchValues.length };
|
|
221
203
|
}
|
|
222
204
|
async update(args) {
|
|
223
205
|
const { headers, rows } = await this.readAllRows();
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { parseWhere, buildOrderBy, quote } from './base/sql';
|
|
|
3
3
|
export { NBaseVectorClient, NBaseError, createNBaseVectorClient, createNBaseClient, parseNBaseConnectionString, buildVectorId, parseVectorId, } from './nbase';
|
|
4
4
|
export type { NBaseAdapterConfig, NBaseClientConfig, NBaseVector, NBaseSearchOptions, NBaseSearchResult, NBaseStats, } from './nbase';
|
|
5
5
|
export type { An5AdapterConfig, AdapterMetadata, Dialect, } from './an5Adapter';
|
|
6
|
+
export { encodeVector, decodeVector, vectorDistance, isVectorField, AN5_VECTOR_FUNCTIONS, SQLITE_VEC_FUNCTIONS, } from './sqlite/vector';
|
|
7
|
+
export type { SqliteVectorStrategy, VectorMetric, VectorStrategyPreference, } from './sqlite/vector';
|
|
6
8
|
export type { TypedAn5Adapter, AdapterAPI } from './typed';
|
|
7
9
|
export { getLlmConfig, setLlmConfig, getEmbeddingConfig, setEmbeddingConfig, resetAdapter, } from './config';
|
|
8
10
|
export type { LlmConfigData, EmbeddingConfigData, } from './config';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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.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;
|
|
3
|
+
exports.parseSheetsConnectionString = exports.createAn5SheetsAdapter = exports.SheetsTableClient = exports.An5SheetsAdapter = exports.resetAdapter = exports.setEmbeddingConfig = exports.getEmbeddingConfig = exports.setLlmConfig = exports.getLlmConfig = exports.SQLITE_VEC_FUNCTIONS = exports.AN5_VECTOR_FUNCTIONS = exports.isVectorField = exports.vectorDistance = exports.decodeVector = exports.encodeVector = 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; } });
|
|
@@ -20,6 +20,13 @@ Object.defineProperty(exports, "createNBaseClient", { enumerable: true, get: fun
|
|
|
20
20
|
Object.defineProperty(exports, "parseNBaseConnectionString", { enumerable: true, get: function () { return nbase_1.parseNBaseConnectionString; } });
|
|
21
21
|
Object.defineProperty(exports, "buildVectorId", { enumerable: true, get: function () { return nbase_1.buildVectorId; } });
|
|
22
22
|
Object.defineProperty(exports, "parseVectorId", { enumerable: true, get: function () { return nbase_1.parseVectorId; } });
|
|
23
|
+
var vector_1 = require("./sqlite/vector");
|
|
24
|
+
Object.defineProperty(exports, "encodeVector", { enumerable: true, get: function () { return vector_1.encodeVector; } });
|
|
25
|
+
Object.defineProperty(exports, "decodeVector", { enumerable: true, get: function () { return vector_1.decodeVector; } });
|
|
26
|
+
Object.defineProperty(exports, "vectorDistance", { enumerable: true, get: function () { return vector_1.vectorDistance; } });
|
|
27
|
+
Object.defineProperty(exports, "isVectorField", { enumerable: true, get: function () { return vector_1.isVectorField; } });
|
|
28
|
+
Object.defineProperty(exports, "AN5_VECTOR_FUNCTIONS", { enumerable: true, get: function () { return vector_1.AN5_VECTOR_FUNCTIONS; } });
|
|
29
|
+
Object.defineProperty(exports, "SQLITE_VEC_FUNCTIONS", { enumerable: true, get: function () { return vector_1.SQLITE_VEC_FUNCTIONS; } });
|
|
23
30
|
var config_1 = require("./config");
|
|
24
31
|
Object.defineProperty(exports, "getLlmConfig", { enumerable: true, get: function () { return config_1.getLlmConfig; } });
|
|
25
32
|
Object.defineProperty(exports, "setLlmConfig", { enumerable: true, get: function () { return config_1.setLlmConfig; } });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Dialect, QueryEngine, TransactionHandle } from '../base/types';
|
|
2
|
+
import { SqliteVectorSupport } from './vector';
|
|
2
3
|
export interface SqliteDriver {
|
|
3
4
|
exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]> | T[];
|
|
4
5
|
executeRaw?(query: string, params?: Record<string, any>): Promise<number> | number;
|
|
@@ -9,9 +10,21 @@ export interface SqliteBrowserConfig {
|
|
|
9
10
|
driver?: SqliteDriver;
|
|
10
11
|
exec?: <T = any>(query: string, params?: Record<string, any>) => Promise<T[]> | T[];
|
|
11
12
|
executeRaw?: (query: string, params?: Record<string, any>) => Promise<number> | number;
|
|
13
|
+
/** Path to the sqlite-vec extension, for WASM builds that allow loading one. */
|
|
14
|
+
sqliteVec?: string;
|
|
15
|
+
/** Pin the vector search strategy instead of probing for one. */
|
|
16
|
+
vectorStrategy?: 'auto' | 'sqlite-vec' | 'udf' | 'sql' | 'memory';
|
|
17
|
+
/** Register a scalar function with the driver, when its API allows it. */
|
|
18
|
+
registerFunction?: (name: string, fn: (...args: any[]) => any) => void;
|
|
12
19
|
}
|
|
13
20
|
export declare class SqliteBrowserEngine implements QueryEngine {
|
|
14
21
|
dialect: Dialect;
|
|
22
|
+
/**
|
|
23
|
+
* A WASM build cannot register a JS callback as an SQL function, so this only
|
|
24
|
+
* reaches the `sql` strategy (json_each in plain SQL) and the in-memory one.
|
|
25
|
+
* A custom `registerFunction` hook unlocks `udf` as well.
|
|
26
|
+
*/
|
|
27
|
+
readonly vectorSupport: SqliteVectorSupport;
|
|
15
28
|
private db;
|
|
16
29
|
private driver;
|
|
17
30
|
private customExec;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SqliteBrowserEngine = void 0;
|
|
4
4
|
exports.createBrowserSqliteAdapter = createBrowserSqliteAdapter;
|
|
5
|
+
const vector_1 = require("./vector");
|
|
5
6
|
// ─── Browser SQLite Engine ──────────────────────────────────────────────────────────
|
|
6
7
|
class SqliteBrowserEngine {
|
|
7
8
|
constructor(config) {
|
|
@@ -10,6 +11,18 @@ class SqliteBrowserEngine {
|
|
|
10
11
|
this.driver = null;
|
|
11
12
|
this.customExec = null;
|
|
12
13
|
this.customExecuteRaw = null;
|
|
14
|
+
this.vectorSupport = new vector_1.SqliteVectorSupport({
|
|
15
|
+
native: () => this.db,
|
|
16
|
+
registerFunction: (name, fn) => {
|
|
17
|
+
const register = config?.registerFunction;
|
|
18
|
+
if (typeof register === 'function')
|
|
19
|
+
return register(name, fn);
|
|
20
|
+
const db = this.db;
|
|
21
|
+
if (db && typeof db.create_function === 'function')
|
|
22
|
+
return db.create_function(name, fn);
|
|
23
|
+
throw new Error('this SQLite build cannot register functions');
|
|
24
|
+
},
|
|
25
|
+
}, { sqliteVec: config?.sqliteVec, vectorStrategy: config?.vectorStrategy });
|
|
13
26
|
if (!config)
|
|
14
27
|
return;
|
|
15
28
|
if (config.exec && typeof config.exec === 'function') {
|
package/dist/sqlite/engine.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import type { An5AdapterConfig, Dialect, QueryEngine, TransactionHandle } from '../base/types';
|
|
2
|
+
import { SqliteVectorSupport } from './vector';
|
|
2
3
|
export declare class SqliteEngine implements QueryEngine {
|
|
3
4
|
dialect: Dialect;
|
|
5
|
+
/** Registers `an5_vec_*` and loads sqlite-vec for in-database vector search. */
|
|
6
|
+
readonly vectorSupport: SqliteVectorSupport;
|
|
4
7
|
private db;
|
|
5
8
|
private readonly filePath;
|
|
6
9
|
constructor(adapterConfig: An5AdapterConfig);
|
|
10
|
+
/** The better-sqlite3 handle, needed for extension loading. */
|
|
11
|
+
native(): any;
|
|
7
12
|
private getDb;
|
|
8
13
|
exec<T = any>(query: string, params?: Record<string, any>): Promise<T[]>;
|
|
9
14
|
executeRaw(query: string, params?: Record<string, any>): Promise<number>;
|
package/dist/sqlite/engine.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SqliteEngine = void 0;
|
|
4
|
+
const vector_1 = require("./vector");
|
|
4
5
|
// ─── SQLite Engine ─────────────────────────────────────────────────────────────────
|
|
5
6
|
let BetterSqlite3 = null;
|
|
6
7
|
try {
|
|
@@ -17,6 +18,14 @@ class SqliteEngine {
|
|
|
17
18
|
.replace(/^sqlite:\/\/\//i, '/')
|
|
18
19
|
.replace(/^sqlite:\/\//i, '')
|
|
19
20
|
.replace(/^sqlite:/i, '');
|
|
21
|
+
this.vectorSupport = new vector_1.SqliteVectorSupport({
|
|
22
|
+
native: () => this.getDb(),
|
|
23
|
+
registerFunction: (name, fn) => this.getDb().function(name, { deterministic: true }, fn),
|
|
24
|
+
}, { sqliteVec: adapterConfig.sqliteVec, vectorStrategy: adapterConfig.vectorStrategy });
|
|
25
|
+
}
|
|
26
|
+
/** The better-sqlite3 handle, needed for extension loading. */
|
|
27
|
+
native() {
|
|
28
|
+
return this.getDb();
|
|
20
29
|
}
|
|
21
30
|
getDb() {
|
|
22
31
|
if (!this.db)
|
|
@@ -42,6 +51,7 @@ class SqliteEngine {
|
|
|
42
51
|
this.db.close();
|
|
43
52
|
this.db = null;
|
|
44
53
|
}
|
|
54
|
+
this.vectorSupport.reset();
|
|
45
55
|
}
|
|
46
56
|
async beginTransaction() {
|
|
47
57
|
const db = this.getDb();
|
package/dist/sqlite/index.d.ts
CHANGED
package/dist/sqlite/index.js
CHANGED
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./engine"), exports);
|
|
18
18
|
__exportStar(require("./browserEngine"), exports);
|
|
19
|
+
__exportStar(require("./vector"), exports);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
export type VectorMetric = 'cosine' | 'euclidean' | 'dot';
|
|
2
|
+
export type SqliteVectorStrategy = 'sqlite-vec' | 'udf' | 'sql' | 'memory';
|
|
3
|
+
export type VectorStrategyPreference = 'auto' | SqliteVectorStrategy;
|
|
4
|
+
/** Scalar functions shipped by the sqlite-vec extension. */
|
|
5
|
+
export declare const SQLITE_VEC_FUNCTIONS: Record<VectorMetric, string>;
|
|
6
|
+
/** Scalar functions the adapter registers itself when the driver allows it. */
|
|
7
|
+
export declare const AN5_VECTOR_FUNCTIONS: Record<VectorMetric, string>;
|
|
8
|
+
/** Read a numeric array out of the shapes a driver can hand back. */
|
|
9
|
+
export declare function parseVector(value: unknown): number[] | null;
|
|
10
|
+
/**
|
|
11
|
+
* Decode a stored vector: a float32 BLOB, a legacy JSON text column, or an
|
|
12
|
+
* array the caller already decoded.
|
|
13
|
+
*/
|
|
14
|
+
export declare function decodeVector(value: unknown): number[] | null;
|
|
15
|
+
/** Encode a vector as the little-endian float32 BLOB `VECTOR(n)` columns store. */
|
|
16
|
+
export declare function encodeVector(values: readonly number[]): Uint8Array;
|
|
17
|
+
/** True when the value still needs encoding on its way into a `VECTOR(n)` column. */
|
|
18
|
+
export declare function needsVectorEncoding(value: unknown): boolean;
|
|
19
|
+
/** True when a generated metadata entry describes a `VECTOR(n)` column. */
|
|
20
|
+
export declare function isVectorField(def: unknown): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Distance between two equal-length vectors, lower is closer. Mirrors the
|
|
23
|
+
* functions registered on the drivers so a search ranks the same way whichever
|
|
24
|
+
* strategy ran.
|
|
25
|
+
*/
|
|
26
|
+
export declare function vectorDistance(a: readonly number[], b: readonly number[], metric: unknown): number | null;
|
|
27
|
+
export interface SqliteVectorQuery {
|
|
28
|
+
sql: string;
|
|
29
|
+
params: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
interface BuildArgs {
|
|
32
|
+
strategy: SqliteVectorStrategy;
|
|
33
|
+
metric: VectorMetric;
|
|
34
|
+
/** Already quoted, e.g. `[documents]`. */
|
|
35
|
+
table: string;
|
|
36
|
+
/** Already quoted column reference. */
|
|
37
|
+
column: string;
|
|
38
|
+
/** The query embedding. */
|
|
39
|
+
vector: number[];
|
|
40
|
+
take: number;
|
|
41
|
+
/** A WHERE tail built by the caller, or empty. */
|
|
42
|
+
tail?: string;
|
|
43
|
+
/** Pre-bound WHERE parameters shared with the caller. */
|
|
44
|
+
params: Record<string, any>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Ranking SQL for one strategy. `sqlite-vec` and `udf` bind the query vector as
|
|
48
|
+
* a float32 BLOB; `sql` binds it as JSON text because `json_each` reads text.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildSqliteVectorQuery(args: BuildArgs): SqliteVectorQuery;
|
|
51
|
+
export interface SqliteVectorCapabilities {
|
|
52
|
+
/** AN5's C extension is loaded; keep its functions instead of driver callbacks. */
|
|
53
|
+
native?: boolean;
|
|
54
|
+
/** `vec_version()` answered, so the sqlite-vec extension is loaded. */
|
|
55
|
+
vec: boolean;
|
|
56
|
+
/** The adapter's own distance functions are registered with the driver. */
|
|
57
|
+
udf: boolean;
|
|
58
|
+
/** `json_each()` is available, which the pure-SQL strategy needs. */
|
|
59
|
+
json1: boolean;
|
|
60
|
+
}
|
|
61
|
+
export interface SqliteVectorOptions {
|
|
62
|
+
/** Path to the sqlite-vec extension binary to load before probing. */
|
|
63
|
+
sqliteVec?: string | undefined;
|
|
64
|
+
/** Pin a strategy instead of probing for the fastest one available. */
|
|
65
|
+
vectorStrategy?: VectorStrategyPreference | undefined;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A driver hook the engine can supply to register the distance functions and
|
|
69
|
+
* load the sqlite-vec extension. Every field is optional: a driver that offers
|
|
70
|
+
* nothing simply reports no capabilities and the search falls back.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* Registers a scalar function with the driver. Implementations that take a
|
|
74
|
+
* determinism flag (better-sqlite3) supply it themselves.
|
|
75
|
+
*/
|
|
76
|
+
export type SqliteVectorFunctionRegistrar = (name: string, fn: (...args: any[]) => any) => void;
|
|
77
|
+
export interface SqliteVectorHooks {
|
|
78
|
+
/** Raw driver handle, used for `loadExtension`. */
|
|
79
|
+
native?: () => any;
|
|
80
|
+
/** Register `name` with the driver's scalar-function API. */
|
|
81
|
+
registerFunction?: SqliteVectorFunctionRegistrar;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the ordered list of strategies to try for this connection.
|
|
85
|
+
*
|
|
86
|
+
* `declaredType` is the column's DDL type: the JSON strategy only reaches rows
|
|
87
|
+
* stored as text, so a `BLOB` column drops it from the order.
|
|
88
|
+
*/
|
|
89
|
+
export declare function planSqliteVectorStrategies(caps: SqliteVectorCapabilities, declaredType: string | null, preference?: VectorStrategyPreference): SqliteVectorStrategy[];
|
|
90
|
+
/**
|
|
91
|
+
* Register `an5_vec_*` on a driver and load sqlite-vec when a path is configured.
|
|
92
|
+
* Safe to call repeatedly; each driver hook is used at most once.
|
|
93
|
+
*/
|
|
94
|
+
export declare class SqliteVectorSupport {
|
|
95
|
+
private readonly hooks;
|
|
96
|
+
private readonly options;
|
|
97
|
+
private caps;
|
|
98
|
+
/**
|
|
99
|
+
* Declared column types and the "any binary row" probe, keyed by column.
|
|
100
|
+
*
|
|
101
|
+
* Both cost a query, and neither changes while a schema is in use. A stale
|
|
102
|
+
* answer is still safe: the probe only decides which strategy to try first, and
|
|
103
|
+
* a strategy that fails falls through to the next one rather than reporting a
|
|
104
|
+
* wrong result.
|
|
105
|
+
*/
|
|
106
|
+
private readonly columnTypes;
|
|
107
|
+
private readonly binaryRows;
|
|
108
|
+
constructor(hooks: SqliteVectorHooks, options?: SqliteVectorOptions);
|
|
109
|
+
capabilities(): Promise<SqliteVectorCapabilities>;
|
|
110
|
+
/** Confirms JSON1 and a usable sqlite-vec/UDF before a query is built for them. */
|
|
111
|
+
probe(exec: (sql: string, params?: Record<string, any>) => Promise<any[]>): Promise<SqliteVectorCapabilities>;
|
|
112
|
+
/** The column's declared DDL type, remembered per column. */
|
|
113
|
+
columnType(exec: (sql: string, params?: Record<string, any>) => Promise<any[]>, table: string, column: string): Promise<string | null>;
|
|
114
|
+
/**
|
|
115
|
+
* Whether any row stores raw bytes, which `json_each` cannot read.
|
|
116
|
+
*
|
|
117
|
+
* Checked only for the `sql` strategy, where a legacy JSON column that has
|
|
118
|
+
* since taken new float32 rows would otherwise rank just the old ones.
|
|
119
|
+
*/
|
|
120
|
+
hasBinaryRows(exec: (sql: string, params?: Record<string, any>) => Promise<any[]>, table: string, column: string, tail: string, params: Record<string, any>): Promise<boolean>;
|
|
121
|
+
reset(): void;
|
|
122
|
+
}
|
|
123
|
+
/** Reads a vector column's declared DDL type, or null when it cannot be found. */
|
|
124
|
+
export declare function readSqliteColumnType(exec: (sql: string, params?: Record<string, any>) => Promise<any[]>, table: string, column: string): Promise<string | null>;
|
|
125
|
+
export interface SqliteVectorSearchArgs {
|
|
126
|
+
exec: (sql: string, params?: Record<string, any>) => Promise<any[]>;
|
|
127
|
+
/** Absent when the engine cannot register functions or load extensions. */
|
|
128
|
+
vectorSupport?: SqliteVectorSupport | null;
|
|
129
|
+
/** Quoted table reference, e.g. `[documents]`. */
|
|
130
|
+
table: string;
|
|
131
|
+
/** Unquoted table name, for `pragma_table_info`. */
|
|
132
|
+
rawTable: string;
|
|
133
|
+
/** Quoted column reference. */
|
|
134
|
+
column: string;
|
|
135
|
+
/** Unquoted column name. */
|
|
136
|
+
rawColumn: string;
|
|
137
|
+
vector: number[];
|
|
138
|
+
metric: VectorMetric;
|
|
139
|
+
take: number;
|
|
140
|
+
/** A WHERE tail (leading space included) or empty. */
|
|
141
|
+
tail?: string | undefined;
|
|
142
|
+
/** Parameter object shared with the caller's WHERE clause. */
|
|
143
|
+
params: Record<string, any>;
|
|
144
|
+
preference?: VectorStrategyPreference | undefined;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Rank a SQLite table by distance inside the database, trying each available
|
|
148
|
+
* strategy in order. Returns null when the connection offers none, so the
|
|
149
|
+
* caller can fall back to scoring in memory.
|
|
150
|
+
*/
|
|
151
|
+
export declare function runSqliteVectorSearch(args: SqliteVectorSearchArgs): Promise<{
|
|
152
|
+
rows: Record<string, any>[];
|
|
153
|
+
strategy: SqliteVectorStrategy;
|
|
154
|
+
} | null>;
|
|
155
|
+
export {};
|