@zauso-ai/capstan-db 0.2.0 → 0.3.0
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/dist/client.d.ts +3 -6
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +206 -27
- package/dist/client.js.map +1 -1
- package/dist/crud.d.ts +14 -0
- package/dist/crud.d.ts.map +1 -1
- package/dist/crud.js +49 -39
- package/dist/crud.js.map +1 -1
- package/dist/dialect.d.ts +25 -0
- package/dist/dialect.d.ts.map +1 -0
- package/dist/dialect.js +208 -0
- package/dist/dialect.js.map +1 -0
- package/dist/embedding.d.ts +63 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/embedding.js +61 -0
- package/dist/embedding.js.map +1 -0
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/migrate.d.ts +44 -23
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +308 -125
- package/dist/migrate.js.map +1 -1
- package/dist/model.d.ts +9 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +13 -0
- package/dist/model.js.map +1 -1
- package/dist/naming.d.ts +37 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +196 -0
- package/dist/naming.js.map +1 -0
- package/dist/runtime.d.ts +51 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +490 -0
- package/dist/runtime.js.map +1 -0
- package/dist/schema.d.ts +2 -27
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +181 -197
- package/dist/schema.js.map +1 -1
- package/dist/search.d.ts +52 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +110 -0
- package/dist/search.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store-memory.d.ts +31 -0
- package/dist/vector-store-memory.d.ts.map +1 -0
- package/dist/vector-store-memory.js +125 -0
- package/dist/vector-store-memory.js.map +1 -0
- package/dist/vector-store-pgvector.d.ts +46 -0
- package/dist/vector-store-pgvector.d.ts.map +1 -0
- package/dist/vector-store-pgvector.js +215 -0
- package/dist/vector-store-pgvector.js.map +1 -0
- package/dist/vector-store-sqlite.d.ts +51 -0
- package/dist/vector-store-sqlite.d.ts.map +1 -0
- package/dist/vector-store-sqlite.js +203 -0
- package/dist/vector-store-sqlite.js.map +1 -0
- package/dist/vector-store.d.ts +79 -0
- package/dist/vector-store.d.ts.map +1 -0
- package/dist/vector-store.js +5 -0
- package/dist/vector-store.js.map +1 -0
- package/dist/write.d.ts +15 -0
- package/dist/write.d.ts.map +1 -0
- package/dist/write.js +156 -0
- package/dist/write.js.map +1 -0
- package/package.json +9 -4
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// SqliteVectorStore — SQLite-backed vector search with JSON array storage
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
//
|
|
5
|
+
// Vectors are persisted as JSON arrays in a `capstan_vectors` table. On
|
|
6
|
+
// search, all matching rows are loaded into memory and scored with the same
|
|
7
|
+
// cosine-distance function used by the in-memory store. This gives durable
|
|
8
|
+
// storage without requiring pgvector, at the cost of O(n) scan time.
|
|
9
|
+
//
|
|
10
|
+
// Suitable for moderate datasets where PostgreSQL is overkill but persistence
|
|
11
|
+
// across restarts is desired.
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
import { cosineDistance } from "./search.js";
|
|
14
|
+
/** Simple whitespace tokeniser with lower-casing and deduplication. */
|
|
15
|
+
function tokenize(text) {
|
|
16
|
+
return [
|
|
17
|
+
...new Set(text
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.split(/\W+/)
|
|
20
|
+
.filter((t) => t.length > 0)),
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
function keywordOverlap(queryTerms, text) {
|
|
24
|
+
if (queryTerms.length === 0)
|
|
25
|
+
return 0;
|
|
26
|
+
const docTokens = new Set(tokenize(text));
|
|
27
|
+
let hits = 0;
|
|
28
|
+
for (const term of queryTerms) {
|
|
29
|
+
if (docTokens.has(term))
|
|
30
|
+
hits++;
|
|
31
|
+
}
|
|
32
|
+
return hits / queryTerms.length;
|
|
33
|
+
}
|
|
34
|
+
function matchesFilter(metadata, filter) {
|
|
35
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
36
|
+
const actual = metadata[key];
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
if (!value.includes(actual))
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
else if (actual !== value) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* SQLite vector store.
|
|
49
|
+
*
|
|
50
|
+
* Stores vectors as JSON text columns and loads them into memory for
|
|
51
|
+
* brute-force cosine search. The trade-off is durability with a simple
|
|
52
|
+
* dependency chain — no native extensions beyond `better-sqlite3`.
|
|
53
|
+
*/
|
|
54
|
+
export class SqliteVectorStore {
|
|
55
|
+
_db;
|
|
56
|
+
_table;
|
|
57
|
+
_dimensions;
|
|
58
|
+
_initialised = false;
|
|
59
|
+
constructor(config) {
|
|
60
|
+
if (!config.connection) {
|
|
61
|
+
throw new Error("SqliteVectorStore requires a `connection` (better-sqlite3 Database instance).");
|
|
62
|
+
}
|
|
63
|
+
this._db = config.connection;
|
|
64
|
+
this._table = config.tableName ?? "capstan_vectors";
|
|
65
|
+
this._dimensions = config.dimensions;
|
|
66
|
+
}
|
|
67
|
+
// -------------------------------------------------------------------------
|
|
68
|
+
// Schema bootstrap
|
|
69
|
+
// -------------------------------------------------------------------------
|
|
70
|
+
/** @internal */
|
|
71
|
+
_ensureSchema() {
|
|
72
|
+
if (this._initialised)
|
|
73
|
+
return;
|
|
74
|
+
this._db.exec(`
|
|
75
|
+
CREATE TABLE IF NOT EXISTS "${this._esc(this._table)}" (
|
|
76
|
+
id TEXT PRIMARY KEY,
|
|
77
|
+
embedding TEXT NOT NULL,
|
|
78
|
+
content TEXT NOT NULL DEFAULT '',
|
|
79
|
+
metadata TEXT NOT NULL DEFAULT '{}'
|
|
80
|
+
)
|
|
81
|
+
`);
|
|
82
|
+
this._initialised = true;
|
|
83
|
+
}
|
|
84
|
+
// -------------------------------------------------------------------------
|
|
85
|
+
// VectorStore implementation
|
|
86
|
+
// -------------------------------------------------------------------------
|
|
87
|
+
async upsert(id, vector, metadata) {
|
|
88
|
+
this._validateDimensions(vector);
|
|
89
|
+
this._ensureSchema();
|
|
90
|
+
const text = typeof metadata?.["text"] === "string" ? metadata["text"] : "";
|
|
91
|
+
const metaJson = JSON.stringify(metadata ?? {});
|
|
92
|
+
this._db
|
|
93
|
+
.prepare(`INSERT INTO "${this._esc(this._table)}" (id, embedding, content, metadata)
|
|
94
|
+
VALUES (?, ?, ?, ?)
|
|
95
|
+
ON CONFLICT(id) DO UPDATE
|
|
96
|
+
SET embedding = excluded.embedding,
|
|
97
|
+
content = excluded.content,
|
|
98
|
+
metadata = excluded.metadata`)
|
|
99
|
+
.run(id, JSON.stringify(vector), text, metaJson);
|
|
100
|
+
}
|
|
101
|
+
async upsertBatch(items) {
|
|
102
|
+
if (items.length === 0)
|
|
103
|
+
return;
|
|
104
|
+
for (const item of items)
|
|
105
|
+
this._validateDimensions(item.vector);
|
|
106
|
+
this._ensureSchema();
|
|
107
|
+
const stmt = this._db.prepare(`INSERT INTO "${this._esc(this._table)}" (id, embedding, content, metadata)
|
|
108
|
+
VALUES (?, ?, ?, ?)
|
|
109
|
+
ON CONFLICT(id) DO UPDATE
|
|
110
|
+
SET embedding = excluded.embedding,
|
|
111
|
+
content = excluded.content,
|
|
112
|
+
metadata = excluded.metadata`);
|
|
113
|
+
for (const item of items) {
|
|
114
|
+
const text = typeof item.metadata?.["text"] === "string" ? item.metadata["text"] : "";
|
|
115
|
+
const metaJson = JSON.stringify(item.metadata ?? {});
|
|
116
|
+
stmt.run(item.id, JSON.stringify(item.vector), text, metaJson);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async search(query, k, filter) {
|
|
120
|
+
if (query.length === 0)
|
|
121
|
+
return [];
|
|
122
|
+
this._ensureSchema();
|
|
123
|
+
const rows = this._loadAll();
|
|
124
|
+
const results = [];
|
|
125
|
+
for (const row of rows) {
|
|
126
|
+
if (filter && !matchesFilter(row.metadata, filter))
|
|
127
|
+
continue;
|
|
128
|
+
if (row.vector.length !== query.length)
|
|
129
|
+
continue;
|
|
130
|
+
const score = 1 - cosineDistance(query, row.vector);
|
|
131
|
+
results.push({ id: row.id, score, metadata: row.metadata });
|
|
132
|
+
}
|
|
133
|
+
results.sort((a, b) => b.score - a.score);
|
|
134
|
+
return results.slice(0, Math.max(0, k));
|
|
135
|
+
}
|
|
136
|
+
async hybridSearch(query, queryVector, k, opts) {
|
|
137
|
+
const vectorWeight = opts?.vectorWeight ?? 0.7;
|
|
138
|
+
const keywordWeight = opts?.keywordWeight ?? 0.3;
|
|
139
|
+
const queryTerms = tokenize(query);
|
|
140
|
+
if (queryTerms.length === 0 && queryVector.length === 0)
|
|
141
|
+
return [];
|
|
142
|
+
this._ensureSchema();
|
|
143
|
+
const rows = this._loadAll();
|
|
144
|
+
const results = [];
|
|
145
|
+
for (const row of rows) {
|
|
146
|
+
if (opts?.filter && !matchesFilter(row.metadata, opts.filter))
|
|
147
|
+
continue;
|
|
148
|
+
const vectorScore = queryVector.length > 0 && row.vector.length === queryVector.length
|
|
149
|
+
? 1 - cosineDistance(queryVector, row.vector)
|
|
150
|
+
: 0;
|
|
151
|
+
const kwScore = keywordOverlap(queryTerms, row.content);
|
|
152
|
+
results.push({
|
|
153
|
+
id: row.id,
|
|
154
|
+
score: vectorWeight * vectorScore + keywordWeight * kwScore,
|
|
155
|
+
metadata: row.metadata,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
results.sort((a, b) => b.score - a.score);
|
|
159
|
+
return results.slice(0, Math.max(0, k));
|
|
160
|
+
}
|
|
161
|
+
async remove(id) {
|
|
162
|
+
this._ensureSchema();
|
|
163
|
+
const result = this._db
|
|
164
|
+
.prepare(`DELETE FROM "${this._esc(this._table)}" WHERE id = ?`)
|
|
165
|
+
.run(id);
|
|
166
|
+
return result.changes > 0;
|
|
167
|
+
}
|
|
168
|
+
async count() {
|
|
169
|
+
this._ensureSchema();
|
|
170
|
+
const row = this._db
|
|
171
|
+
.prepare(`SELECT COUNT(*) AS count FROM "${this._esc(this._table)}"`)
|
|
172
|
+
.get();
|
|
173
|
+
return Number(row?.["count"] ?? 0);
|
|
174
|
+
}
|
|
175
|
+
// -------------------------------------------------------------------------
|
|
176
|
+
// Internal helpers
|
|
177
|
+
// -------------------------------------------------------------------------
|
|
178
|
+
_validateDimensions(vector) {
|
|
179
|
+
if (vector.length === 0) {
|
|
180
|
+
throw new Error("Cannot store a zero-length vector.");
|
|
181
|
+
}
|
|
182
|
+
if (this._dimensions !== undefined && vector.length !== this._dimensions) {
|
|
183
|
+
throw new Error(`Dimension mismatch: expected ${this._dimensions}, got ${vector.length}.`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** Load all stored rows, parsing JSON columns. */
|
|
187
|
+
_loadAll() {
|
|
188
|
+
const rawRows = this._db
|
|
189
|
+
.prepare(`SELECT id, embedding, content, metadata FROM "${this._esc(this._table)}"`)
|
|
190
|
+
.all();
|
|
191
|
+
return rawRows.map((row) => ({
|
|
192
|
+
id: String(row["id"]),
|
|
193
|
+
vector: JSON.parse(String(row["embedding"])),
|
|
194
|
+
content: String(row["content"] ?? ""),
|
|
195
|
+
metadata: JSON.parse(String(row["metadata"] ?? "{}")),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
/** Escape a SQL identifier (double-quote style). */
|
|
199
|
+
_esc(identifier) {
|
|
200
|
+
return identifier.replace(/"/g, '""');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=vector-store-sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store-sqlite.js","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store-sqlite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter condition for vector search. Each key is a metadata field name and
|
|
3
|
+
* the value is either a literal (exact match) or an array of allowed values.
|
|
4
|
+
*/
|
|
5
|
+
export type VectorFilter = Record<string, unknown>;
|
|
6
|
+
/** A single result returned from a vector search operation. */
|
|
7
|
+
export interface VectorSearchResult {
|
|
8
|
+
/** Identifier of the stored vector. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Similarity score in [0, 1] where 1 is identical. */
|
|
11
|
+
score: number;
|
|
12
|
+
/** Metadata that was stored alongside the vector. */
|
|
13
|
+
metadata?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
/** Options for hybrid (keyword + vector) search. */
|
|
16
|
+
export interface VectorHybridSearchOptions {
|
|
17
|
+
/** Weight for the keyword component (0-1). @default 0.3 */
|
|
18
|
+
keywordWeight?: number;
|
|
19
|
+
/** Weight for the vector component (0-1). @default 0.7 */
|
|
20
|
+
vectorWeight?: number;
|
|
21
|
+
/** Optional metadata filter applied before scoring. */
|
|
22
|
+
filter?: VectorFilter;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Pluggable vector storage and similarity search backend.
|
|
26
|
+
*
|
|
27
|
+
* Implementations range from a simple in-memory map (development) through
|
|
28
|
+
* SQLite-backed persistence up to full pgvector-powered ANN search.
|
|
29
|
+
*/
|
|
30
|
+
export interface VectorStore {
|
|
31
|
+
/** Insert or update a vector with its ID and optional metadata. */
|
|
32
|
+
upsert(id: string, vector: number[], metadata?: Record<string, unknown>): Promise<void>;
|
|
33
|
+
/** Batch upsert for efficiency. */
|
|
34
|
+
upsertBatch(items: ReadonlyArray<{
|
|
35
|
+
id: string;
|
|
36
|
+
vector: number[];
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
}>): Promise<void>;
|
|
39
|
+
/** Find k nearest neighbours by vector similarity. */
|
|
40
|
+
search(query: number[], k: number, filter?: VectorFilter): Promise<VectorSearchResult[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Hybrid search combining vector similarity with keyword text matching.
|
|
43
|
+
*
|
|
44
|
+
* The `query` string is used for keyword scoring while `queryVector` drives
|
|
45
|
+
* the vector similarity component.
|
|
46
|
+
*/
|
|
47
|
+
hybridSearch(query: string, queryVector: number[], k: number, opts?: VectorHybridSearchOptions): Promise<VectorSearchResult[]>;
|
|
48
|
+
/** Remove a vector by ID. Returns `true` if the entry existed. */
|
|
49
|
+
remove(id: string): Promise<boolean>;
|
|
50
|
+
/** Return the number of stored vectors. */
|
|
51
|
+
count(): Promise<number>;
|
|
52
|
+
}
|
|
53
|
+
/** Configuration accepted by the {@link createVectorStore} factory. */
|
|
54
|
+
export interface VectorStoreConfig {
|
|
55
|
+
/** Backend provider to use. */
|
|
56
|
+
provider: "memory" | "pgvector" | "sqlite";
|
|
57
|
+
/**
|
|
58
|
+
* Number of dimensions each vector contains. Required for pgvector so that
|
|
59
|
+
* the column can be sized correctly; optional for memory and SQLite stores.
|
|
60
|
+
*/
|
|
61
|
+
dimensions?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Name of the database table used for persistence.
|
|
64
|
+
* @default "capstan_vectors"
|
|
65
|
+
*/
|
|
66
|
+
tableName?: string;
|
|
67
|
+
/**
|
|
68
|
+
* A raw query function used by the pgvector and SQLite adapters.
|
|
69
|
+
*
|
|
70
|
+
* For pgvector this should be a function that accepts a parameterised SQL
|
|
71
|
+
* string with `$1`, `$2`, etc. placeholders and returns an array of row
|
|
72
|
+
* objects.
|
|
73
|
+
*
|
|
74
|
+
* For SQLite this should be a synchronous `better-sqlite3` `Database`
|
|
75
|
+
* instance (it will be accessed via `.prepare().all()` / `.run()`).
|
|
76
|
+
*/
|
|
77
|
+
connection?: unknown;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=vector-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store.d.ts","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEnD,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,oDAAoD;AACpD,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExF,mCAAmC;IACnC,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvH,sDAAsD;IACtD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAEzF;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAE/H,mEAAmE;IACnE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAErC,2CAA2C;IAC3C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1B;AAED,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,+BAA+B;IAC/B,QAAQ,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;IAE3C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// VectorStore — adapter interface for pluggable vector search backends
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=vector-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store.js","sourceRoot":"","sources":["../../../.claude/worktrees/agent-a1ae6f0b/packages/db/src/vector-store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,uEAAuE;AACvE,8EAA8E"}
|
package/dist/write.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EmbeddingConfig } from "./embedding.js";
|
|
2
|
+
import type { ModelDefinition } from "./types.js";
|
|
3
|
+
export interface PrepareWriteOptions {
|
|
4
|
+
now?: Date;
|
|
5
|
+
embeddings?: Array<EmbeddingConfig & {
|
|
6
|
+
modelName?: string;
|
|
7
|
+
}> | (EmbeddingConfig & {
|
|
8
|
+
modelName?: string;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
type RecordInput = Record<string, unknown>;
|
|
12
|
+
export declare function prepareCreateData(model: ModelDefinition, input: RecordInput, options?: PrepareWriteOptions): Promise<RecordInput>;
|
|
13
|
+
export declare function prepareUpdateData(model: ModelDefinition, input: RecordInput, options?: PrepareWriteOptions): Promise<RecordInput>;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=write.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,KAAK,EAAmB,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,IAAI,CAAC;IACX,UAAU,CAAC,EAAE,KAAK,CAAC,eAAe,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,CAAC,eAAe,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3G;AAED,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA4L3C,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,WAAW,CAAC,CAEtB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,WAAW,CAAC,CAEtB"}
|
package/dist/write.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { cloneDefaultValue } from "./naming.js";
|
|
2
|
+
function assertKnownFields(model, input) {
|
|
3
|
+
for (const key of Object.keys(input)) {
|
|
4
|
+
if (!(key in model.fields)) {
|
|
5
|
+
throw new Error(`Unknown field "${key}" for model "${model.name}".`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function validateFieldValue(model, fieldName, field, value) {
|
|
10
|
+
if (value === undefined)
|
|
11
|
+
return;
|
|
12
|
+
if (value === null) {
|
|
13
|
+
if (field.required || field.updatedAt || field.autoId) {
|
|
14
|
+
throw new Error(`Field "${model.name}.${fieldName}" cannot be null.`);
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
switch (field.type) {
|
|
19
|
+
case "string":
|
|
20
|
+
case "text":
|
|
21
|
+
if (typeof value !== "string") {
|
|
22
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a string.`);
|
|
23
|
+
}
|
|
24
|
+
if (field.min !== undefined && value.length < field.min) {
|
|
25
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at least ${field.min} characters.`);
|
|
26
|
+
}
|
|
27
|
+
if (field.max !== undefined && value.length > field.max) {
|
|
28
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at most ${field.max} characters.`);
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
case "date":
|
|
32
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
33
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a YYYY-MM-DD string.`);
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
case "datetime":
|
|
37
|
+
if (typeof value !== "string" || Number.isNaN(Date.parse(value))) {
|
|
38
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a valid datetime string.`);
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
case "integer":
|
|
42
|
+
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
43
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be an integer.`);
|
|
44
|
+
}
|
|
45
|
+
if (field.min !== undefined && value < field.min) {
|
|
46
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at least ${field.min}.`);
|
|
47
|
+
}
|
|
48
|
+
if (field.max !== undefined && value > field.max) {
|
|
49
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at most ${field.max}.`);
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "number":
|
|
53
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
54
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a number.`);
|
|
55
|
+
}
|
|
56
|
+
if (field.min !== undefined && value < field.min) {
|
|
57
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at least ${field.min}.`);
|
|
58
|
+
}
|
|
59
|
+
if (field.max !== undefined && value > field.max) {
|
|
60
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be at most ${field.max}.`);
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case "boolean":
|
|
64
|
+
if (typeof value !== "boolean") {
|
|
65
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a boolean.`);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case "vector":
|
|
69
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "number" || Number.isNaN(entry))) {
|
|
70
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be a numeric vector.`);
|
|
71
|
+
}
|
|
72
|
+
if (field.dimensions !== undefined && value.length !== field.dimensions) {
|
|
73
|
+
throw new Error(`Field "${model.name}.${fieldName}" must contain exactly ${field.dimensions} dimensions.`);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case "json":
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
if (field.enum && !field.enum.includes(value)) {
|
|
80
|
+
throw new Error(`Field "${model.name}.${fieldName}" must be one of: ${field.enum.join(", ")}.`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function validateRequiredFields(model, payload) {
|
|
84
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
85
|
+
if ((field.required || field.updatedAt || field.autoId) && payload[fieldName] === undefined) {
|
|
86
|
+
throw new Error(`Missing required field "${model.name}.${fieldName}".`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function nowValue(field, now) {
|
|
91
|
+
switch (field.type) {
|
|
92
|
+
case "date":
|
|
93
|
+
return now.toISOString().slice(0, 10);
|
|
94
|
+
case "datetime":
|
|
95
|
+
return now.toISOString();
|
|
96
|
+
default:
|
|
97
|
+
return now.toISOString();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function embeddingConfigsForModel(model, embeddings) {
|
|
101
|
+
const list = embeddings === undefined ? [] : Array.isArray(embeddings) ? embeddings : [embeddings];
|
|
102
|
+
return list.filter((config) => config.modelName === undefined || config.modelName === model.name);
|
|
103
|
+
}
|
|
104
|
+
async function applyEmbeddings(model, payload, embeddings) {
|
|
105
|
+
for (const config of embeddingConfigsForModel(model, embeddings)) {
|
|
106
|
+
const sourceValue = payload[config.sourceField];
|
|
107
|
+
if (sourceValue === undefined || sourceValue === null)
|
|
108
|
+
continue;
|
|
109
|
+
if (typeof sourceValue !== "string") {
|
|
110
|
+
throw new Error(`Embedding source field "${config.sourceField}" on model "${model.name}" must resolve to a string.`);
|
|
111
|
+
}
|
|
112
|
+
const vectors = await config.adapter.embed([sourceValue]);
|
|
113
|
+
const vector = vectors[0];
|
|
114
|
+
if (!vector) {
|
|
115
|
+
throw new Error(`Embedding adapter for model "${model.name}" returned no embedding for "${config.sourceField}".`);
|
|
116
|
+
}
|
|
117
|
+
const vectorField = model.fields[config.vectorField];
|
|
118
|
+
if (vectorField?.dimensions !== undefined && vector.length !== vectorField.dimensions) {
|
|
119
|
+
throw new Error(`Embedding dimensions mismatch for "${model.name}.${config.vectorField}": expected ${vectorField.dimensions}, received ${vector.length}.`);
|
|
120
|
+
}
|
|
121
|
+
payload[config.vectorField] = vector;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function prepareWrite(mode, model, input, options) {
|
|
125
|
+
const now = options?.now ?? new Date();
|
|
126
|
+
const payload = { ...input };
|
|
127
|
+
assertKnownFields(model, payload);
|
|
128
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
129
|
+
if (mode === "create") {
|
|
130
|
+
if (field.autoId && payload[fieldName] === undefined) {
|
|
131
|
+
payload[fieldName] = globalThis.crypto.randomUUID();
|
|
132
|
+
}
|
|
133
|
+
if (payload[fieldName] === undefined && field.default !== undefined) {
|
|
134
|
+
payload[fieldName] = field.default === "now" ? nowValue(field, now) : cloneDefaultValue(field.default);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (field.updatedAt) {
|
|
138
|
+
payload[fieldName] = nowValue(field, now);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
await applyEmbeddings(model, payload, options?.embeddings);
|
|
142
|
+
if (mode === "create") {
|
|
143
|
+
validateRequiredFields(model, payload);
|
|
144
|
+
}
|
|
145
|
+
for (const [fieldName, field] of Object.entries(model.fields)) {
|
|
146
|
+
validateFieldValue(model, fieldName, field, payload[fieldName]);
|
|
147
|
+
}
|
|
148
|
+
return payload;
|
|
149
|
+
}
|
|
150
|
+
export async function prepareCreateData(model, input, options) {
|
|
151
|
+
return prepareWrite("create", model, input, options);
|
|
152
|
+
}
|
|
153
|
+
export async function prepareUpdateData(model, input, options) {
|
|
154
|
+
return prepareWrite("update", model, input, options);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../src/write.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauso-ai/capstan-db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -12,11 +12,13 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"build": "tsc -p tsconfig.json",
|
|
15
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"clean": "rm -rf dist"
|
|
16
17
|
},
|
|
17
18
|
"peerDependencies": {
|
|
18
|
-
"drizzle-orm": "
|
|
19
|
-
"better-sqlite3": "
|
|
19
|
+
"drizzle-orm": ">=0.44.0",
|
|
20
|
+
"better-sqlite3": ">=9.0.0",
|
|
21
|
+
"@libsql/client": ">=0.15.0",
|
|
20
22
|
"pg": "^8.0.0",
|
|
21
23
|
"mysql2": "^3.0.0"
|
|
22
24
|
},
|
|
@@ -27,6 +29,9 @@
|
|
|
27
29
|
"better-sqlite3": {
|
|
28
30
|
"optional": true
|
|
29
31
|
},
|
|
32
|
+
"@libsql/client": {
|
|
33
|
+
"optional": true
|
|
34
|
+
},
|
|
30
35
|
"pg": {
|
|
31
36
|
"optional": true
|
|
32
37
|
},
|