@an5/adapters 0.2.6 → 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.
@@ -0,0 +1,104 @@
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 {
14
+ NBaseVectorClient,
15
+ NBaseError,
16
+ createNBaseVectorClient,
17
+ type NBaseClientConfig,
18
+ type NBaseVector,
19
+ type NBaseSearchOptions,
20
+ type NBaseSearchResult,
21
+ type NBaseStats,
22
+ } from './client';
23
+
24
+ export interface NBaseAdapterConfig extends NBaseClientConfig {
25
+ url: string;
26
+ /**
27
+ * Metadata key that holds the relational row id. `an5Id` by default, which
28
+ * is what `indexTableVectors` writes.
29
+ */
30
+ idField?: string;
31
+ /** Metadata key holding the model name, used to keep collections apart. */
32
+ modelField?: string;
33
+ /** Force the search method instead of letting NBase choose. */
34
+ method?: 'hnsw' | 'clustered';
35
+ }
36
+
37
+ /** Matches `nbase:`, `nbase://` and `nbase=http(s)://` at the start of a value. */
38
+ const NBASE_PREFIX = /^nbase:(?:\/\/)?/i;
39
+
40
+ /** True when the whole connection string points at NBase. */
41
+ export function isNBaseConnectionString(connectionString: string): boolean {
42
+ return NBASE_PREFIX.test(connectionString.trim());
43
+ }
44
+
45
+ /** Builds options from a URL and an optional query string. */
46
+ function buildOptions(url: string, query?: string): NBaseAdapterConfig {
47
+ const params = new URLSearchParams(query ?? '');
48
+ const trimmed = url.trim().replace(/\/+$/, '');
49
+ // `nbase://host:port` is shorthand for the same host over HTTP; an explicit
50
+ // scheme is used as-is so https deployments work.
51
+ const withScheme = !trimmed
52
+ ? 'http://localhost:1307'
53
+ : /^[a-z]+:\/\//i.test(trimmed)
54
+ ? trimmed
55
+ : `http://${trimmed}`;
56
+ return {
57
+ url: withScheme,
58
+ ...(params.get('token') ? { token: params.get('token') as string } : {}),
59
+ ...(params.get('timeoutMs') ? { timeoutMs: Number(params.get('timeoutMs')) } : {}),
60
+ ...(params.get('idField') ? { idField: params.get('idField') as string } : {}),
61
+ ...(params.get('modelField') ? { modelField: params.get('modelField') as string } : {}),
62
+ ...(params.get('method') ? { method: params.get('method') as 'hnsw' | 'clustered' } : {}),
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Parses an NBase connection string.
68
+ *
69
+ * Accepts `nbase:http://host:port`, `nbase://host:port` and
70
+ * `nbase:host:port`, with optional `?token=…&timeoutMs=…` options.
71
+ */
72
+ export function parseNBaseConnectionString(connectionString: string): NBaseAdapterConfig {
73
+ const raw = connectionString.trim();
74
+ if (!isNBaseConnectionString(raw)) {
75
+ throw new Error(`Not an NBase connection string: ${raw}`);
76
+ }
77
+
78
+ const [url, query] = raw.replace(NBASE_PREFIX, '').split('?');
79
+ return buildOptions(url ?? '', query);
80
+ }
81
+
82
+ /** Builds the vector id used to link a NBase vector back to a relational row. */
83
+ export function buildVectorId(model: string, id: string | number): string {
84
+ return `${model}:${id}`;
85
+ }
86
+
87
+ /** Splits a vector id produced by {@link buildVectorId}. */
88
+ export function parseVectorId(vectorId: string | number): { model: string; id: string } {
89
+ const raw = String(vectorId);
90
+ const separator = raw.indexOf(':');
91
+ if (separator === -1) return { model: '', id: raw };
92
+ return { model: raw.slice(0, separator), id: raw.slice(separator + 1) };
93
+ }
94
+
95
+ export function createNBaseClient(config: NBaseAdapterConfig | string): {
96
+ client: NBaseVectorClient;
97
+ options: NBaseAdapterConfig;
98
+ } {
99
+ const options: NBaseAdapterConfig = typeof config === 'string' ? parseNBaseConnectionString(config) : config;
100
+ return { client: createNBaseVectorClient(options), options };
101
+ }
102
+
103
+ export { NBaseVectorClient, NBaseError, createNBaseVectorClient };
104
+ export type { NBaseClientConfig, NBaseVector, NBaseSearchOptions, NBaseSearchResult, NBaseStats };