@rebasepro/server-postgres 0.16.0 → 0.16.1-canary.g701140a
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/PostgresAdapter.d.ts +1 -1
- package/dist/PostgresBackendDriver.d.ts +7 -7
- package/dist/PostgresBootstrapper.d.ts +6 -6
- package/dist/auth/services.d.ts +1 -1
- package/dist/backup/backup-cron.d.ts +1 -1
- package/dist/backup/backup-service.d.ts +2 -2
- package/dist/backup/index.d.ts +4 -4
- package/dist/collections/PostgresCollectionRegistry.d.ts +1 -1
- package/dist/collections/buildRegistry.d.ts +1 -1
- package/dist/collections/validate-relations.d.ts +1 -1
- package/dist/data-transformer.d.ts +1 -1
- package/dist/{ensure-collection-policies-BVFb2olB.js → ensure-collection-policies-LKKfQmtD.js} +2 -2
- package/dist/{ensure-collection-policies-BVFb2olB.js.map → ensure-collection-policies-LKKfQmtD.js.map} +1 -1
- package/dist/{ensure-collection-tables-BY1pHRD_.js → ensure-collection-tables-QQrmaSSN.js} +151 -6
- package/dist/ensure-collection-tables-QQrmaSSN.js.map +1 -0
- package/dist/index.d.ts +16 -16
- package/dist/index.es.js +2 -2
- package/dist/schema/dynamic-tables.d.ts +1 -1
- package/dist/schema/ensure-collection-policies.d.ts +1 -1
- package/dist/schema/ensure-collection-tables.d.ts +12 -0
- package/dist/schema/introspect-db-constraints.d.ts +1 -1
- package/dist/schema/introspect-db-logic.d.ts +3 -3
- package/dist/schema/introspect-db-project.d.ts +1 -1
- package/dist/schema/introspect-db-queries.d.ts +1 -1
- package/dist/schema/introspect-db-structure.d.ts +2 -2
- package/dist/schema/introspect-runtime.d.ts +1 -1
- package/dist/schema/vector-index.d.ts +88 -0
- package/dist/services/BranchService.d.ts +2 -2
- package/dist/services/FetchService.d.ts +4 -4
- package/dist/services/PersistService.d.ts +5 -5
- package/dist/services/RelationService.d.ts +3 -3
- package/dist/services/RelationWriteService.d.ts +3 -3
- package/dist/services/cdc/junction-tables.d.ts +1 -1
- package/dist/services/cdc/trigger-cdc.d.ts +1 -1
- package/dist/services/channel-bus/PostgresChannelBus.d.ts +1 -1
- package/dist/services/channel-bus/index.d.ts +2 -2
- package/dist/services/collection-helpers.d.ts +1 -1
- package/dist/services/dataService.d.ts +10 -10
- package/dist/services/index.d.ts +4 -4
- package/dist/services/junction-writes.d.ts +2 -2
- package/dist/services/nested-path.d.ts +1 -1
- package/dist/services/realtimeService.d.ts +3 -3
- package/dist/services/row-pipeline.d.ts +1 -1
- package/dist/services/write-denial.d.ts +1 -1
- package/dist/utils/drizzle-conditions.d.ts +2 -2
- package/dist/websocket.d.ts +2 -2
- package/package.json +7 -7
- package/src/schema/ensure-collection-tables.ts +49 -6
- package/src/schema/generate-postgres-ddl-logic.ts +15 -0
- package/src/schema/vector-index.ts +278 -0
- package/dist/ensure-collection-tables-BY1pHRD_.js.map +0 -1
|
@@ -2,10 +2,10 @@ import { SQL } from "drizzle-orm";
|
|
|
2
2
|
import { PgTable } from "drizzle-orm/pg-core";
|
|
3
3
|
import { FilterValues, OrderByTuple, LogicalCondition } from "@rebasepro/types";
|
|
4
4
|
import type { VectorSearchParams } from "@rebasepro/types";
|
|
5
|
-
import { RelationService } from "./RelationService";
|
|
6
|
-
import { DrizzleClient } from "../interfaces";
|
|
7
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
8
|
-
import { type NestedPathHop } from "./nested-path";
|
|
5
|
+
import { RelationService } from "./RelationService.js";
|
|
6
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
7
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
8
|
+
import { type NestedPathHop } from "./nested-path.js";
|
|
9
9
|
/**
|
|
10
10
|
* Service for handling all row read operations.
|
|
11
11
|
* Handles fetching, searching, counting, and filtering rows.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RelationService } from "./RelationService";
|
|
2
|
-
import { RelationWriteService } from "./RelationWriteService";
|
|
3
|
-
import { FetchService } from "./FetchService";
|
|
4
|
-
import { DrizzleClient } from "../interfaces";
|
|
5
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
1
|
+
import { RelationService } from "./RelationService.js";
|
|
2
|
+
import { RelationWriteService } from "./RelationWriteService.js";
|
|
3
|
+
import { FetchService } from "./FetchService.js";
|
|
4
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
5
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
6
6
|
/**
|
|
7
7
|
* Service for handling all row write operations.
|
|
8
8
|
* Handles saving, deleting, and updating rows.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DrizzleClient } from "../interfaces";
|
|
1
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
2
2
|
import { CollectionConfig, FilterValues, OrderByTuple, ResolvedRelation, ResolvedHasMany, ResolvedHasOne } from "@rebasepro/types";
|
|
3
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
-
import type { NestedPathHop } from "./nested-path";
|
|
3
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
4
|
+
import type { NestedPathHop } from "./nested-path.js";
|
|
5
5
|
/**
|
|
6
6
|
* Service for handling all relation-related operations.
|
|
7
7
|
* Handles fetching, updating, and managing row relations.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CollectionConfig, ResolvedManyToMany, ResolvedRelation, ResolvedVia } from "@rebasepro/types";
|
|
2
|
-
import { DrizzleClient } from "../interfaces";
|
|
3
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
-
import type { NestedPathHop } from "./nested-path";
|
|
2
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
3
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
4
|
+
import type { NestedPathHop } from "./nested-path.js";
|
|
5
5
|
/**
|
|
6
6
|
* Writing relations: junction membership, foreign-key stamping, and the links a
|
|
7
7
|
* nested path creates or removes.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
-
import { PostgresCollectionRegistry } from "../../collections/PostgresCollectionRegistry";
|
|
2
|
+
import { PostgresCollectionRegistry } from "../../collections/PostgresCollectionRegistry.js";
|
|
3
3
|
/**
|
|
4
4
|
* One end of a many-to-many, as seen from the junction table.
|
|
5
5
|
*
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* than correctness. That is what makes coalescing safe.
|
|
27
27
|
*/
|
|
28
28
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
29
|
-
import { ChannelBus, ChannelBusFrame, ChannelBusHandler } from "./ChannelBus";
|
|
29
|
+
import { ChannelBus, ChannelBusFrame, ChannelBusHandler } from "./ChannelBus.js";
|
|
30
30
|
/** NOTIFY channel carrying channel-bus frames. */
|
|
31
31
|
export declare const CHANNEL_BUS_NOTIFY_CHANNEL = "rebase_channel_bus";
|
|
32
32
|
/**
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
18
18
|
import { type ChannelBus, type ChannelBusSetting } from "@rebasepro/types";
|
|
19
|
-
export * from "./ChannelBus";
|
|
20
|
-
export { PostgresChannelBus, CHANNEL_BUS_NOTIFY_CHANNEL, PG_NOTIFY_MAX_PAYLOAD_BYTES, DEFAULT_BATCH_WINDOW_MS, parseChannelBusFrame, parseChannelBusPayload } from "./PostgresChannelBus";
|
|
19
|
+
export * from "./ChannelBus.js";
|
|
20
|
+
export { PostgresChannelBus, CHANNEL_BUS_NOTIFY_CHANNEL, PG_NOTIFY_MAX_PAYLOAD_BYTES, DEFAULT_BATCH_WINDOW_MS, parseChannelBusFrame, parseChannelBusPayload } from "./PostgresChannelBus.js";
|
|
21
21
|
export interface ChannelBusDeps {
|
|
22
22
|
db: NodePgDatabase<Record<string, unknown>>;
|
|
23
23
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PgTable, AnyPgColumn } from "drizzle-orm/pg-core";
|
|
2
2
|
import { CollectionConfig, ResolvedHasMany, ResolvedHasOne } from "@rebasepro/types";
|
|
3
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
3
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
4
4
|
import { ApiError } from "@rebasepro/server";
|
|
5
5
|
export { buildCompositeId, parseIdValues, isAddressableId, COMPOSITE_ID_SEPARATOR } from "@rebasepro/common";
|
|
6
6
|
export type { PrimaryKeyInfo } from "@rebasepro/common";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { FilterValues, LogicalCondition, OrderByTuple } from "@rebasepro/types";
|
|
2
2
|
import type { VectorSearchParams } from "@rebasepro/types";
|
|
3
|
-
import { FetchService } from "./FetchService";
|
|
4
|
-
import { PersistService } from "./PersistService";
|
|
5
|
-
import { RelationService } from "./RelationService";
|
|
6
|
-
import { DataRepository, DrizzleClient } from "../interfaces";
|
|
7
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
8
|
-
export { sanitizeAndConvertDates, serializeDataToServer, parseDataFromServer } from "../data-transformer";
|
|
9
|
-
export { FetchService } from "./FetchService";
|
|
10
|
-
export { PersistService } from "./PersistService";
|
|
11
|
-
export { RelationService } from "./RelationService";
|
|
12
|
-
export * from "../interfaces";
|
|
3
|
+
import { FetchService } from "./FetchService.js";
|
|
4
|
+
import { PersistService } from "./PersistService.js";
|
|
5
|
+
import { RelationService } from "./RelationService.js";
|
|
6
|
+
import { DataRepository, DrizzleClient } from "../interfaces.js";
|
|
7
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
8
|
+
export { sanitizeAndConvertDates, serializeDataToServer, parseDataFromServer } from "../data-transformer.js";
|
|
9
|
+
export { FetchService } from "./FetchService.js";
|
|
10
|
+
export { PersistService } from "./PersistService.js";
|
|
11
|
+
export { RelationService } from "./RelationService.js";
|
|
12
|
+
export * from "../interfaces.js";
|
|
13
13
|
/**
|
|
14
14
|
* DataService - Facade for row operations.
|
|
15
15
|
*
|
package/dist/services/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { FetchService } from "./FetchService";
|
|
2
|
-
export { PersistService } from "./PersistService";
|
|
3
|
-
export { RelationService } from "./RelationService";
|
|
4
|
-
export { getCollectionByPath, getTableForCollection, getPrimaryKeys, deriveRowAddress, parseIdValues, buildCompositeId } from "./collection-helpers";
|
|
1
|
+
export { FetchService } from "./FetchService.js";
|
|
2
|
+
export { PersistService } from "./PersistService.js";
|
|
3
|
+
export { RelationService } from "./RelationService.js";
|
|
4
|
+
export { getCollectionByPath, getTableForCollection, getPrimaryKeys, deriveRowAddress, parseIdValues, buildCompositeId } from "./collection-helpers.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AnyPgColumn, PgTable } from "drizzle-orm/pg-core";
|
|
2
2
|
import type { ResolvedVia } from "@rebasepro/types";
|
|
3
|
-
import { DrizzleClient } from "../interfaces";
|
|
4
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
3
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
4
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
5
5
|
/**
|
|
6
6
|
* Writing a many-to-many means writing rows in a junction table, and doing that
|
|
7
7
|
* needs three things: the table, the column naming the row being written from,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CollectionConfig, ResolvedRelation } from "@rebasepro/types";
|
|
2
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
2
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
3
3
|
/**
|
|
4
4
|
* The last hop of a nested collection path, e.g. `authors/1/posts`.
|
|
5
5
|
*
|
|
@@ -2,9 +2,9 @@ import { WebSocket } from "ws";
|
|
|
2
2
|
import { EventEmitter } from "events";
|
|
3
3
|
import { DataDriver, WebSocketMessage, LogicalCondition, OrderByTuple } from "@rebasepro/types";
|
|
4
4
|
import { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
5
|
-
import { RealtimeProvider, CollectionSubscriptionConfig, SingleSubscriptionConfig } from "../interfaces";
|
|
6
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
7
|
-
import { ChannelBus } from "./channel-bus";
|
|
5
|
+
import { RealtimeProvider, CollectionSubscriptionConfig, SingleSubscriptionConfig } from "../interfaces.js";
|
|
6
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
7
|
+
import { ChannelBus } from "./channel-bus/index.js";
|
|
8
8
|
import type { ChannelRetentionRule } from "@rebasepro/types";
|
|
9
9
|
/**
|
|
10
10
|
* Auth context stored per-subscription so real-time refetches respect RLS.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CollectionConfig, ResolvedRelation } from "@rebasepro/types";
|
|
2
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
2
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
3
3
|
/**
|
|
4
4
|
* Turning a drizzle result into a row we serve.
|
|
5
5
|
*
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SQL } from "drizzle-orm";
|
|
2
2
|
import { PgTable } from "drizzle-orm/pg-core";
|
|
3
3
|
import { ApiError } from "@rebasepro/server";
|
|
4
|
-
import { DrizzleClient } from "../interfaces";
|
|
4
|
+
import { DrizzleClient } from "../interfaces.js";
|
|
5
5
|
/**
|
|
6
6
|
* Explain a write that matched no rows.
|
|
7
7
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SQL } from "drizzle-orm";
|
|
2
2
|
import { AnyPgColumn, PgTable } from "drizzle-orm/pg-core";
|
|
3
3
|
import { CollectionConfig, FilterValues, WhereFilterOp, LogicalCondition, FilterCondition, ResolvedRelation, ResolvedBelongsTo, ResolvedForeignKeyOnTarget, ResolvedManyToMany, type RelationAggregateSort } from "@rebasepro/types";
|
|
4
|
-
import { type SearchColumnSpec } from "../schema/search-column";
|
|
5
|
-
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
+
import { type SearchColumnSpec } from "../schema/search-column.js";
|
|
5
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry.js";
|
|
6
6
|
/**
|
|
7
7
|
* What to do with a filter field that resolves to no column at all.
|
|
8
8
|
*
|
package/dist/websocket.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { RealtimeService } from "./services/realtimeService";
|
|
2
|
-
import { PostgresBackendDriver } from "./PostgresBackendDriver";
|
|
1
|
+
import { RealtimeService } from "./services/realtimeService.js";
|
|
2
|
+
import { PostgresBackendDriver } from "./PostgresBackendDriver.js";
|
|
3
3
|
import type { AuthAdapter } from "@rebasepro/types";
|
|
4
4
|
import { Server } from "http";
|
|
5
5
|
/** Minimal subset of RebaseAuthConfig used by the WebSocket layer. */
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/server-postgres",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.1-canary.g701140a",
|
|
5
5
|
"description": "PostgreSQL data source backend implementation for Rebase with Drizzle ORM",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -47,11 +47,11 @@
|
|
|
47
47
|
"execa": "^9.6.1",
|
|
48
48
|
"pg": "^8.22.0",
|
|
49
49
|
"ws": "^8.21.1",
|
|
50
|
-
"@rebasepro/
|
|
51
|
-
"@rebasepro/
|
|
52
|
-
"@rebasepro/
|
|
53
|
-
"@rebasepro/
|
|
54
|
-
"@rebasepro/
|
|
50
|
+
"@rebasepro/codegen": "0.16.1-canary.g701140a",
|
|
51
|
+
"@rebasepro/common": "0.16.1-canary.g701140a",
|
|
52
|
+
"@rebasepro/server": "0.16.1-canary.g701140a",
|
|
53
|
+
"@rebasepro/utils": "0.16.1-canary.g701140a",
|
|
54
|
+
"@rebasepro/types": "0.16.1-canary.g701140a"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@hono/node-server": "^2.0.12",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
],
|
|
78
78
|
"scripts": {
|
|
79
79
|
"watch": "vite build --watch",
|
|
80
|
-
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/assert-build-output.mjs",
|
|
80
|
+
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/add-dts-extensions.mjs dist && node ../../scripts/assert-build-output.mjs",
|
|
81
81
|
"test:lint": "eslint \"src/**\" --quiet",
|
|
82
82
|
"test": "jest",
|
|
83
83
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
planJunctionTables,
|
|
49
49
|
quoteSqlLiteral
|
|
50
50
|
} from "./generate-postgres-ddl-logic";
|
|
51
|
+
import { buildVectorIndexPlan, vectorIndexStatement, type SkippedVectorIndex } from "./vector-index";
|
|
51
52
|
import {
|
|
52
53
|
AUTH_USERS_COLUMNS,
|
|
53
54
|
authUsersColumnDefinition,
|
|
@@ -138,6 +139,17 @@ export interface EnsurePlan {
|
|
|
138
139
|
* current block cannot be known, which is what the caller reports.
|
|
139
140
|
*/
|
|
140
141
|
searchAdopted: { table: string; column: string }[];
|
|
142
|
+
/**
|
|
143
|
+
* Vector columns this plan is deliberately leaving unindexed, because
|
|
144
|
+
* pgvector cannot build an ANN index that wide.
|
|
145
|
+
*
|
|
146
|
+
* Reported rather than thrown: the column is valid, storable and
|
|
147
|
+
* searchable, and refusing the boot over it would make a working
|
|
148
|
+
* configuration unbootable. Reported rather than dropped: an unindexed
|
|
149
|
+
* vector column and an indexed one differ only in latency, so nothing
|
|
150
|
+
* about the running system says which one you got.
|
|
151
|
+
*/
|
|
152
|
+
vectorIndexSkipped: SkippedVectorIndex[];
|
|
141
153
|
}
|
|
142
154
|
|
|
143
155
|
/**
|
|
@@ -595,7 +607,26 @@ export function planCollectionSchemaEnsure(
|
|
|
595
607
|
}
|
|
596
608
|
}
|
|
597
609
|
|
|
598
|
-
|
|
610
|
+
// ANN indexes for vector columns, on the same terms: the column has to
|
|
611
|
+
// exist, the build is real work against real rows, and CONCURRENTLY is
|
|
612
|
+
// what keeps that from locking writes for its duration.
|
|
613
|
+
//
|
|
614
|
+
// A column too wide for pgvector to index is reported, not planned —
|
|
615
|
+
// silence there would read as "indexed" to anyone watching the boot.
|
|
616
|
+
const vectorIndexSkipped: SkippedVectorIndex[] = [];
|
|
617
|
+
for (const collection of collections) {
|
|
618
|
+
const plan = buildVectorIndexPlan(collection, resolveColumnName);
|
|
619
|
+
for (const spec of plan.specs) {
|
|
620
|
+
actions.push({
|
|
621
|
+
kind: "create-index",
|
|
622
|
+
target: `${spec.schema}.${spec.table}`,
|
|
623
|
+
sql: vectorIndexStatement(spec).replace("CREATE INDEX IF NOT EXISTS", "CREATE INDEX CONCURRENTLY IF NOT EXISTS")
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
vectorIndexSkipped.push(...plan.skipped);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
return { actions, statements: actions.map(a => a.sql), legacyForeignKeys, searchDrift, searchAdopted, vectorIndexSkipped };
|
|
599
630
|
}
|
|
600
631
|
|
|
601
632
|
/** Read what the database has, for the schemas the collections live in. */
|
|
@@ -707,20 +738,23 @@ function searchDriftMessage(drift: SearchColumnDrift[]): string {
|
|
|
707
738
|
* The missing-pgvector explanation, appended to the error that reveals it.
|
|
708
739
|
*
|
|
709
740
|
* A `{ type: "vector" }` property compiles to `VECTOR(n)`, and nothing in the
|
|
710
|
-
* OSS pipeline installs pgvector — not this ensure, not `db push
|
|
711
|
-
*
|
|
712
|
-
* extension on someone's database is a decision with a deployment behind it
|
|
741
|
+
* OSS pipeline installs pgvector — not this ensure, not `db push`. Installing
|
|
742
|
+
* an extension on someone's database is a decision with a deployment behind it
|
|
713
743
|
* (image, superuser, cloud allow-list), so this path stays a refusal; what it
|
|
714
744
|
* must not stay is a bare `type "vector" does not exist` on a crash-looping
|
|
715
745
|
* pod, which names nothing the reader can act on.
|
|
746
|
+
*
|
|
747
|
+
* The scaffold now ships `pgvector/pgvector:pg18`, so this is reached by a
|
|
748
|
+
* project pointed at a database someone else provisioned — which is exactly
|
|
749
|
+
* the case where naming the extension and the image is worth the words.
|
|
716
750
|
*/
|
|
717
751
|
function vectorExtensionHint(message: string): string {
|
|
718
752
|
if (!/type "(vector|halfvec|sparsevec)" does not exist/i.test(message)) return "";
|
|
719
753
|
return (
|
|
720
754
|
"\n pgvector is not installed on this database, and Rebase does not install it: it is a server extension, " +
|
|
721
|
-
"so it needs an image that ships it (
|
|
755
|
+
"so it needs an image that ships it (the scaffold's `pgvector/pgvector:pg18` does; a stock `postgres:18` " +
|
|
722
756
|
"does not) and a role allowed to run `CREATE EXTENSION vector;`. Install it once, then boot again. " +
|
|
723
|
-
"
|
|
757
|
+
"Rebase then creates an ANN index for the column automatically — see the `index` option on the property."
|
|
724
758
|
);
|
|
725
759
|
}
|
|
726
760
|
|
|
@@ -793,6 +827,15 @@ export async function ensureCollectionTables(
|
|
|
793
827
|
log?.(message);
|
|
794
828
|
}
|
|
795
829
|
|
|
830
|
+
// Said once per column, every boot: an unindexed vector column and an
|
|
831
|
+
// indexed one behave identically apart from latency, so the only way anyone
|
|
832
|
+
// learns which one they have is if the boot says so.
|
|
833
|
+
for (const skip of plan.vectorIndexSkipped) {
|
|
834
|
+
const message = `No ANN index on "${skip.table}"."${skip.column}": ${skip.reason}`;
|
|
835
|
+
logger.warn(`[schema] ${message}`);
|
|
836
|
+
log?.(message);
|
|
837
|
+
}
|
|
838
|
+
|
|
796
839
|
if (plan.actions.length === 0) {
|
|
797
840
|
log?.("Schema is up to date; nothing to create.");
|
|
798
841
|
return { ...plan, failures };
|
|
@@ -15,6 +15,11 @@ import {
|
|
|
15
15
|
searchIndexNames,
|
|
16
16
|
type SearchColumnSpec
|
|
17
17
|
} from "./search-column";
|
|
18
|
+
import {
|
|
19
|
+
buildVectorIndexPlan,
|
|
20
|
+
vectorIndexStatements,
|
|
21
|
+
type VectorIndexPlan
|
|
22
|
+
} from "./vector-index";
|
|
18
23
|
import { REBASE_SCHEMA } from "@rebasepro/types";
|
|
19
24
|
|
|
20
25
|
// --- Helper Functions ---
|
|
@@ -719,6 +724,16 @@ export const generatePostgresDdl = async (
|
|
|
719
724
|
indexStatements.push(...searchIndexStatements(searchSpec));
|
|
720
725
|
}
|
|
721
726
|
|
|
727
|
+
// ANN indexes for vector columns. Emitted with the other indexes
|
|
728
|
+
// rather than inline, because `CREATE INDEX` is a statement and a
|
|
729
|
+
// column definition is not — and because a column too wide for
|
|
730
|
+
// pgvector to index still needs its column.
|
|
731
|
+
const vectorPlan: VectorIndexPlan = buildVectorIndexPlan(collection, resolveColumnName);
|
|
732
|
+
indexStatements.push(...vectorIndexStatements(vectorPlan));
|
|
733
|
+
for (const skip of vectorPlan.skipped) {
|
|
734
|
+
indexStatements.push(`-- No ANN index on "${skip.schema}"."${skip.table}"."${skip.column}": ${skip.reason}`);
|
|
735
|
+
}
|
|
736
|
+
|
|
722
737
|
// Backwards compatibility: add default id primary key if missing
|
|
723
738
|
const hasPk = columns.some(c => c.includes("PRIMARY KEY"));
|
|
724
739
|
if (!hasPk) {
|