viyv-db-postgres 0.1.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/LICENSE +21 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +15 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +9 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +13 -0
- package/dist/db.js.map +1 -0
- package/dist/error-mapper.d.ts +2 -0
- package/dist/error-mapper.d.ts.map +1 -0
- package/dist/error-mapper.js +24 -0
- package/dist/error-mapper.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/logical/cte-builder.d.ts +57 -0
- package/dist/logical/cte-builder.d.ts.map +1 -0
- package/dist/logical/cte-builder.js +167 -0
- package/dist/logical/cte-builder.js.map +1 -0
- package/dist/logical/data-ops.d.ts +19 -0
- package/dist/logical/data-ops.d.ts.map +1 -0
- package/dist/logical/data-ops.js +124 -0
- package/dist/logical/data-ops.js.map +1 -0
- package/dist/logical/embedding-ops.d.ts +24 -0
- package/dist/logical/embedding-ops.d.ts.map +1 -0
- package/dist/logical/embedding-ops.js +94 -0
- package/dist/logical/embedding-ops.js.map +1 -0
- package/dist/logical/migration-ops.d.ts +10 -0
- package/dist/logical/migration-ops.d.ts.map +1 -0
- package/dist/logical/migration-ops.js +201 -0
- package/dist/logical/migration-ops.js.map +1 -0
- package/dist/logical/query-ops.d.ts +18 -0
- package/dist/logical/query-ops.d.ts.map +1 -0
- package/dist/logical/query-ops.js +193 -0
- package/dist/logical/query-ops.js.map +1 -0
- package/dist/logical/registry.d.ts +27 -0
- package/dist/logical/registry.d.ts.map +1 -0
- package/dist/logical/registry.js +79 -0
- package/dist/logical/registry.js.map +1 -0
- package/dist/logical/schema-ops.d.ts +7 -0
- package/dist/logical/schema-ops.d.ts.map +1 -0
- package/dist/logical/schema-ops.js +311 -0
- package/dist/logical/schema-ops.js.map +1 -0
- package/dist/logical/sql-parser.d.ts +11 -0
- package/dist/logical/sql-parser.d.ts.map +1 -0
- package/dist/logical/sql-parser.js +37 -0
- package/dist/logical/sql-parser.js.map +1 -0
- package/dist/logical/sql-table-refs.d.ts +18 -0
- package/dist/logical/sql-table-refs.d.ts.map +1 -0
- package/dist/logical/sql-table-refs.js +203 -0
- package/dist/logical/sql-table-refs.js.map +1 -0
- package/dist/logical/sql-tokenizer.d.ts +20 -0
- package/dist/logical/sql-tokenizer.d.ts.map +1 -0
- package/dist/logical/sql-tokenizer.js +249 -0
- package/dist/logical/sql-tokenizer.js.map +1 -0
- package/dist/logical/type-utils.d.ts +11 -0
- package/dist/logical/type-utils.d.ts.map +1 -0
- package/dist/logical/type-utils.js +42 -0
- package/dist/logical/type-utils.js.map +1 -0
- package/dist/logical/where-builder.d.ts +6 -0
- package/dist/logical/where-builder.d.ts.map +1 -0
- package/dist/logical/where-builder.js +20 -0
- package/dist/logical/where-builder.js.map +1 -0
- package/dist/schema.d.ts +926 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +78 -0
- package/dist/schema.js.map +1 -0
- package/dist/services/postgres-service.d.ts +40 -0
- package/dist/services/postgres-service.d.ts.map +1 -0
- package/dist/services/postgres-service.js +479 -0
- package/dist/services/postgres-service.js.map +1 -0
- package/dist/services/semantic-search-service.d.ts +16 -0
- package/dist/services/semantic-search-service.d.ts.map +1 -0
- package/dist/services/semantic-search-service.js +94 -0
- package/dist/services/semantic-search-service.js.map +1 -0
- package/dist/system-migrations/001_composite_pk.d.ts +4 -0
- package/dist/system-migrations/001_composite_pk.d.ts.map +1 -0
- package/dist/system-migrations/001_composite_pk.js +23 -0
- package/dist/system-migrations/001_composite_pk.js.map +1 -0
- package/dist/system-migrations/002_schema_log_index.d.ts +4 -0
- package/dist/system-migrations/002_schema_log_index.d.ts.map +1 -0
- package/dist/system-migrations/002_schema_log_index.js +13 -0
- package/dist/system-migrations/002_schema_log_index.js.map +1 -0
- package/dist/system-migrations/index.d.ts +9 -0
- package/dist/system-migrations/index.d.ts.map +1 -0
- package/dist/system-migrations/index.js +9 -0
- package/dist/system-migrations/index.js.map +1 -0
- package/dist/system-migrations/types.d.ts +18 -0
- package/dist/system-migrations/types.d.ts.map +1 -0
- package/dist/system-migrations/types.js +28 -0
- package/dist/system-migrations/types.js.map +1 -0
- package/dist/system-migrations.d.ts +25 -0
- package/dist/system-migrations.d.ts.map +1 -0
- package/dist/system-migrations.js +66 -0
- package/dist/system-migrations.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { IEmbeddingProvider, ISemanticSearchService, SemanticSearchOptions, SemanticSearchResult } from 'viyv-db-core';
|
|
2
|
+
import type { DrizzleDb } from '../db.js';
|
|
3
|
+
import type { LogicalTableRegistry } from '../logical/registry.js';
|
|
4
|
+
export declare class PostgresSemanticSearchService implements ISemanticSearchService {
|
|
5
|
+
private readonly db;
|
|
6
|
+
private readonly registry;
|
|
7
|
+
private readonly embeddingProvider;
|
|
8
|
+
private readonly tenantId;
|
|
9
|
+
private readonly dimensions;
|
|
10
|
+
constructor(db: DrizzleDb, registry: LogicalTableRegistry, embeddingProvider: IEmbeddingProvider, tenantId: string, dimensions: number);
|
|
11
|
+
initialize(): Promise<void>;
|
|
12
|
+
semanticSearch(options: SemanticSearchOptions): Promise<SemanticSearchResult[]>;
|
|
13
|
+
embedRows(table: string, rowIds: string[]): Promise<void>;
|
|
14
|
+
deleteEmbeddings(rowIds: string[]): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=semantic-search-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-service.d.ts","sourceRoot":"","sources":["../../src/services/semantic-search-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAO1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAGnE,qBAAa,6BAA8B,YAAW,sBAAsB;IAE1E,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAJV,EAAE,EAAE,SAAS,EACb,QAAQ,EAAE,oBAAoB,EAC9B,iBAAiB,EAAE,kBAAkB,EACrC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM;IAG9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAoC/E,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDzD,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAGvD"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { and, eq, inArray } from 'drizzle-orm';
|
|
2
|
+
import { buildEmbeddingText } from 'viyv-db-core';
|
|
3
|
+
import { deleteEmbeddingsByRowIds, initializeEmbeddingTable, searchSimilar, storeEmbeddings, } from '../logical/embedding-ops.js';
|
|
4
|
+
import { logicalRows, logicalTables } from '../schema.js';
|
|
5
|
+
export class PostgresSemanticSearchService {
|
|
6
|
+
db;
|
|
7
|
+
registry;
|
|
8
|
+
embeddingProvider;
|
|
9
|
+
tenantId;
|
|
10
|
+
dimensions;
|
|
11
|
+
constructor(db, registry, embeddingProvider, tenantId, dimensions) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
this.registry = registry;
|
|
14
|
+
this.embeddingProvider = embeddingProvider;
|
|
15
|
+
this.tenantId = tenantId;
|
|
16
|
+
this.dimensions = dimensions;
|
|
17
|
+
}
|
|
18
|
+
async initialize() {
|
|
19
|
+
await initializeEmbeddingTable(this.db, this.dimensions);
|
|
20
|
+
}
|
|
21
|
+
async semanticSearch(options) {
|
|
22
|
+
const limit = options.limit ?? 10;
|
|
23
|
+
const threshold = options.threshold ?? 0.0;
|
|
24
|
+
await this.registry.ensureLoaded(this.db, this.tenantId);
|
|
25
|
+
// Resolve table IDs if table names are specified
|
|
26
|
+
let tableIds;
|
|
27
|
+
if (options.tables && options.tables.length > 0) {
|
|
28
|
+
tableIds = [];
|
|
29
|
+
for (const name of options.tables) {
|
|
30
|
+
const id = this.registry.getTableId(name);
|
|
31
|
+
if (id)
|
|
32
|
+
tableIds.push(id);
|
|
33
|
+
}
|
|
34
|
+
if (tableIds.length === 0)
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
// Embed the query text
|
|
38
|
+
const queryPrefix = `query: ${options.query}`;
|
|
39
|
+
const [queryVector] = await this.embeddingProvider.embed([queryPrefix]);
|
|
40
|
+
const results = await searchSimilar(this.db, this.tenantId, queryVector, {
|
|
41
|
+
tableIds,
|
|
42
|
+
limit,
|
|
43
|
+
threshold,
|
|
44
|
+
});
|
|
45
|
+
return results.map((r) => ({
|
|
46
|
+
tableName: r.tableName,
|
|
47
|
+
tablePurpose: r.tablePurpose,
|
|
48
|
+
row: r.data,
|
|
49
|
+
similarity: r.similarity,
|
|
50
|
+
rowId: r.rowId,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
async embedRows(table, rowIds) {
|
|
54
|
+
if (rowIds.length === 0)
|
|
55
|
+
return;
|
|
56
|
+
await this.registry.ensureLoaded(this.db, this.tenantId);
|
|
57
|
+
const entry = this.registry.getTable(table);
|
|
58
|
+
if (!entry)
|
|
59
|
+
return;
|
|
60
|
+
// Get table metadata for purpose
|
|
61
|
+
const [tableRow] = await this.db
|
|
62
|
+
.select({ purpose: logicalTables.purpose })
|
|
63
|
+
.from(logicalTables)
|
|
64
|
+
.where(eq(logicalTables.id, entry.id));
|
|
65
|
+
const purpose = tableRow?.purpose ?? null;
|
|
66
|
+
// Fetch the actual row data
|
|
67
|
+
const rows = await this.db
|
|
68
|
+
.select({ id: logicalRows.id, data: logicalRows.data })
|
|
69
|
+
.from(logicalRows)
|
|
70
|
+
.where(and(eq(logicalRows.tenantId, this.tenantId), eq(logicalRows.tableId, entry.id), inArray(logicalRows.id, rowIds)));
|
|
71
|
+
if (rows.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
// Build embedding texts
|
|
74
|
+
const columns = entry.columns.map((c) => ({ name: c.name, description: c.description }));
|
|
75
|
+
const texts = rows.map((r) => {
|
|
76
|
+
const data = r.data;
|
|
77
|
+
return `passage: ${buildEmbeddingText(table, purpose, columns, data)}`;
|
|
78
|
+
});
|
|
79
|
+
// Generate embeddings
|
|
80
|
+
const embeddings = await this.embeddingProvider.embed(texts);
|
|
81
|
+
// Store embeddings
|
|
82
|
+
const entries = rows.map((r, i) => ({
|
|
83
|
+
rowId: r.id,
|
|
84
|
+
tableId: entry.id,
|
|
85
|
+
embedding: embeddings[i],
|
|
86
|
+
embeddingText: texts[i],
|
|
87
|
+
}));
|
|
88
|
+
await storeEmbeddings(this.db, this.tenantId, entries);
|
|
89
|
+
}
|
|
90
|
+
async deleteEmbeddings(rowIds) {
|
|
91
|
+
await deleteEmbeddingsByRowIds(this.db, this.tenantId, rowIds);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=semantic-search-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-search-service.js","sourceRoot":"","sources":["../../src/services/semantic-search-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"001_composite_pk.d.ts","sourceRoot":"","sources":["../../src/system-migrations/001_composite_pk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,0FAA0F;AAC1F,eAAO,MAAM,SAAS,EAAE,eAmBvB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
/** Convert _viyv_logical_rows PK from (id) to (id, tenant_id) for partitioning support */
|
|
3
|
+
export const migration = {
|
|
4
|
+
version: '001',
|
|
5
|
+
description: 'Composite PK (id, tenant_id) on _viyv_logical_rows',
|
|
6
|
+
up: async (tx) => {
|
|
7
|
+
await tx.execute(sql `
|
|
8
|
+
DO $$
|
|
9
|
+
BEGIN
|
|
10
|
+
IF EXISTS (
|
|
11
|
+
SELECT 1 FROM pg_constraint
|
|
12
|
+
WHERE conrelid = '_viyv_logical_rows'::regclass
|
|
13
|
+
AND contype = 'p'
|
|
14
|
+
AND array_length(conkey, 1) = 1
|
|
15
|
+
) THEN
|
|
16
|
+
ALTER TABLE _viyv_logical_rows DROP CONSTRAINT _viyv_logical_rows_pkey;
|
|
17
|
+
ALTER TABLE _viyv_logical_rows ADD PRIMARY KEY (id, tenant_id);
|
|
18
|
+
END IF;
|
|
19
|
+
END $$
|
|
20
|
+
`);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=001_composite_pk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"001_composite_pk.js","sourceRoot":"","sources":["../../src/system-migrations/001_composite_pk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,SAAS,GAAoB;IACzC,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,oDAAoD;IACjE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAChB,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;;;;;;;;;;;GAanB,CAAC,CAAC;IACJ,CAAC;CACD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"002_schema_log_index.d.ts","sourceRoot":"","sources":["../../src/system-migrations/002_schema_log_index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,kFAAkF;AAClF,eAAO,MAAM,SAAS,EAAE,eASvB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
/** Add descending index on _viyv_schema_log.applied_at for time-series queries */
|
|
3
|
+
export const migration = {
|
|
4
|
+
version: '002',
|
|
5
|
+
description: 'Index on _viyv_schema_log(applied_at DESC)',
|
|
6
|
+
up: async (tx) => {
|
|
7
|
+
await tx.execute(sql `
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_schema_log_applied_at
|
|
9
|
+
ON _viyv_schema_log (applied_at DESC)
|
|
10
|
+
`);
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=002_schema_log_index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"002_schema_log_index.js","sourceRoot":"","sources":["../../src/system-migrations/002_schema_log_index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,kFAAkF;AAClF,MAAM,CAAC,MAAM,SAAS,GAAoB;IACzC,OAAO,EAAE,KAAK;IACd,WAAW,EAAE,4CAA4C;IACzD,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;QAChB,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;GAGnB,CAAC,CAAC;IACJ,CAAC;CACD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { runSystemMigrations } from './types.js';
|
|
2
|
+
export type { SystemMigration } from './types.js';
|
|
3
|
+
import type { SystemMigration } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* All system migrations in order.
|
|
6
|
+
* Add new migrations to the END — never reorder or remove.
|
|
7
|
+
*/
|
|
8
|
+
export declare const systemMigrations: SystemMigration[];
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/system-migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAAiB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { runSystemMigrations } from './types.js';
|
|
2
|
+
import { migration as m001 } from './001_composite_pk.js';
|
|
3
|
+
import { migration as m002 } from './002_schema_log_index.js';
|
|
4
|
+
/**
|
|
5
|
+
* All system migrations in order.
|
|
6
|
+
* Add new migrations to the END — never reorder or remove.
|
|
7
|
+
*/
|
|
8
|
+
export const systemMigrations = [m001, m002];
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/system-migrations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGjD,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,SAAS,IAAI,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAG9D;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SQL } from 'drizzle-orm';
|
|
2
|
+
/** Minimal interface covering both DrizzleDb and PgTransaction */
|
|
3
|
+
export interface Executor {
|
|
4
|
+
execute: (query: SQL) => Promise<{
|
|
5
|
+
rows: unknown[];
|
|
6
|
+
}>;
|
|
7
|
+
}
|
|
8
|
+
export interface SystemMigration {
|
|
9
|
+
version: string;
|
|
10
|
+
description: string;
|
|
11
|
+
up: (tx: Executor) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run pending system migrations inside the given transaction.
|
|
15
|
+
* Call after all base `CREATE TABLE IF NOT EXISTS` statements.
|
|
16
|
+
*/
|
|
17
|
+
export declare function runSystemMigrations(tx: Executor, migrations: SystemMigration[]): Promise<void>;
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/system-migrations/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGvC,kEAAkE;AAClE,MAAM,WAAW,QAAQ;IACxB,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACxC,EAAE,EAAE,QAAQ,EACZ,UAAU,EAAE,eAAe,EAAE,GAC3B,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
/**
|
|
3
|
+
* Run pending system migrations inside the given transaction.
|
|
4
|
+
* Call after all base `CREATE TABLE IF NOT EXISTS` statements.
|
|
5
|
+
*/
|
|
6
|
+
export async function runSystemMigrations(tx, migrations) {
|
|
7
|
+
// Bootstrap the tracking table
|
|
8
|
+
await tx.execute(sql `
|
|
9
|
+
CREATE TABLE IF NOT EXISTS _viyv_system_migrations (
|
|
10
|
+
version TEXT PRIMARY KEY,
|
|
11
|
+
description TEXT NOT NULL,
|
|
12
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
13
|
+
)
|
|
14
|
+
`);
|
|
15
|
+
// Fetch already-applied versions
|
|
16
|
+
const applied = await tx.execute(sql `
|
|
17
|
+
SELECT version FROM _viyv_system_migrations
|
|
18
|
+
`);
|
|
19
|
+
const appliedSet = new Set(applied.rows.map((r) => r.version));
|
|
20
|
+
// Run pending migrations in order
|
|
21
|
+
for (const m of migrations) {
|
|
22
|
+
if (appliedSet.has(m.version))
|
|
23
|
+
continue;
|
|
24
|
+
await m.up(tx);
|
|
25
|
+
await tx.execute(sql `INSERT INTO _viyv_system_migrations (version, description) VALUES (${m.version}, ${m.description})`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/system-migrations/types.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAalC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACxC,EAAY,EACZ,UAA6B;IAE7B,+BAA+B;IAC/B,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;;;;EAMnB,CAAC,CAAC;IAEH,iCAAiC;IACjC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;EAEnC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAE,OAAO,CAAC,IAAmC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAE/F,kCAAkC;IAClC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC5B,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,SAAS;QACxC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACf,MAAM,EAAE,CAAC,OAAO,CACf,GAAG,CAAA,sEAAsE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,WAAW,GAAG,CACvG,CAAC;IACH,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { SQL } from 'drizzle-orm';
|
|
2
|
+
/** Minimal interface covering both DrizzleDb and PgTransaction */
|
|
3
|
+
interface Executor {
|
|
4
|
+
execute: (query: SQL) => Promise<{
|
|
5
|
+
rows: unknown[];
|
|
6
|
+
}>;
|
|
7
|
+
}
|
|
8
|
+
export interface SystemMigration {
|
|
9
|
+
version: string;
|
|
10
|
+
description: string;
|
|
11
|
+
up: (tx: Executor) => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ordered list of system schema migrations.
|
|
15
|
+
* Each migration runs once and is recorded in `_viyv_system_migrations`.
|
|
16
|
+
* Add new migrations to the END of this array — never reorder or remove.
|
|
17
|
+
*/
|
|
18
|
+
export declare const systemMigrations: SystemMigration[];
|
|
19
|
+
/**
|
|
20
|
+
* Run pending system migrations inside the given transaction.
|
|
21
|
+
* Call after all base `CREATE TABLE IF NOT EXISTS` statements.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runSystemMigrations(tx: Executor): Promise<void>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=system-migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-migrations.d.ts","sourceRoot":"","sources":["../src/system-migrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGvC,kEAAkE;AAClE,UAAU,QAAQ;IACjB,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAgC7C,CAAC;AAEF;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
/**
|
|
3
|
+
* Ordered list of system schema migrations.
|
|
4
|
+
* Each migration runs once and is recorded in `_viyv_system_migrations`.
|
|
5
|
+
* Add new migrations to the END of this array — never reorder or remove.
|
|
6
|
+
*/
|
|
7
|
+
export const systemMigrations = [
|
|
8
|
+
{
|
|
9
|
+
version: '001',
|
|
10
|
+
description: 'Composite PK (id, tenant_id) on _viyv_logical_rows',
|
|
11
|
+
up: async (tx) => {
|
|
12
|
+
// Only alter if PK is still single-column (idempotent guard)
|
|
13
|
+
await tx.execute(sql `
|
|
14
|
+
DO $$
|
|
15
|
+
BEGIN
|
|
16
|
+
IF EXISTS (
|
|
17
|
+
SELECT 1 FROM pg_constraint
|
|
18
|
+
WHERE conrelid = '_viyv_logical_rows'::regclass
|
|
19
|
+
AND contype = 'p'
|
|
20
|
+
AND array_length(conkey, 1) = 1
|
|
21
|
+
) THEN
|
|
22
|
+
ALTER TABLE _viyv_logical_rows DROP CONSTRAINT _viyv_logical_rows_pkey;
|
|
23
|
+
ALTER TABLE _viyv_logical_rows ADD PRIMARY KEY (id, tenant_id);
|
|
24
|
+
END IF;
|
|
25
|
+
END $$
|
|
26
|
+
`);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
version: '002',
|
|
31
|
+
description: 'Index on _viyv_schema_log(applied_at DESC)',
|
|
32
|
+
up: async (tx) => {
|
|
33
|
+
await tx.execute(sql `
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_schema_log_applied_at
|
|
35
|
+
ON _viyv_schema_log (applied_at DESC)
|
|
36
|
+
`);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Run pending system migrations inside the given transaction.
|
|
42
|
+
* Call after all base `CREATE TABLE IF NOT EXISTS` statements.
|
|
43
|
+
*/
|
|
44
|
+
export async function runSystemMigrations(tx) {
|
|
45
|
+
// Bootstrap the tracking table
|
|
46
|
+
await tx.execute(sql `
|
|
47
|
+
CREATE TABLE IF NOT EXISTS _viyv_system_migrations (
|
|
48
|
+
version TEXT PRIMARY KEY,
|
|
49
|
+
description TEXT NOT NULL,
|
|
50
|
+
applied_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
51
|
+
)
|
|
52
|
+
`);
|
|
53
|
+
// Fetch already-applied versions
|
|
54
|
+
const applied = await tx.execute(sql `
|
|
55
|
+
SELECT version FROM _viyv_system_migrations
|
|
56
|
+
`);
|
|
57
|
+
const appliedSet = new Set(applied.rows.map((r) => r.version));
|
|
58
|
+
// Run pending migrations in order
|
|
59
|
+
for (const m of systemMigrations) {
|
|
60
|
+
if (appliedSet.has(m.version))
|
|
61
|
+
continue;
|
|
62
|
+
await m.up(tx);
|
|
63
|
+
await tx.execute(sql `INSERT INTO _viyv_system_migrations (version, description) VALUES (${m.version}, ${m.description})`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=system-migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-migrations.js","sourceRoot":"","sources":["../src/system-migrations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAalC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IAClD;QACC,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,oDAAoD;QACjE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAChB,6DAA6D;YAC7D,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;;;;;;;;;;;IAanB,CAAC,CAAC;QACJ,CAAC;KACD;IACD;QACC,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,4CAA4C;QACzD,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAChB,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;IAGnB,CAAC,CAAC;QACJ,CAAC;KACD;CACD,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAY;IACrD,+BAA+B;IAC/B,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;;;;;EAMnB,CAAC,CAAC;IAEH,iCAAiC;IACjC,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAA;;EAEnC,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAE,OAAO,CAAC,IAAmC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAE/F,kCAAkC;IAClC,KAAK,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;QAClC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;YAAE,SAAS;QACxC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACf,MAAM,EAAE,CAAC,OAAO,CACf,GAAG,CAAA,sEAAsE,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,WAAW,GAAG,CACvG,CAAC;IACH,CAAC;AACF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "viyv-db-postgres",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "PostgreSQL logical table implementation for viyv-db",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "viyv",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"!dist/__tests__"
|
|
22
|
+
],
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"pg": "^8.13.0",
|
|
25
|
+
"drizzle-orm": "^0.38.0",
|
|
26
|
+
"nanoid": "^5.0.0",
|
|
27
|
+
"zod": "^3.23.0",
|
|
28
|
+
"viyv-db-core": "0.1.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/pg": "^8.11.0",
|
|
32
|
+
"drizzle-kit": "^0.30.0",
|
|
33
|
+
"typescript": "^5.7.0",
|
|
34
|
+
"vitest": "^2.1.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"test": "vitest run",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"db:generate": "drizzle-kit generate",
|
|
42
|
+
"db:migrate": "drizzle-kit migrate"
|
|
43
|
+
}
|
|
44
|
+
}
|