@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.
Files changed (51) hide show
  1. package/dist/PostgresAdapter.d.ts +1 -1
  2. package/dist/PostgresBackendDriver.d.ts +7 -7
  3. package/dist/PostgresBootstrapper.d.ts +6 -6
  4. package/dist/auth/services.d.ts +1 -1
  5. package/dist/backup/backup-cron.d.ts +1 -1
  6. package/dist/backup/backup-service.d.ts +2 -2
  7. package/dist/backup/index.d.ts +4 -4
  8. package/dist/collections/PostgresCollectionRegistry.d.ts +1 -1
  9. package/dist/collections/buildRegistry.d.ts +1 -1
  10. package/dist/collections/validate-relations.d.ts +1 -1
  11. package/dist/data-transformer.d.ts +1 -1
  12. package/dist/{ensure-collection-policies-BVFb2olB.js → ensure-collection-policies-LKKfQmtD.js} +2 -2
  13. package/dist/{ensure-collection-policies-BVFb2olB.js.map → ensure-collection-policies-LKKfQmtD.js.map} +1 -1
  14. package/dist/{ensure-collection-tables-BY1pHRD_.js → ensure-collection-tables-QQrmaSSN.js} +151 -6
  15. package/dist/ensure-collection-tables-QQrmaSSN.js.map +1 -0
  16. package/dist/index.d.ts +16 -16
  17. package/dist/index.es.js +2 -2
  18. package/dist/schema/dynamic-tables.d.ts +1 -1
  19. package/dist/schema/ensure-collection-policies.d.ts +1 -1
  20. package/dist/schema/ensure-collection-tables.d.ts +12 -0
  21. package/dist/schema/introspect-db-constraints.d.ts +1 -1
  22. package/dist/schema/introspect-db-logic.d.ts +3 -3
  23. package/dist/schema/introspect-db-project.d.ts +1 -1
  24. package/dist/schema/introspect-db-queries.d.ts +1 -1
  25. package/dist/schema/introspect-db-structure.d.ts +2 -2
  26. package/dist/schema/introspect-runtime.d.ts +1 -1
  27. package/dist/schema/vector-index.d.ts +88 -0
  28. package/dist/services/BranchService.d.ts +2 -2
  29. package/dist/services/FetchService.d.ts +4 -4
  30. package/dist/services/PersistService.d.ts +5 -5
  31. package/dist/services/RelationService.d.ts +3 -3
  32. package/dist/services/RelationWriteService.d.ts +3 -3
  33. package/dist/services/cdc/junction-tables.d.ts +1 -1
  34. package/dist/services/cdc/trigger-cdc.d.ts +1 -1
  35. package/dist/services/channel-bus/PostgresChannelBus.d.ts +1 -1
  36. package/dist/services/channel-bus/index.d.ts +2 -2
  37. package/dist/services/collection-helpers.d.ts +1 -1
  38. package/dist/services/dataService.d.ts +10 -10
  39. package/dist/services/index.d.ts +4 -4
  40. package/dist/services/junction-writes.d.ts +2 -2
  41. package/dist/services/nested-path.d.ts +1 -1
  42. package/dist/services/realtimeService.d.ts +3 -3
  43. package/dist/services/row-pipeline.d.ts +1 -1
  44. package/dist/services/write-denial.d.ts +1 -1
  45. package/dist/utils/drizzle-conditions.d.ts +2 -2
  46. package/dist/websocket.d.ts +2 -2
  47. package/package.json +7 -7
  48. package/src/schema/ensure-collection-tables.ts +49 -6
  49. package/src/schema/generate-postgres-ddl-logic.ts +15 -0
  50. package/src/schema/vector-index.ts +278 -0
  51. 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
  *
@@ -1,4 +1,4 @@
1
- import type { RawSqlRunner } from "../../security/rls-enforcement";
1
+ import type { RawSqlRunner } from "../../security/rls-enforcement.js";
2
2
  /**
3
3
  * Trigger-based Change Data Capture (CDC).
4
4
  *
@@ -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
  *
@@ -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
  *
@@ -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.0",
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/common": "0.16.0",
51
- "@rebasepro/server": "0.16.0",
52
- "@rebasepro/types": "0.16.0",
53
- "@rebasepro/codegen": "0.16.0",
54
- "@rebasepro/utils": "0.16.0"
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
- return { actions, statements: actions.map(a => a.sql), legacyForeignKeys, searchDrift, searchAdopted };
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`, not the
711
- * scaffold's `postgres:18-alpine`, which does not ship it. Installing an
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 (e.g. `pgvector/pgvector:pg18` the scaffold's `postgres:18-alpine` " +
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
- "Note also that Rebase creates no ANN index for a vector column, so `vectorSearch` is an exact scan."
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) {