@workglow/postgres 0.2.28
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/job-queue/PostgresQueueStorage.d.ts +155 -0
- package/dist/job-queue/PostgresQueueStorage.d.ts.map +1 -0
- package/dist/job-queue/PostgresRateLimiterStorage.d.ts +57 -0
- package/dist/job-queue/PostgresRateLimiterStorage.d.ts.map +1 -0
- package/dist/job-queue/browser.d.ts +7 -0
- package/dist/job-queue/browser.d.ts.map +1 -0
- package/dist/job-queue/browser.js +732 -0
- package/dist/job-queue/browser.js.map +11 -0
- package/dist/job-queue/bun.d.ts +7 -0
- package/dist/job-queue/bun.d.ts.map +1 -0
- package/dist/job-queue/common.d.ts +8 -0
- package/dist/job-queue/common.d.ts.map +1 -0
- package/dist/job-queue/node.d.ts +7 -0
- package/dist/job-queue/node.d.ts.map +1 -0
- package/dist/job-queue/node.js +732 -0
- package/dist/job-queue/node.js.map +11 -0
- package/dist/storage/PostgresKvStorage.d.ts +27 -0
- package/dist/storage/PostgresKvStorage.d.ts.map +1 -0
- package/dist/storage/PostgresTabularStorage.d.ts +194 -0
- package/dist/storage/PostgresTabularStorage.d.ts.map +1 -0
- package/dist/storage/PostgresVectorStorage.d.ts +39 -0
- package/dist/storage/PostgresVectorStorage.d.ts.map +1 -0
- package/dist/storage/_postgres/browser.d.ts +32 -0
- package/dist/storage/_postgres/browser.d.ts.map +1 -0
- package/dist/storage/_postgres/node-bun.d.ts +26 -0
- package/dist/storage/_postgres/node-bun.d.ts.map +1 -0
- package/dist/storage/_postgres/pglite-pool.d.ts +21 -0
- package/dist/storage/_postgres/pglite-pool.d.ts.map +1 -0
- package/dist/storage/browser.d.ts +10 -0
- package/dist/storage/browser.d.ts.map +1 -0
- package/dist/storage/browser.js +951 -0
- package/dist/storage/browser.js.map +14 -0
- package/dist/storage/bun.d.ts +7 -0
- package/dist/storage/bun.d.ts.map +1 -0
- package/dist/storage/common.d.ts +10 -0
- package/dist/storage/common.d.ts.map +1 -0
- package/dist/storage/node.d.ts +7 -0
- package/dist/storage/node.d.ts.map +1 -0
- package/dist/storage/node.js +842 -0
- package/dist/storage/node.js.map +13 -0
- package/package.json +78 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/storage/_postgres/pglite-pool.ts", "../../src/storage/_postgres/browser.ts", "../../src/storage/PostgresKvStorage.ts", "../../src/storage/PostgresTabularStorage.ts", "../../src/storage/PostgresVectorStorage.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { PGliteInterface, PGliteOptions, Results } from \"@electric-sql/pglite\";\nimport type { PoolConfig, QueryConfig, QueryResult, QueryResultRow, Submittable } from \"pg\";\n\nfunction toFieldDefs(fields: Results[\"fields\"]): QueryResult[\"fields\"] {\n return fields.map((f) => ({\n name: f.name,\n tableID: 0,\n columnID: 0,\n dataTypeID: f.dataTypeID,\n dataTypeSize: 0,\n dataTypeModifier: 0,\n format: \"text\" as const,\n }));\n}\n\nfunction toQueryResult<R extends QueryResultRow>(r: Results<R>): QueryResult<R> {\n const rowCount = r.affectedRows ?? r.rows.length;\n return {\n rows: r.rows,\n rowCount,\n command: \"\",\n oid: 0,\n fields: toFieldDefs(r.fields),\n };\n}\n\nfunction dataDirFromPoolConfig(config?: PoolConfig): string {\n if (!config) {\n return \"memory://\";\n }\n const extended = config as PoolConfig & { dataDir?: string; pglite?: { dataDir?: string } };\n if (typeof extended.dataDir === \"string\") {\n return extended.dataDir;\n }\n if (extended.pglite && typeof extended.pglite.dataDir === \"string\") {\n return extended.pglite.dataDir;\n }\n const cs = config.connectionString;\n if (typeof cs === \"string\" && (cs.startsWith(\"memory://\") || cs.startsWith(\"idb://\"))) {\n return cs;\n }\n return \"memory://\";\n}\n\nfunction pgliteOptionsFromPoolConfig(config?: PoolConfig): PGliteOptions {\n const extended = config as PoolConfig & { pglite?: PGliteOptions };\n return extended.pglite ?? {};\n}\n\nfunction normalizeParams<I extends any[]>(\n values?: import(\"pg\").QueryConfigValues<I>\n): unknown[] | undefined {\n if (values === undefined) {\n return undefined;\n }\n return Array.isArray(values) ? [...values] : Object.values(values as Record<string, unknown>);\n}\n\n/**\n * Wraps a {@link PGliteInterface} so {@link import(\"pg\").Pool#query} call sites can stay the same\n * as with `pg` (string + optional params, or {@link QueryConfig} with `text` / `values`).\n */\nexport class PGLitePool {\n readonly #db: PGliteInterface;\n\n constructor(PGliteCtor: typeof import(\"@electric-sql/pglite\").PGlite, config?: PoolConfig) {\n const dataDir = dataDirFromPoolConfig(config);\n const opts = pgliteOptionsFromPoolConfig(config);\n this.#db = new PGliteCtor(dataDir, opts);\n }\n\n /** Resolve when WASM / FS initialization has finished. */\n async waitUntilReady(): Promise<void> {\n await this.#db.waitReady;\n }\n\n query<T extends Submittable>(queryStream: T): T;\n query<R extends QueryResultRow = any, I extends any[] = any[]>(\n queryConfig: QueryConfig<I>\n ): Promise<QueryResult<R>>;\n query<R extends QueryResultRow = any, I extends any[] = any[]>(\n queryTextOrConfig: string | QueryConfig<I>,\n values?: import(\"pg\").QueryConfigValues<I>\n ): Promise<QueryResult<R>>;\n query(queryTextOrConfig: unknown, values?: unknown): unknown {\n if (\n queryTextOrConfig !== null &&\n typeof queryTextOrConfig === \"object\" &&\n \"submit\" in (queryTextOrConfig as object)\n ) {\n return queryTextOrConfig;\n }\n\n let text: string;\n let params: unknown[] | undefined;\n\n if (typeof queryTextOrConfig === \"string\") {\n text = queryTextOrConfig;\n params = normalizeParams(values as import(\"pg\").QueryConfigValues<any>);\n } else {\n const cfg = queryTextOrConfig as QueryConfig<any>;\n if (\"rowMode\" in cfg && cfg.rowMode === \"array\") {\n throw new Error(\n 'PGLitePool (browser): rowMode \"array\" is not supported; use default row objects.'\n );\n }\n text = cfg.text;\n params = normalizeParams(cfg.values as import(\"pg\").QueryConfigValues<any>);\n }\n\n return this.#db.query(text, params).then((r) => toQueryResult(r as Results<QueryResultRow>));\n }\n\n async end(): Promise<void> {\n await this.#db.close();\n }\n}\n",
|
|
6
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool, PoolConfig } from \"pg\";\n\nimport { PGLitePool } from \"./pglite-pool\";\n\nexport type { Pool, PoolConfig };\n\nlet _PGlite: typeof import(\"@electric-sql/pglite\").PGlite | undefined;\nlet _PoolBound: (new (config?: PoolConfig) => PGLitePool) | undefined;\n\n/**\n * Loads `@electric-sql/pglite` (browser WASM Postgres). Idempotent; same implementation as\n * {@link Postgres.init} (mirrors {@link Sqlite.init} from `@workglow/sqlite/storage`).\n */\nexport async function loadPostgres(): Promise<void> {\n if (_PGlite) {\n return;\n }\n try {\n const m = await import(\"@electric-sql/pglite\");\n const PGliteCtor =\n m.PGlite ?? (m as { default?: typeof import(\"@electric-sql/pglite\").PGlite }).default;\n if (!PGliteCtor) {\n throw new Error(\"PGlite export not found\");\n }\n _PGlite = PGliteCtor;\n const Base = PGliteCtor;\n _PoolBound = class BrowserPGLitePool extends PGLitePool {\n constructor(config?: PoolConfig) {\n super(Base, config);\n }\n };\n } catch {\n throw new Error(\n \"@electric-sql/pglite is required for @workglow/postgres/storage in the browser. Install: bun add @electric-sql/pglite\"\n );\n }\n}\n\nfunction requirePoolCtor(): new (config?: PoolConfig) => PGLitePool {\n if (!_PoolBound) {\n throw new Error(\n \"Postgres is not ready. Await Postgres.init() before using @workglow/postgres/storage in the browser.\"\n );\n }\n return _PoolBound;\n}\n\n/**\n * Minimal `pg`-shaped module: `Pool` is a constructor compatible with `new Pool(config)` on Node.\n * Call {@link Postgres.init} / {@link loadPostgres} first.\n */\nexport function getPostgres(): typeof import(\"pg\") {\n const PoolCtor = requirePoolCtor();\n return {\n Pool: PoolCtor as unknown as typeof import(\"pg\").Pool,\n } as unknown as typeof import(\"pg\");\n}\n\n/**\n * Creates a PGlite-backed pool whose {@link Pool.query} matches `pg` (string + params or {@link import(\"pg\").QueryConfig}).\n *\n * `PoolConfig` mapping: default data dir is `memory://`. Use `connectionString` `memory://` or `idb://…`,\n * or `dataDir` / `pglite.dataDir`, or `pglite: { … }` for full {@link import(\"@electric-sql/pglite\").PGliteOptions}.\n */\nexport async function createPool(config?: PoolConfig): Promise<Pool> {\n await loadPostgres();\n const pool = new (requirePoolCtor())(config);\n await pool.waitUntilReady();\n return pool as unknown as Pool;\n}\n\n/** Same entry shape as the Node/Bun entry of this package. {@link Postgres.init} matches {@link Sqlite.init}. */\nexport const Postgres = {\n init: loadPostgres,\n load: loadPostgres,\n get module(): typeof import(\"pg\") {\n return getPostgres();\n },\n createPool,\n} as const;\n",
|
|
7
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { PostgresTabularStorage } from \"./PostgresTabularStorage\";\nimport {\n DefaultKeyValueKey,\n DefaultKeyValueSchema,\n IKvStorage,\n KvViaTabularStorage,\n} from \"@workglow/storage\";\n\nexport const POSTGRES_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.postgres\"\n);\n\n/**\n * A key-value repository implementation that uses PostgreSQL for persistent storage.\n * Leverages a tabular repository abstraction for PostgreSQL operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class PostgresKvStorage extends KvViaTabularStorage {\n public tabularRepository: PostgresTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public db: any,\n public dbName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new PostgresTabularStorage(\n db,\n dbName,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
|
|
8
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { TypedArray } from \"@workglow/util/schema\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n pickCoveringIndex,\n} from \"@workglow/storage\";\n\nexport const POSTGRES_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.postgres\"\n);\n\n/**\n * A PostgreSQL-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a PostgreSQL database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class PostgresTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected db: Pool;\n\n /**\n * Creates a new PostgresTabularStorage instance.\n *\n * @param db - PostgreSQL db\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n db: Pool,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.db = db;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n await this.db.query(sql);\n\n // Create vector indexes if there are vector columns\n await this.createVectorIndexes();\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n await this.db.query(\n `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`\n );\n createdIndexes.add(columnKey);\n }\n }\n }\n\n protected isVectorFormat(format?: string): boolean {\n if (!format) return false;\n return format.startsWith(\"TypedArray:\") || format === \"TypedArray\";\n }\n\n protected getVectorDimensions(typeDef: JsonSchema): number | undefined {\n return undefined;\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Handle vector format (pgvector extension)\n if (this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n return `vector(${dimension})`;\n }\n }\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert JavaScript values to PostgreSQL values, including TypedArray to vector string\n */\n protected override jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (typeDef) {\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert TypedArray to pgvector string format [1.0, 2.0, ...]\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (value && ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n // It's a TypedArray\n const array = Array.from(value as unknown as TypedArray);\n return `[${array.join(\",\")}]`;\n }\n // If it's already a string (serialized), return as-is\n if (typeof value === \"string\") {\n return value;\n }\n }\n }\n return super.jsToSqlValue(column, value);\n }\n\n /**\n * Convert PostgreSQL values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert pgvector string to TypedArray\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (typeof value === \"string\") {\n try {\n // Parse the vector string format [1.0, 2.0, ...] to TypedArray\n const array = JSON.parse(value);\n return new Float32Array(array) as Entity[keyof Entity];\n } catch (e) {\n console.warn(`Failed to parse vector for column ${column}:`, e);\n }\n }\n // If it's already an object/TypedArray, return as-is\n if (value && typeof value === \"object\") {\n return value as Entity[keyof Entity];\n }\n }\n\n // Handle numeric types - PostgreSQL can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Gets information about vector columns in the schema\n * @returns Array of objects with column name and dimension\n */\n protected getVectorColumns(): Array<{ column: string; dimension: number }> {\n const vectorColumns: Array<{ column: string; dimension: number }> = [];\n\n // Check all properties in the schema\n for (const [key, typeDef] of Object.entries<JsonSchema>(this.schema.properties)) {\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n vectorColumns.push({ column: key, dimension });\n } else {\n console.warn(`Invalid vector format for column ${key}: ${actualType.format}, skipping`);\n }\n }\n }\n\n return vectorColumns;\n }\n\n /**\n * Creates vector-specific indexes (HNSW for pgvector)\n * Called after table creation if vector columns exist\n */\n protected async createVectorIndexes(): Promise<void> {\n const vectorColumns = this.getVectorColumns();\n\n if (vectorColumns.length === 0) {\n return; // No vector columns, nothing to do\n }\n\n // Try to enable pgvector extension\n try {\n await this.db.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n } catch (error) {\n console.warn(\n \"pgvector extension not available, vector columns will use TEXT fallback:\",\n error\n );\n return;\n }\n\n // Create HNSW index for each vector column\n for (const { column } of vectorColumns) {\n const indexName = `${this.table}_${column}_hnsw_idx`;\n try {\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS \"${indexName}\"\n ON \"${this.table}\"\n USING hnsw (\"${column}\" vector_cosine_ops)\n `);\n } catch (error) {\n console.warn(`Failed to create HNSW index on ${column}:`, error);\n }\n }\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n const db = this.db;\n\n // Determine which columns to include in INSERT\n const columnsToInsert: string[] = [];\n const paramsToInsert: ValueOptionType[] = [];\n\n // Handle primary key columns\n const pkColumns = this.primaryKeyColumns();\n const entityRecord = entity as Record<string, unknown>;\n for (const col of pkColumns) {\n const colStr = String(col);\n\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(colStr)) {\n const clientProvidedValue = entityRecord[colStr];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldUseClientValue = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldUseClientValue = false;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${colStr}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldUseClientValue = true;\n } else {\n // \"if-missing\" - use client value if provided\n shouldUseClientValue = hasClientValue;\n }\n\n if (shouldUseClientValue) {\n columnsToInsert.push(colStr);\n paramsToInsert.push(\n this.jsToSqlValue(colStr, clientProvidedValue as Entity[keyof Entity])\n );\n }\n // Otherwise skip it - let database generate via SERIAL or DEFAULT\n continue;\n }\n\n // Regular primary key column\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n // Handle value columns\n const valueColumns = this.valueColumns();\n for (const col of valueColumns) {\n const colStr = String(col);\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n const columnList = columnsToInsert.map((c) => `\"${c}\"`).join(\", \");\n const placeholders = columnsToInsert.map((_, i) => `$${i + 1}`).join(\", \");\n\n // Build ON CONFLICT clause if there are value columns\n const conflictClause =\n valueColumns.length > 0\n ? `\n ON CONFLICT (${this.primaryKeyColumnList('\"')}) DO UPDATE\n SET \n ${(valueColumns as string[])\n .map((col) => {\n const colIdx = columnsToInsert.indexOf(String(col));\n return `\"${col}\" = $${colIdx + 1}`;\n })\n .join(\", \")}\n `\n : \"\";\n\n const sql = `\n INSERT INTO \"${this.table}\" (${columnList})\n VALUES (${placeholders})\n ${conflictClause}\n RETURNING *\n `;\n\n const params = paramsToInsert;\n const result = await db.query(sql, params);\n\n const updatedEntity = result.rows[0] as Entity;\n // Convert blob fields from SQL to JS values\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n updatedRecord[key] = this.sqlToJsValue(key, updatedRecord[key] as ValueOptionType);\n }\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows in the database in a bulk operation.\n * Uses individual put calls to ensure auto-generated keys are handled correctly.\n *\n * @param entities - Array of entities to store (may be missing auto-generated keys)\n * @returns Array of entities with any server-generated fields updated\n * @emits \"put\" event for each entity stored\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(entities.map((entity) => this.put(entity)));\n\n /* Original bulk implementation - keeping for reference but using simpler approach above\n if (entities.length === 0) return [];\n\n const db = this.db;\n\n // Prepare all parameters and build VALUES clause\n const allParams: any[] = [];\n const valuesPerRow = this.primaryKeyColumns().length + this.valueColumns().length;\n let paramIndex = 1;\n\n // Build the VALUES clauses - one for each entity\n const valuesClauses = entities\n .map((entity) => {\n const { key, value } = this.separateKeyValueFromCombined(entity);\n const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);\n const valueParams = this.getValueAsOrderedArray(value);\n const entityParams = [...primaryKeyParams, ...valueParams];\n\n // Add all parameters for this entity to the flat array\n allParams.push(...entityParams);\n\n // Create placeholders for this row using PostgreSQL $1, $2, etc.\n const placeholders = Array(valuesPerRow)\n .fill(0)\n .map(() => `$${paramIndex++}`)\n .join(\", \");\n return `(${placeholders})`;\n })\n .join(\", \");\n\n const sql = `\n INSERT INTO \"${this.table}\" (\n ${this.primaryKeyColumnList('\"')} ${this.valueColumnList() ? \", \" + this.valueColumnList('\"') : \"\"}\n )\n VALUES ${valuesClauses}\n ${\n !this.valueColumnList()\n ? \"\"\n : `\n ON CONFLICT (${this.primaryKeyColumnList('\"')}) DO UPDATE\n SET \n ${(this.valueColumns() as string[])\n .map((col) => {\n // For the UPDATE part, we need to reference the excluded values\n return `\"${col}\" = EXCLUDED.\"${col}\"`;\n })\n .join(\", \")}\n `\n }\n RETURNING *\n `;\n\n const result = await db.query(sql, allParams);\n\n const updatedEntities = result.rows.map((row) => {\n const entity = row as Entity;\n // Convert blob fields from SQL to JS values\n for (const key in this.schema.properties) {\n // @ts-ignore\n entity[key] = this.sqlToJsValue(key, entity[key]);\n }\n return entity;\n });\n\n // Emit events for each entity\n for (const entity of updatedEntities) {\n this.events.emit(\"put\", entity);\n }\n\n return updatedEntities;\n */\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored value or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = this.db;\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((discriminatorKey, i) => `\"${discriminatorKey}\" = $${i + 1}`)\n .join(\" AND \");\n\n const sql = `SELECT * FROM \"${this.table}\" WHERE ${whereClauses}`;\n const params = this.getPrimaryKeyAsOrderedArray(key);\n const result = await db.query(sql, params);\n\n let val: Entity | undefined;\n if (result.rows.length > 0) {\n val = result.rows[0] as Entity;\n // Convert all columns according to schema\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n } else {\n val = undefined;\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param key - The primary key object to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const db = this.db;\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((key, i) => `${key} = $${i + 1}`)\n .join(\" AND \");\n\n const params = this.getPrimaryKeyAsOrderedArray(key);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClauses}`, params);\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = this.db;\n let sql = `SELECT * FROM \"${this.table}\"`;\n const params: ValueOptionType[] = [];\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = params.length > 0 ? await db.query(sql, params) : await db.query(sql);\n\n if (result.rows.length > 0) {\n // Convert all columns according to schema\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return result.rows;\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n const db = this.db;\n await db.query(`DELETE FROM \"${this.table}\"`);\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const db = this.db;\n const result = await db.query(`SELECT COUNT(*) FROM \"${this.table}\"`);\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n const result = await db.query<{ count: string }, ValueOptionType[]>(\n `SELECT COUNT(*) FROM \"${this.table}\" WHERE ${whereClause}`,\n params\n );\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n const db = this.db;\n const orderByClause = this.primaryKeyColumns()\n .map((col) => `\"${String(col)}\"`)\n .join(\", \");\n const result = await db.query(\n `SELECT * FROM \"${this.table}\" ORDER BY ${orderByClause} LIMIT $1 OFFSET $2`,\n [limit, offset]\n );\n\n if (!result.rows || result.rows.length === 0) {\n return undefined;\n }\n\n // Convert all columns according to schema (consistent with getAll)\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return result.rows as Entity[];\n }\n\n /**\n * Builds WHERE clause conditions from delete search criteria.\n * @param criteria - The search criteria object\n * @returns Object with whereClause string and params array\n */\n protected buildDeleteSearchWhere(criteria: DeleteSearchCriteria<Entity>): {\n whereClause: string;\n params: ValueOptionType[];\n } {\n const conditions: string[] = [];\n const params: ValueOptionType[] = [];\n let paramIndex = 1;\n\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n conditions.push(`\"${String(column)}\" ${operator} $${paramIndex}`);\n params.push(this.jsToSqlValue(column as string, value));\n paramIndex++;\n }\n\n return {\n whereClause: conditions.join(\" AND \"),\n params,\n };\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClause}`, params);\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = this.db;\n\n let sql = `SELECT * FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = await db.query(sql, params);\n\n if (result.rows.length > 0) {\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k in this.schema.properties) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, result.rows as Entity[]);\n return result.rows as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Queries entries matching the specified search criteria, returning only the selected columns.\n * Requires a covering index that satisfies the criteria, orderBy, and select columns.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Required select columns plus optional orderBy, limit, and offset\n * @returns Array of partial entities containing only the selected columns\n * @throws {CoveringIndexMissingError} when no registered index covers the query\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const cols = options.select.map((c) => `\"${String(c)}\"`).join(\", \");\n let sql = `SELECT ${cols} FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options.orderBy && options.orderBy.length > 0) {\n sql +=\n ` ORDER BY ` +\n options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`).join(\", \");\n }\n if (options.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n if (options.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const db = this.db;\n const result = await db.query(sql, params);\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k of Object.keys(record)) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n return result.rows as Pick<Entity, K>[];\n }\n\n /**\n * Subscribes to changes in the repository.\n * NOT IMPLEMENTED for PostgreSQL storage.\n *\n * @throws Error always - subscribeToChanges is not supported for PostgreSQL storage\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"subscribeToChanges is not supported for PostgresTabularStorage\");\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n super.destroy();\n }\n}\n",
|
|
9
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { PostgresTabularStorage } from \"./PostgresTabularStorage\";\nimport { StorageValidationError, getMetadataProperty, getVectorProperty } from \"@workglow/storage\";\nimport type { HybridSearchOptions, IVectorStorage, VectorSearchOptions } from \"@workglow/storage\";\n\n/**\n * PostgreSQL vector repository implementation using pgvector extension.\n * Extends PostgresTabularStorage for storage.\n * Provides efficient vector similarity search with native database support.\n *\n * Requirements:\n * - PostgreSQL database with pgvector extension installed\n * - CREATE EXTENSION vector;\n *\n * @template Metadata - The metadata type\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n */\n/**\n * Regex for validating metadata filter keys to prevent SQL injection.\n * Only allows alphanumeric characters and underscores, starting with a letter or underscore.\n */\nconst SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nexport class PostgresVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends PostgresTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private readonly vectorCtor: TypedArrayConstructor;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n /**\n * Creates a new PostgreSQL vector repository\n * @param db - PostgreSQL connection pool\n * @param table - The name of the table to use for storage\n * @param schema - The schema definition for the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable\n * @param dimensions - The number of dimensions of the vector\n * @param vectorCtor - TypedArray constructor used when hydrating vectors from SQL text (e.g. {@link Float32Array})\n */\n constructor(\n db: Pool,\n table: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n vectorCtor: TypedArrayConstructor = Float32Array\n ) {\n super(db, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.vectorCtor = vectorCtor;\n\n // Cache vector and metadata property names from schema\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n public override getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n public async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Metadata> = {}\n ): Promise<Array<Entity & { score: number }>> {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n\n try {\n // Try native pgvector search first\n const queryVector = `[${Array.from(query).join(\",\")}]`;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n let sql = `\n SELECT \n *,\n 1 - (${vectorCol} <=> $1::vector) as score\n FROM \"${this.table}\"\n `;\n\n const params: any[] = [queryVector];\n let paramIndex = 2;\n\n if (filter && Object.keys(filter).length > 0 && metadataCol) {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(filter)) {\n if (!SAFE_IDENTIFIER_RE.test(key)) {\n throw new StorageValidationError(\n `Invalid metadata filter key: \"${key}\". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`\n );\n }\n conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);\n params.push(String(value));\n paramIndex++;\n }\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n }\n\n if (scoreThreshold > 0) {\n sql += filter ? \" AND\" : \" WHERE\";\n sql += ` (1 - (${vectorCol} <=> $1::vector)) >= $${paramIndex}`;\n params.push(scoreThreshold);\n paramIndex++;\n }\n\n sql += ` ORDER BY ${vectorCol} <=> $1::vector LIMIT $${paramIndex}`;\n params.push(topK);\n\n const result = await this.db.query(sql, params);\n\n // Fetch vectors separately for each result\n const results: Array<Entity & { score: number }> = [];\n for (const row of result.rows) {\n const vectorResult = await this.db.query(\n `SELECT ${vectorCol}::text FROM \"${this.table}\" WHERE ${this.getPrimaryKeyWhereClause()}`,\n this.getPrimaryKeyValues(row)\n );\n const vectorStr = vectorResult.rows[0]?.[vectorCol] || \"[]\";\n const vectorArray = JSON.parse(vectorStr);\n\n results.push({\n ...row,\n [this.vectorPropertyName]: new this.vectorCtor(vectorArray),\n score: parseFloat(row.score),\n } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n if (error instanceof StorageValidationError) {\n throw error; // Don't swallow validation errors\n }\n // Fall back to in-memory similarity calculation if pgvector is not available\n console.error(\"pgvector query failed, falling back to in-memory search:\", error);\n return this.searchFallback(query, options);\n }\n }\n\n async hybridSearch(query: TypedArray, options: HybridSearchOptions<Metadata>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n if (!textQuery || textQuery.trim().length === 0) {\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n try {\n // Try native hybrid search with pgvector + full-text\n const queryVector = `[${Array.from(query).join(\",\")}]`;\n // Use plainto_tsquery via parameterized query to avoid tsquery injection\n const tsQueryText = textQuery;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n let sql = `\n SELECT \n *,\n (\n $2 * (1 - (${vectorCol} <=> $1::vector)) +\n $3 * ts_rank(to_tsvector('english', ${metadataCol || \"''\"}::text), plainto_tsquery('english', $4))\n ) as score\n FROM \"${this.table}\"\n `;\n\n const params: any[] = [queryVector, vectorWeight, 1 - vectorWeight, tsQueryText];\n let paramIndex = 5;\n\n if (filter && Object.keys(filter).length > 0 && metadataCol) {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(filter)) {\n if (!SAFE_IDENTIFIER_RE.test(key)) {\n throw new StorageValidationError(\n `Invalid metadata filter key: \"${key}\". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`\n );\n }\n conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);\n params.push(String(value));\n paramIndex++;\n }\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n }\n\n if (scoreThreshold > 0) {\n sql += filter ? \" AND\" : \" WHERE\";\n sql += ` (\n $2 * (1 - (${vectorCol} <=> $1::vector)) +\n $3 * ts_rank(to_tsvector('english', ${metadataCol || \"''\"}::text), plainto_tsquery('english', $4))\n ) >= $${paramIndex}`;\n params.push(scoreThreshold);\n paramIndex++;\n }\n\n sql += ` ORDER BY score DESC LIMIT $${paramIndex}`;\n params.push(topK);\n\n const result = await this.db.query(sql, params);\n\n // Fetch vectors separately for each result\n const results: Array<Entity & { score: number }> = [];\n for (const row of result.rows) {\n const vectorResult = await this.db.query(\n `SELECT ${vectorCol}::text FROM \"${this.table}\" WHERE ${this.getPrimaryKeyWhereClause()}`,\n this.getPrimaryKeyValues(row)\n );\n const vectorStr = vectorResult.rows[0]?.[vectorCol] || \"[]\";\n const vectorArray = JSON.parse(vectorStr);\n\n results.push({\n ...row,\n [this.vectorPropertyName]: new this.vectorCtor(vectorArray),\n score: parseFloat(row.score),\n } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n if (error instanceof StorageValidationError) {\n throw error; // Don't swallow validation errors\n }\n // Fall back to in-memory hybrid search\n console.error(\"pgvector hybrid query failed, falling back to in-memory search:\", error);\n return this.hybridSearchFallback(query, options);\n }\n }\n\n /**\n * Fallback search using in-memory cosine similarity\n */\n private async searchFallback(query: TypedArray, options: VectorSearchOptions<Metadata>) {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const allRows = (await this.getAll()) || [];\n const results: Array<Entity & { score: number }> = [];\n\n for (const row of allRows) {\n const vector = row[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (row[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n if (filter && !this.matchesFilter(metadata, filter)) {\n continue;\n }\n\n const score = cosineSimilarity(query, vector);\n\n if (score >= scoreThreshold) {\n results.push({ ...row, score } as Entity & { score: number });\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n /**\n * Fallback hybrid search\n */\n private async hybridSearchFallback(query: TypedArray, options: HybridSearchOptions<Metadata>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n const allRows = (await this.getAll()) || [];\n const results: Array<Entity & { score: number }> = [];\n const queryLower = textQuery.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n\n for (const row of allRows) {\n const vector = row[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (row[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n if (filter && !this.matchesFilter(metadata, filter)) {\n continue;\n }\n\n const vectorScore = cosineSimilarity(query, vector);\n const metadataText = Object.values(metadata ?? {})\n .join(\" \")\n .toLowerCase();\n let textScore = 0;\n if (queryWords.length > 0) {\n let matches = 0;\n for (const word of queryWords) {\n if (metadataText.includes(word)) {\n matches++;\n }\n }\n textScore = matches / queryWords.length;\n }\n\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n if (combinedScore >= scoreThreshold) {\n results.push({ ...row, score: combinedScore } as Entity & { score: number });\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n private getPrimaryKeyWhereClause(): string {\n const conditions = this.primaryKeyNames.map((key, idx) => `${String(key)} = $${idx + 1}`);\n return conditions.join(\" AND \");\n }\n\n private getPrimaryKeyValues(row: any): any[] {\n return this.primaryKeyNames.map((key) => row[key]);\n }\n\n private matchesFilter(metadata: Metadata, filter: Partial<Metadata>): boolean {\n for (const [key, value] of Object.entries(filter)) {\n if (metadata[key as keyof Metadata] !== value) {\n return false;\n }\n }\n return true;\n }\n}\n"
|
|
10
|
+
],
|
|
11
|
+
"mappings": "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",
|
|
12
|
+
"debugId": "AA405D543F42642864756E2164756E21",
|
|
13
|
+
"names": []
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/storage/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
export * from "./_postgres/node-bun";
|
|
7
|
+
export * from "./PostgresKvStorage";
|
|
8
|
+
export * from "./PostgresTabularStorage";
|
|
9
|
+
export * from "./PostgresVectorStorage";
|
|
10
|
+
//# sourceMappingURL=common.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/storage/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/storage/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
|