@workglow/storage 0.1.0 → 0.1.1
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/browser.js.map +9 -9
- package/dist/bun.js.map +13 -13
- package/dist/node.js.map +13 -13
- package/dist/tabular/BaseSqlTabularStorage.d.ts.map +1 -1
- package/dist/tabular/CachedTabularStorage.d.ts.map +1 -1
- package/dist/tabular/FsFolderTabularStorage.d.ts.map +1 -1
- package/dist/tabular/HuggingFaceTabularStorage.d.ts.map +1 -1
- package/dist/tabular/InMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
- package/dist/tabular/PostgresTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
- package/dist/tabular/SqliteTabularStorage.d.ts.map +1 -1
- package/dist/tabular/StorageError.d.ts.map +1 -1
- package/dist/tabular/SupabaseTabularStorage.d.ts.map +1 -1
- package/dist/vector/PostgresVectorStorage.d.ts.map +1 -1
- package/dist/vector/SqliteAiVectorStorage.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/node.js.map
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, EventEmitter, makeFingerprint } from \"@workglow/util\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n ITabularStorage,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularEventListener,\n TabularEventListeners,\n TabularEventName,\n TabularEventParameters,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\nimport {\n StorageEmptyCriteriaError,\n StorageInvalidColumnError,\n StorageInvalidLimitError,\n StorageValidationError,\n} from \"./StorageError\";\n\nexport const TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository\"\n);\n\n/**\n * Options for controlling how client-provided values for auto-generated keys are handled\n */\nexport type ClientProvidedKeysOption = \"never\" | \"if-missing\" | \"always\";\n\n/**\n * Generation strategy for auto-generated keys\n */\nexport type KeyGenerationStrategy = \"autoincrement\" | \"uuid\";\n\n/**\n * Abstract base class for tabular storage repositories.\n * Provides functionality for storing and retrieving data with typed\n * primary keys and values, and supports compound keys and partial key lookup.\n * Has a basic event emitter for listening to repository events.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport abstract class BaseTabularStorage<\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 = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> implements ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, InsertType> {\n /** Event emitter for repository events */\n protected events = new EventEmitter<TabularEventListeners<PrimaryKey, Entity>>();\n\n protected indexes: Array<keyof Entity>[];\n protected primaryKeySchema: DataPortSchemaObject;\n protected valueSchema: DataPortSchemaObject;\n\n /** Name of the auto-generated key column (only first primary key column can be auto-generated) */\n protected autoGeneratedKeyName: keyof Entity | null = null;\n /** Strategy for generating the auto-generated key */\n protected autoGeneratedKeyStrategy: KeyGenerationStrategy | null = null;\n /** How to handle client-provided values for auto-generated keys */\n protected clientProvidedKeys: ClientProvidedKeysOption;\n\n /**\n * Creates a new BaseTabularStorage instance\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 protected schema: Schema,\n protected primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n this.clientProvidedKeys = clientProvidedKeys;\n const primaryKeyProps: Record<string, any> = {};\n const valueProps: Record<string, any> = {};\n const primaryKeySet = new Set(primaryKeyNames);\n\n // Split the schema properties into primary key and value properties\n for (const [key, typeDef] of Object.entries(schema.properties)) {\n if (primaryKeySet.has(key as keyof Schema[\"properties\"])) {\n primaryKeyProps[key] = Object.assign({}, typeDef);\n } else {\n valueProps[key] = Object.assign({}, typeDef);\n }\n }\n\n // Filter required array to only include primary key fields\n const primaryKeyRequired =\n schema.required?.filter((key) => primaryKeySet.has(key as keyof Schema[\"properties\"])) ?? [];\n // Filter required array to only include value fields\n const valueRequired =\n schema.required?.filter((key) => !primaryKeySet.has(key as keyof Schema[\"properties\"])) ?? [];\n\n this.primaryKeySchema = {\n type: \"object\",\n properties: primaryKeyProps,\n required: primaryKeyRequired,\n additionalProperties: false,\n } as DataPortSchemaObject;\n this.valueSchema = {\n type: \"object\",\n properties: valueProps,\n required: valueRequired,\n additionalProperties: false,\n } as DataPortSchemaObject;\n\n // validate all combined columns names are \"identifier\" names\n const combinedColumns = [...this.primaryKeyColumns(), ...this.valueColumns()];\n for (const column of combinedColumns) {\n if (typeof column !== \"string\") {\n throw new Error(\"Column names must be strings\");\n }\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(column)) {\n throw new Error(\n \"Column names must start with a letter and contain only letters, digits, and underscores\"\n );\n }\n }\n\n // Normalize searchable into array of arrays\n this.indexes = indexes.map((spec) => (Array.isArray(spec) ? spec : [spec])) as Array<\n Array<keyof Entity>\n >;\n\n // searchable is an array of compound keys, which are arrays of columns\n // clean up searchable array by removing any compoundkeys that are a prefix of another compoundkey\n // or a prefix of the primary key\n this.indexes = this.filterCompoundKeys(\n this.primaryKeyColumns() as unknown as Array<keyof Entity>,\n this.indexes\n );\n\n // Validate searchable columns\n for (const compoundIndex of this.indexes) {\n for (const column of compoundIndex) {\n if (\n !(column in this.primaryKeySchema.properties) &&\n !(column in this.valueSchema.properties)\n ) {\n throw new Error(\n `Searchable column ${String(column)} is not in the primary key schema or value schema`\n );\n }\n }\n }\n\n // Detect and validate auto-generated keys\n // Only the first primary key column can be auto-generated\n const autoGeneratedKeys: string[] = [];\n for (const key of primaryKeyNames) {\n const keyStr = String(key);\n const propDef = (schema.properties as any)[keyStr];\n if (propDef && typeof propDef === \"object\" && \"x-auto-generated\" in propDef) {\n if (propDef[\"x-auto-generated\"] === true) {\n autoGeneratedKeys.push(keyStr);\n }\n }\n }\n\n if (autoGeneratedKeys.length > 1) {\n throw new Error(\n `Multiple auto-generated keys detected: ${autoGeneratedKeys.join(\", \")}. ` +\n `Only the first primary key column can be auto-generated.`\n );\n }\n\n if (autoGeneratedKeys.length > 0) {\n const autoGenKeyName = autoGeneratedKeys[0];\n const firstPrimaryKey = String(primaryKeyNames[0]);\n\n if (autoGenKeyName !== firstPrimaryKey) {\n throw new Error(\n `Auto-generated key \"${autoGenKeyName}\" must be the first primary key column. ` +\n `Current first primary key is \"${firstPrimaryKey}\".`\n );\n }\n\n this.autoGeneratedKeyName = autoGenKeyName as keyof Entity;\n this.autoGeneratedKeyStrategy = this.determineGenerationStrategy(\n autoGenKeyName,\n schema.properties[autoGenKeyName as keyof Schema[\"properties\"]]\n );\n }\n }\n\n protected filterCompoundKeys(\n primaryKey: Array<keyof Entity>,\n potentialKeys: Array<keyof Entity>[]\n ): Array<keyof Entity>[] {\n // Function to check if one array is a prefix of another\n const isPrefix = (prefix: Array<keyof Entity>, arr: Array<keyof Entity>): boolean => {\n if (prefix.length > arr.length) return false;\n return prefix.every((val, index) => val === arr[index]);\n };\n\n // Sort potential keys by length\n potentialKeys.sort((a, b) => a.length - b.length);\n\n let filteredKeys: Array<keyof Entity>[] = [];\n\n for (let i = 0; i < potentialKeys.length; i++) {\n let key = potentialKeys[i];\n\n if (isPrefix(key, primaryKey)) continue;\n\n // Keep single-column indexes regardless of being a prefix\n if (key.length === 1) {\n filteredKeys.push(key);\n continue;\n }\n\n // Skip if the key is a prefix of a later key in the list\n let isRedundant = potentialKeys.some((otherKey, j) => j > i && isPrefix(key, otherKey));\n\n if (!isRedundant) {\n filteredKeys.push(key);\n }\n }\n\n return filteredKeys;\n }\n\n /**\n * Adds an event listener for a specific event\n * @param name The name of the event to listen for\n * @param fn The callback function to execute when the event occurs\n */\n on<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ) {\n this.events.on(name, fn);\n }\n\n /**\n * Removes an event listener for a specific event\n * @param name The name of the event to remove the listener from\n * @param fn The callback function to remove\n */\n off<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ) {\n this.events.off(name, fn);\n }\n\n /**\n * Adds an event listener that will only be called once\n * @param name The name of the event to listen for\n * @param fn The callback function to execute when the event occurs\n */\n once<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ) {\n this.events.once(name, fn);\n }\n\n /**\n * Emits an event with the specified name and arguments\n * @param name The name of the event to emit\n * @param args The arguments to pass to the event listeners\n */\n emit<Event extends TabularEventName>(\n name: Event,\n ...args: TabularEventParameters<Event, PrimaryKey, Entity>\n ) {\n this.events.emit(name, ...args);\n }\n\n /**\n * Returns when the event was emitted (promise form of once)\n * @param name The name of the event to check\n * @returns true if the event has listeners, false otherwise\n */\n waitOn<Event extends TabularEventName>(\n name: Event\n ): Promise<TabularEventParameters<Event, PrimaryKey, Entity>> {\n return this.events.waitOn(name) as Promise<TabularEventParameters<Event, PrimaryKey, Entity>>;\n }\n\n /**\n * Core abstract methods that must be implemented by concrete repositories\n */\n abstract put(value: InsertType): Promise<Entity>;\n abstract putBulk(values: InsertType[]): Promise<Entity[]>;\n abstract get(key: PrimaryKey): Promise<Entity | undefined>;\n abstract delete(key: PrimaryKey | Entity): Promise<void>;\n abstract getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined>;\n abstract deleteAll(): Promise<void>;\n abstract size(): Promise<number>;\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 abstract deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void>;\n\n /**\n * Queries entries matching the specified search criteria with optional ordering and limit.\n * Unlike `search`, this method does not require an index and supports comparison operators,\n * ORDER BY, and LIMIT.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering and limit options\n * @returns Array of matching entities or undefined if no matches found\n */\n abstract query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined>;\n\n /**\n * Abstract method to fetch a page of records.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Promise resolving to an array of entities or undefined if no records found\n */\n abstract getBulk(offset: number, limit: number): Promise<Entity[] | undefined>;\n\n /**\n * Async generator that yields records one at a time.\n * Uses getBulk internally to fetch pages of data.\n * @param pageSize - Number of records to fetch per page (default: 100)\n * @yields Individual entity records\n */\n async *records(pageSize: number = 100): AsyncGenerator<Entity, void, undefined> {\n if (pageSize <= 0) {\n throw new RangeError(`pageSize must be greater than 0, got ${pageSize}`);\n }\n let offset = 0;\n while (true) {\n const page = await this.getBulk(offset, pageSize);\n if (!page || page.length === 0) {\n break;\n }\n for (const entity of page) {\n yield entity;\n }\n if (page.length < pageSize) {\n break;\n }\n offset += pageSize;\n }\n }\n\n /**\n * Async generator that yields pages of records.\n * Uses getBulk internally to fetch pages of data.\n * @param pageSize - Number of records per page (default: 100)\n * @yields Arrays of entities\n */\n async *pages(pageSize: number = 100): AsyncGenerator<Entity[], void, undefined> {\n if (pageSize <= 0) {\n throw new RangeError(`pageSize must be greater than 0, got ${pageSize}`);\n }\n let offset = 0;\n while (true) {\n const page = await this.getBulk(offset, pageSize);\n if (!page || page.length === 0) {\n break;\n }\n yield page;\n if (page.length < pageSize) {\n break;\n }\n offset += pageSize;\n }\n }\n\n /**\n * Subscribes to changes in the repository (including remote changes).\n * Default implementation throws an error - override in subclasses that support subscriptions.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n * @throws Error if not implemented by the concrete repository\n */\n public subscribeToChanges(\n _callback: (change: TabularChangePayload<Entity>) => void,\n _options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\n `subscribeToChanges is not implemented for ${this.constructor.name}. ` +\n `All concrete repository implementations should override this method.`\n );\n }\n\n /**\n * Validates query parameters: criteria columns, options, and operator values.\n * @throws StorageEmptyCriteriaError if criteria is empty\n * @throws StorageInvalidLimitError if limit <= 0\n * @throws StorageValidationError if offset < 0\n * @throws StorageInvalidColumnError if any column name is not in the schema\n */\n protected validateQueryParams(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): void {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n\n if (criteriaKeys.length === 0) {\n throw new StorageEmptyCriteriaError();\n }\n\n if (options?.limit !== undefined && options.limit <= 0) {\n throw new StorageInvalidLimitError(options.limit);\n }\n\n if (options?.offset !== undefined && options.offset < 0) {\n throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);\n }\n\n // Validate criteria column names exist in schema\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new StorageInvalidColumnError(String(column));\n }\n // Validate operator values at runtime\n const criterion = criteria[column];\n if (isSearchCondition(criterion)) {\n const validOperators = [\"=\", \"<\", \"<=\", \">\", \">=\"];\n if (!validOperators.includes(criterion.operator)) {\n throw new StorageValidationError(\n `Invalid operator \"${criterion.operator}\". Must be one of: ${validOperators.join(\", \")}`\n );\n }\n }\n }\n\n // Validate orderBy column names\n if (options?.orderBy) {\n const validDirections = [\"ASC\", \"DESC\"];\n for (const { column, direction } of options.orderBy) {\n if (!(column in this.schema.properties)) {\n throw new StorageInvalidColumnError(String(column));\n }\n if (!validDirections.includes(direction)) {\n throw new StorageValidationError(\n `Invalid sort direction \"${direction}\". Must be \"ASC\" or \"DESC\"`\n );\n }\n }\n }\n }\n\n /**\n * Validates getAll options (orderBy, limit, offset) without criteria.\n */\n protected validateGetAllOptions(options?: QueryOptions<Entity>): void {\n if (!options) return;\n\n if (options.limit !== undefined && options.limit <= 0) {\n throw new StorageInvalidLimitError(options.limit);\n }\n\n if (options.offset !== undefined && options.offset < 0) {\n throw new StorageValidationError(`Query offset must be non-negative, got ${options.offset}`);\n }\n\n if (options.orderBy) {\n const validDirections = [\"ASC\", \"DESC\"];\n for (const { column, direction } of options.orderBy) {\n if (!(column in this.schema.properties)) {\n throw new StorageInvalidColumnError(String(column));\n }\n if (!validDirections.includes(direction)) {\n throw new StorageValidationError(\n `Invalid sort direction \"${direction}\". Must be \"ASC\" or \"DESC\"`\n );\n }\n }\n }\n }\n\n protected primaryKeyColumns(): Array<keyof PrimaryKey> {\n const columns: Array<keyof PrimaryKey> = [];\n for (const key of Object.keys(this.primaryKeySchema.properties)) {\n columns.push(key as keyof PrimaryKey);\n }\n return columns;\n }\n\n protected valueColumns(): Array<keyof Value> {\n const columns: Array<keyof Value> = [];\n for (const key of Object.keys(this.valueSchema.properties)) {\n columns.push(key as keyof Value);\n }\n return columns;\n }\n\n /**\n * Utility method to separate a combined object into its key and value components\n * for storage.\n * @param obj - Entity row object\n * @returns Separated key and value objects\n */\n protected separateKeyValueFromCombined(obj: Entity): { value: Value; key: PrimaryKey } {\n if (obj === null) {\n console.warn(\"Key is null\");\n return { value: {} as Value, key: {} as PrimaryKey };\n }\n if (typeof obj !== \"object\") {\n console.warn(\"Object is not an object\");\n return { value: {} as Value, key: {} as PrimaryKey };\n }\n const primaryKeyNames = this.primaryKeyColumns();\n const valueNames = this.valueColumns();\n const value: Partial<Value> = {};\n const key: Partial<PrimaryKey> = {};\n const objRecord = obj as Record<string, unknown>;\n for (const k of primaryKeyNames) {\n (key as Record<string, unknown>)[k as string] = objRecord[k as string];\n }\n for (const k of valueNames) {\n (value as Record<string, unknown>)[k as string] = objRecord[k as string];\n }\n\n return { value: value as Value, key: key as PrimaryKey };\n }\n\n /**\n * Generates a consistent string identifier for a given key.\n *\n * @param key - Primary key to convert\n * @returns Promise resolving to a string fingerprint of the key\n */\n protected async getKeyAsIdString(key: PrimaryKey): Promise<string> {\n return await makeFingerprint(key);\n }\n\n /**\n * Converts a primary key object into an ordered array based on the schema\n * This ensures consistent parameter ordering for storage operations\n * @param key - The primary key object to convert\n * @returns Array of key values ordered according to the schema\n */\n protected getPrimaryKeyAsOrderedArray(key: PrimaryKey): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const keyObj = key as Record<string, ValueOptionType>;\n for (const k in this.primaryKeySchema.properties) {\n if (k in keyObj) {\n orderedParams.push(keyObj[k]);\n } else {\n throw new Error(`Missing required primary key field: ${k}`);\n }\n }\n return orderedParams;\n }\n\n /**\n * Finds the best matching index for a set of search keys.\n * @param unorderedSearchKey - Unordered array of keys being searched, can be reordered\n * @returns Array of column names representing the best matching index, or undefined if no suitable index is found\n */\n public findBestMatchingIndex(\n unorderedSearchKey: Array<keyof Entity>\n ): Array<keyof Entity> | undefined {\n if (!unorderedSearchKey.length) return undefined;\n\n const allKeys: Array<keyof Entity>[] = [\n this.primaryKeyColumns() as unknown as Array<keyof Entity>,\n ...(this.indexes as Array<keyof Entity>[]),\n ];\n\n const searchKeySet = new Set(unorderedSearchKey);\n\n const hasMatchingPrefix = (index: Array<keyof Entity>): boolean => {\n // Check if the first column of the index is in our search keys\n return index.length > 0 && searchKeySet.has(index[0]);\n };\n\n let bestMatch: Array<keyof Entity> | undefined;\n let bestMatchScore = 0;\n\n for (const index of allKeys) {\n if (hasMatchingPrefix(index)) {\n // Calculate how many consecutive search keys we can use from this index\n let score = 0;\n for (const col of index) {\n if (!searchKeySet.has(col)) break;\n score++;\n }\n\n if (score > bestMatchScore) {\n bestMatch = index;\n bestMatchScore = score;\n }\n }\n }\n\n return bestMatch;\n }\n\n /**\n * Checks if this storage has an auto-generated key configured\n * @returns true if an auto-generated key is configured\n */\n protected hasAutoGeneratedKey(): boolean {\n return this.autoGeneratedKeyName !== null;\n }\n\n /**\n * Checks if a given column name is the auto-generated key\n * @param name - Column name to check\n * @returns true if the column is the auto-generated key\n */\n protected isAutoGeneratedKey(name: string): boolean {\n return this.autoGeneratedKeyName !== null && String(this.autoGeneratedKeyName) === name;\n }\n\n /**\n * Determines the generation strategy for an auto-generated key based on its type\n * @param columnName - Name of the column\n * @param typeDef - JSON Schema type definition for the column\n * @returns The generation strategy to use\n */\n protected determineGenerationStrategy(columnName: string, typeDef: any): KeyGenerationStrategy {\n // Extract the actual type if it's a union with null\n let actualType = typeDef;\n if (typeDef && typeof typeDef === \"object\") {\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n actualType = typeDef.anyOf.find((t: any) => t.type !== \"null\") || typeDef;\n } else if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n actualType = typeDef.oneOf.find((t: any) => t.type !== \"null\") || typeDef;\n }\n }\n\n if (typeof actualType !== \"object\") {\n return \"uuid\";\n }\n\n // Integer types use autoincrement\n if (actualType.type === \"integer\") {\n return \"autoincrement\";\n }\n\n // Default to UUID for strings and other types\n return \"uuid\";\n }\n\n /**\n * Generates a key value for client-side key generation\n * Override in storage classes that generate keys client-side (InMemory, IndexedDB for UUIDs)\n * SQL-based storages typically generate keys server-side\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): Promise<string | number> | string | number {\n throw new Error(\n `generateKeyValue not implemented for ${this.constructor.name}. ` +\n `Column: ${columnName}, Strategy: ${strategy}`\n );\n }\n\n /**\n * Sets up the database/storage for the repository.\n * Must be called before using any other methods (except for in-memory implementations).\n * Default implementation is a no-op - override in subclasses that need setup.\n */\n async setupDatabase(): Promise<void> {\n // no op by default\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n // no op by default\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n this.destroy();\n }\n\n [Symbol.dispose](): void {\n this.destroy();\n }\n}\n",
|
|
6
6
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { EventParameters } from \"@workglow/util\";\n\n// Generic type for possible value types in the repository\nexport type ValueOptionType = string | number | bigint | boolean | null | Uint8Array;\n\n/**\n * Type definitions for tabular repository events\n */\nexport type TabularEventListeners<PrimaryKey, Entity> = {\n put: (entity: Entity) => void;\n get: (key: PrimaryKey, entity: Entity | undefined) => void;\n query: (key: Partial<Entity>, entities: Entity[] | undefined) => void;\n delete: (key: keyof Entity) => void;\n clearall: () => void;\n};\n\nexport type TabularEventName = keyof TabularEventListeners<any, any>;\nexport type TabularEventListener<\n Event extends TabularEventName,\n PrimaryKey,\n Entity,\n> = TabularEventListeners<PrimaryKey, Entity>[Event];\n\nexport type TabularEventParameters<\n Event extends TabularEventName,\n PrimaryKey,\n Entity,\n> = EventParameters<TabularEventListeners<PrimaryKey, Entity>, Event>;\n\n/**\n * Type of change that occurred in the repository\n */\nexport type TabularChangeType = \"INSERT\" | \"UPDATE\" | \"DELETE\";\n\n/**\n * Payload describing a change to an entity\n */\nexport interface TabularChangePayload<Entity> {\n readonly type: TabularChangeType;\n readonly old?: Entity;\n readonly new?: Entity;\n}\n\n/**\n * Options for subscribing to changes in a tabular repository\n */\nexport interface TabularSubscribeOptions {\n /** Polling interval in milliseconds (used by implementations that rely on polling) */\n readonly pollingIntervalMs?: number;\n}\n\nexport type JSONValue =\n | string\n | number\n | boolean\n | null\n | JSONValue[]\n | { [key: string]: JSONValue };\n\n/**\n * Comparison operators for search and deleteSearch operations\n */\nexport type SearchOperator = \"=\" | \"<\" | \"<=\" | \">\" | \">=\";\n\n/**\n * A search condition with a value and comparison operator\n */\nexport interface SearchCondition<T> {\n readonly value: T;\n readonly operator: SearchOperator;\n}\n\n/**\n * Criteria for deleteSearch operations supporting multiple columns.\n * Each column can have either a direct value (equality) or a SearchCondition with an operator.\n *\n * @example\n * // Equality match\n * { category: \"electronics\" }\n *\n * // With operator\n * { createdAt: { value: date, operator: \"<\" } }\n *\n * // Multiple columns\n * { category: \"electronics\", createdAt: { value: date, operator: \"<\" } }\n */\nexport type DeleteSearchCriteria<Entity> = {\n readonly [K in keyof Entity]?: Entity[K] | SearchCondition<Entity[K]>;\n};\n\nexport type SearchCriteria<Entity> = DeleteSearchCriteria<Entity>;\n\nexport type SortDirection = \"ASC\" | \"DESC\";\n\nexport interface OrderBy<Entity> {\n readonly column: keyof Entity;\n readonly direction: SortDirection;\n}\n\nexport interface QueryOptions<Entity> {\n readonly orderBy?: ReadonlyArray<OrderBy<Entity>>;\n readonly limit?: number;\n readonly offset?: number;\n}\n\n/**\n * Type guard to check if a value is a SearchCondition\n */\nexport function isSearchCondition<T>(value: unknown): value is SearchCondition<T> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"value\" in value &&\n \"operator\" in value &&\n typeof (value as SearchCondition<T>).operator === \"string\"\n );\n}\n\n/**\n * Helper type to compute PrimaryKey while deferring Entity resolution.\n * Uses a conditional type to avoid forcing full Entity resolution at class definition time.\n *\n */\nexport type SimplifyPrimaryKey<\n Entity,\n KeyName extends ReadonlyArray<keyof any>,\n> = Entity extends any ? Pick<Entity, Extract<KeyName[number], keyof Entity>> : never;\n\n/**\n * Extracts property names marked as auto-generated from the schema.\n * Properties with `x-auto-generated: true` are considered auto-generated.\n */\nexport type AutoGeneratedKeys<Schema extends DataPortSchemaObject> = {\n [K in keyof Schema[\"properties\"]]: Schema[\"properties\"][K] extends { \"x-auto-generated\": true }\n ? K\n : never;\n}[keyof Schema[\"properties\"]];\n\n/**\n * Entity type for insertion - auto-generated keys are optional.\n * This allows clients to omit auto-generated keys when inserting entities.\n */\nexport type InsertEntity<Entity, AutoGenKeys> = Omit<Entity, AutoGenKeys & keyof Entity> &\n Partial<Pick<Entity, AutoGenKeys & keyof Entity>>;\n\n/**\n * Interface defining the contract for tabular storage repositories.\n * Provides a flexible interface for storing and retrieving data with typed\n * primary keys and values, and supports compound keys and partial key lookup.\n *\n * @typeParam Schema - The schema definition for the entity using JSON Schema\n * @typeParam PrimaryKeyNames - Array of property names that form the primary key\n */\nexport interface ITabularStorage<\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 InsertType = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> {\n // Core methods\n put(value: InsertType): Promise<Entity>;\n putBulk(values: InsertType[]): Promise<Entity[]>;\n get(key: PrimaryKey): Promise<Entity | undefined>;\n delete(key: PrimaryKey | Entity): Promise<void>;\n getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined>;\n deleteAll(): Promise<void>;\n size(): Promise<number>;\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 * @example\n * // Delete by equality\n * await repo.deleteSearch({ category: \"electronics\" });\n *\n * // Delete with operator\n * await repo.deleteSearch({ createdAt: { value: date, operator: \"<\" } });\n *\n * // Delete with multiple criteria (AND)\n * await repo.deleteSearch({ category: \"electronics\", value: { value: 100, operator: \"<\" } });\n */\n deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void>;\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 getBulk(offset: number, limit: number): Promise<Entity[] | undefined>;\n\n /**\n * Async generator that yields records one at a time.\n * @param pageSize - Number of records to fetch per page (default: 100)\n * @yields Individual entity records\n */\n records(pageSize?: number): AsyncGenerator<Entity, void, undefined>;\n\n /**\n * Async generator that yields pages of records.\n * @param pageSize - Number of records per page (default: 100)\n * @yields Arrays of entities\n */\n pages(pageSize?: number): AsyncGenerator<Entity[], void, undefined>;\n\n // Event handling methods\n on<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void;\n off<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void;\n emit<Event extends TabularEventName>(\n name: Event,\n ...args: TabularEventParameters<Event, PrimaryKey, Entity>\n ): void;\n once<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void;\n waitOn<Event extends TabularEventName>(\n name: Event\n ): Promise<TabularEventParameters<Event, PrimaryKey, Entity>>;\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n * Uses optimized index paths when possible, falls back to full scan otherwise.\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 query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined>;\n\n /**\n * Subscribes to changes in the repository (including remote changes).\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void;\n\n /**\n * Sets up the database/storage for the repository.\n * Must be called before using any other methods (except for in-memory implementations).\n * @returns Promise that resolves when setup is complete\n */\n setupDatabase(): Promise<void>;\n\n // Destroy the repository and frees up resources.\n destroy(): void;\n [Symbol.dispose](): void;\n [Symbol.asyncDispose](): Promise<void>;\n}\n\nexport type AnyTabularStorage = ITabularStorage<any, any, any, any, any>;\n",
|
|
7
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { BaseError } from \"@workglow/util\";\n\nexport class StorageError extends BaseError {\n static readonly type: string = \"StorageError\";\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class StorageValidationError extends StorageError {\n static readonly type: string = \"StorageValidationError\";\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class StorageEmptyCriteriaError extends StorageValidationError {\n static readonly type: string = \"StorageEmptyCriteriaError\";\n constructor() {\n super(\"Query criteria must not be empty. Use getAll() to retrieve all records.\");\n }\n}\n\nexport class StorageInvalidLimitError extends StorageValidationError {\n static readonly type: string = \"StorageInvalidLimitError\";\n constructor(limit: number) {\n super(`Query limit must be greater than 0, got ${limit}`);\n }\n}\n\nexport class StorageInvalidColumnError extends StorageValidationError {\n static readonly type: string = \"StorageInvalidColumnError\";\n constructor(column: string) {\n super(`Column \"${column}\" does not exist in the schema`);\n }\n}\n\nexport class StorageUnsupportedError extends StorageError {\n static readonly type: string = \"StorageUnsupportedError\";\n constructor(operation: string, backend: string) {\n super(`${operation} is not supported for ${backend}`);\n }\n}\n",
|
|
8
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, getLogger } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport { InMemoryTabularStorage } from \"./InMemoryTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n ITabularStorage,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const CACHED_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.cached\"\n);\n\n/**\n * A tabular repository wrapper that adds caching layer to a durable repository.\n * Uses InMemoryTabularStorage or SharedInMemoryTabularStorage as a cache\n * for faster access to frequently used data.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class CachedTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n public readonly cache: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private durable: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private cacheInitialized = false;\n private cacheInitPromise: Promise<void> | null = null;\n\n /**\n * Creates a new CachedTabularStorage instance\n * @param durable - The durable repository to use as the source of truth\n * @param cache - Optional cache repository (InMemoryTabularStorage or SharedInMemoryTabularStorage).\n * If not provided, a new InMemoryTabularStorage will be created.\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 durable: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>,\n cache?: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>,\n schema?: Schema,\n primaryKeyNames?: PrimaryKeyNames,\n indexes?: readonly (keyof Entity | readonly (keyof Entity)[])[],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n // Extract schema and primaryKeyNames from durable repository if not provided\n // Note: This is a limitation - we can't always extract these from an interface\n // So we require them to be provided or assume they match\n if (!schema || !primaryKeyNames) {\n throw new Error(\n \"Schema and primaryKeyNames must be provided when creating CachedTabularStorage\"\n );\n }\n\n super(schema, primaryKeyNames, indexes || [], clientProvidedKeys);\n this.durable = durable;\n\n // Create cache if not provided\n if (cache) {\n this.cache = cache;\n } else {\n this.cache = new InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>(\n schema,\n primaryKeyNames,\n indexes || [],\n clientProvidedKeys\n );\n }\n\n // Forward events from both cache and durable\n this.setupEventForwarding();\n }\n\n /**\n * Sets up event forwarding from cache and durable repositories\n */\n private setupEventForwarding(): void {\n // Forward cache events\n this.cache.on(\"put\", (entity) => {\n this.events.emit(\"put\", entity);\n });\n this.cache.on(\"get\", (key, entity) => {\n this.events.emit(\"get\", key, entity);\n });\n this.cache.on(\"query\", (key, entities) => {\n this.events.emit(\"query\", key, entities);\n });\n this.cache.on(\"delete\", (key) => {\n this.events.emit(\"delete\", key);\n });\n this.cache.on(\"clearall\", () => {\n this.events.emit(\"clearall\");\n });\n }\n\n /**\n * Initializes the cache by loading all data from the durable repository.\n * Uses a promise-based lock so concurrent callers await the same initialization.\n */\n private async initializeCache(): Promise<void> {\n if (this.cacheInitialized) return;\n\n if (this.cacheInitPromise) {\n return this.cacheInitPromise;\n }\n\n this.cacheInitPromise = (async () => {\n try {\n const all = await this.durable.getAll();\n if (all && all.length > 0) {\n await this.cache.putBulk(all);\n }\n this.cacheInitialized = true;\n } catch (error) {\n getLogger().warn(\"Failed to initialize cache from durable repository:\", { error });\n // Don't mark as initialized on error — allow retry on next access\n } finally {\n this.cacheInitPromise = null;\n }\n })();\n\n return this.cacheInitPromise;\n }\n\n /**\n * Stores a key-value pair in both cache and durable repository\n * @param value - The combined object to store\n * @returns The stored entity\n * @emits 'put' event with the stored entity when successful\n */\n async put(value: InsertType): Promise<Entity> {\n await this.initializeCache();\n\n // Write to durable first (source of truth)\n const result = await this.durable.put(value);\n\n // Then update cache\n await this.cache.put(result);\n\n return result;\n }\n\n /**\n * Stores multiple key-value pairs in both cache and durable repository\n * @param values - Array of combined objects to store\n * @returns Array of stored entities\n * @emits 'put' event for each value stored\n */\n async putBulk(values: InsertType[]): Promise<Entity[]> {\n await this.initializeCache();\n\n // Write to durable first (source of truth)\n const results = await this.durable.putBulk(values);\n\n // Then update cache\n await this.cache.putBulk(results);\n\n return results;\n }\n\n /**\n * Retrieves a value by its key, checking cache first, then durable repository\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n await this.initializeCache();\n\n // Try cache first\n let result = await this.cache.get(key);\n\n // If not in cache, get from durable and cache it\n if (result === undefined) {\n result = await this.durable.get(key);\n if (result) {\n await this.cache.put(result);\n }\n }\n\n return result;\n }\n\n /**\n * Deletes an entry from both cache and durable repository\n * @param value - The primary key object or entity of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.delete(value);\n\n // Then delete from cache\n await this.cache.delete(value);\n }\n\n /**\n * Removes all entries from both cache and durable repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.deleteAll();\n\n // Then delete from cache\n await this.cache.deleteAll();\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n await this.initializeCache();\n\n // Try cache first (without options for population check)\n let results = await this.cache.getAll();\n\n // If cache is empty, get from durable and populate cache\n if (!results || results.length === 0) {\n results = await this.durable.getAll();\n if (results && results.length > 0) {\n await this.cache.putBulk(results);\n }\n }\n\n // If options provided, apply them via the cache\n if (options && results && results.length > 0) {\n return await this.cache.getAll(options);\n }\n\n return results;\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n await this.initializeCache();\n\n // Get size from durable (source of truth)\n return await this.durable.size();\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 await this.initializeCache();\n\n // Delegate to durable storage (source of truth) to avoid inconsistency\n return await this.durable.getBulk(offset, limit);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering and limit.\n * Delegates to the cache (which has all data after initialization) for best performance.\n * Falls back to durable if cache returns no results.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering and limit 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 await this.initializeCache();\n return await this.cache.query(criteria, options);\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 await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.deleteSearch(criteria);\n\n // Then delete from cache\n await this.cache.deleteSearch(criteria);\n }\n\n /**\n * Invalidates the cache by clearing it and resetting initialization flag\n */\n async invalidateCache(): Promise<void> {\n await this.cache.deleteAll();\n this.cacheInitialized = false;\n }\n\n /**\n * Refreshes the cache by reloading all data from the durable repository\n */\n async refreshCache(): Promise<void> {\n await this.cache.deleteAll();\n this.cacheInitialized = false;\n await this.initializeCache();\n }\n\n /**\n * Subscribes to changes in the repository.\n * Delegates to the durable repository to detect changes (including from other sources).\n * Also updates the cache when changes are detected.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: any) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Subscribe to durable repository to detect all changes\n return this.durable.subscribeToChanges(async (change) => {\n // Update cache based on the change\n if (change.type === \"INSERT\" || change.type === \"UPDATE\") {\n if (change.new) {\n await this.cache.put(change.new);\n }\n } else if (change.type === \"DELETE\") {\n if (change.old) {\n await this.cache.delete(change.old);\n }\n }\n\n // Forward the change to the callback\n callback(change);\n }, options);\n }\n\n /**\n * Destroys the durable and cache repositories.\n */\n destroy(): void {\n this.durable.destroy();\n this.cache.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 { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const MEMORY_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.inMemory\"\n);\n\n/**\n * A generic in-memory key-value repository implementation.\n * Provides a simple, non-persistent storage solution suitable for testing and caching scenarios.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class InMemoryTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Internal storage using a Map with fingerprint strings as keys */\n values = new Map<string, Entity>();\n /** Counter for auto-incrementing integer keys */\n private autoIncrementCounter = 0;\n /** Tracks whether the last put was an insert (new key) or update (existing key) */\n private _lastPutWasInsert = false;\n\n /**\n * Creates a new InMemoryTabularStorage instance\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 schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n }\n\n /**\n * Sets up the database for the repository (no-op for in-memory)\n */\n async setupDatabase(): Promise<void> {\n // No setup needed for in-memory storage\n }\n\n /**\n * Generates a key value for auto-generated keys\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected generateKeyValue(columnName: string, strategy: KeyGenerationStrategy): string | number {\n if (strategy === \"autoincrement\") {\n return ++this.autoIncrementCounter;\n } else {\n return uuid4();\n }\n }\n\n /**\n * Stores a key-value pair in the repository\n * @param value - The combined object to store (may be missing auto-generated keys)\n * @returns The stored entity with all keys filled in\n * @emits 'put' event with the stored entity when successful\n */\n async put(value: InsertType): Promise<Entity> {\n let entityToStore = value as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = this.autoGeneratedKeyName as string;\n const clientProvidedValue = (value as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n // Always generate, ignore client value\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n // Always use client value, error if missing\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\" - generate only if client didn't provide\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy!);\n entityToStore = { ...value, [keyName]: generatedValue } as Entity;\n }\n }\n\n const { key } = this.separateKeyValueFromCombined(entityToStore);\n const id = await makeFingerprint(key);\n this._lastPutWasInsert = !this.values.has(id);\n this.values.set(id, entityToStore);\n this.events.emit(\"put\", entityToStore);\n return entityToStore;\n }\n\n /**\n * Stores multiple key-value pairs in the repository in a bulk operation\n * @param values - Array of combined objects to store (may be missing auto-generated keys)\n * @returns Array of stored entities with all keys filled in\n * @emits 'put' event for each value stored\n */\n async putBulk(values: InsertType[]): Promise<Entity[]> {\n return await Promise.all(values.map(async (value) => this.put(value)));\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const id = await makeFingerprint(key);\n const out = this.values.get(id);\n this.events.emit(\"get\", key, out);\n return out;\n }\n\n /**\n * Deletes an entry by its key\n * @param key - The primary key object of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const id = await makeFingerprint(key);\n this.values.delete(id);\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n this.values.clear();\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let all = Array.from(this.values.values());\n\n if (options?.orderBy && options.orderBy.length > 0) {\n all.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n all = all.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n all = all.slice(0, options.limit);\n }\n\n return all.length > 0 ? all : undefined;\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n return this.values.size;\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 all = Array.from(this.values.values());\n\n // Ensure deterministic ordering by sorting by primary key(s) before pagination\n all.sort((a, b) => {\n for (const key of this.primaryKeyNames) {\n const aVal = (a as Record<string, string | number>)[key as string];\n const bVal = (b as Record<string, string | number>)[key as string];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n }\n return 0;\n });\n\n const page = all.slice(offset, offset + limit);\n return page.length > 0 ? page : undefined;\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 // Convert to array first to avoid iterator issues when modifying the Map\n const entries = Array.from(this.values.entries());\n\n const entriesToDelete = entries.filter(([_, entity]) => {\n // All criteria must match (AND logic)\n for (const column of criteriaKeys) {\n const criterion = criteria[column];\n const columnValue = entity[column];\n\n if (isSearchCondition(criterion)) {\n const { value, operator } = criterion;\n // Cast needed for generic comparison operators across Entity value types\n const v = value as string | number;\n const cv = columnValue as string | number | null | undefined;\n switch (operator) {\n case \"=\":\n if (cv !== v) return false;\n break;\n case \"<\":\n if (cv === null || cv === undefined || !(cv < v)) return false;\n break;\n case \"<=\":\n if (cv === null || cv === undefined || !(cv <= v)) return false;\n break;\n case \">\":\n if (cv === null || cv === undefined || !(cv > v)) return false;\n break;\n case \">=\":\n if (cv === null || cv === undefined || !(cv >= v)) return false;\n break;\n default:\n return false;\n }\n } else {\n // Direct value means equality\n if (columnValue !== criterion) return false;\n }\n }\n return true;\n });\n\n // Delete the filtered entries and emit events for each\n for (const [id, entity] of entriesToDelete) {\n this.values.delete(id);\n const { key } = this.separateKeyValueFromCombined(entity);\n this.events.emit(\"delete\", key as keyof Entity);\n }\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\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n\n let results: Entity[] = Array.from(this.values.values()).filter((entity) => {\n for (const column of criteriaKeys) {\n const criterion = criteria[column];\n const columnValue = entity[column];\n\n if (isSearchCondition(criterion)) {\n const { value, operator } = criterion;\n const v = value as string | number;\n const cv = columnValue as string | number | null | undefined;\n switch (operator) {\n case \"=\":\n if (cv !== v) return false;\n break;\n case \"<\":\n if (cv === null || cv === undefined || !(cv < v)) return false;\n break;\n case \"<=\":\n if (cv === null || cv === undefined || !(cv <= v)) return false;\n break;\n case \">\":\n if (cv === null || cv === undefined || !(cv > v)) return false;\n break;\n case \">=\":\n if (cv === null || cv === undefined || !(cv >= v)) return false;\n break;\n default:\n return false;\n }\n } else {\n if (columnValue !== criterion) return false;\n }\n }\n return true;\n });\n\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n return result;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Since InMemory is both client and server, changes are detected via local events.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for in-memory)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n const handlePut = (entity: Entity) => {\n callback({ type: this._lastPutWasInsert ? \"INSERT\" : \"UPDATE\", new: entity });\n };\n\n const handleDelete = (_key: keyof Entity) => {\n callback({ type: \"DELETE\" });\n };\n\n const handleClearAll = () => {\n callback({ type: \"DELETE\" });\n };\n\n this.events.on(\"put\", handlePut);\n this.events.on(\"delete\", handleDelete);\n this.events.on(\"clearall\", handleClearAll);\n\n return () => {\n this.events.off(\"put\", handlePut);\n this.events.off(\"delete\", handleDelete);\n this.events.off(\"clearall\", handleClearAll);\n };\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n this.values.clear();\n }\n}\n",
|
|
10
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { StorageUnsupportedError } from \"./StorageError\";\n\nexport const HF_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.huggingface\"\n);\n\n/**\n * HuggingFace Dataset Viewer API response types\n */\ninterface HfFirstRowsResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n}\n\ninterface HfRowsResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n num_rows_total: number;\n num_rows_per_page: number;\n partial: boolean;\n}\n\ninterface HfFilterResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n num_rows_total: number;\n num_rows_per_page: number;\n partial: boolean;\n}\n\ninterface HfSizeResponse {\n size: {\n dataset: string;\n config: string;\n split: string;\n num_bytes_original_files: number;\n num_bytes_parquet_files: number;\n num_bytes_memory: number;\n num_rows: number;\n num_columns: number;\n };\n partial: boolean;\n}\n\n/**\n * Options for HuggingFaceTabularStorage\n */\nexport interface HuggingFaceTabularStorageOptions {\n /** HuggingFace API token for private datasets */\n token?: string;\n /** Base URL for the HuggingFace Dataset Viewer API */\n baseUrl?: string;\n /** Indexes for optimizing search operations */\n indexes?: readonly (keyof any | readonly (keyof any)[])[];\n}\n\n/**\n * Read-only tabular storage backed by HuggingFace Dataset Viewer API.\n * Supports both user-provided schemas and auto-detection from HF features.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class HuggingFaceTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private readonly dataset: string;\n private readonly config: string;\n private readonly split: string;\n private readonly token?: string;\n private readonly baseUrl: string;\n\n /**\n * Creates a new HuggingFaceTabularStorage instance\n * @param dataset - HuggingFace dataset name (e.g., \"cornell-movie-review-data/rotten_tomatoes\")\n * @param config - Dataset configuration (e.g., \"default\")\n * @param split - Dataset split (e.g., \"train\", \"test\", \"validation\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param options - Optional configuration including token, baseUrl, and indexes\n */\n constructor(\n dataset: string,\n config: string,\n split: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n options?: HuggingFaceTabularStorageOptions\n ) {\n super(\n schema,\n primaryKeyNames,\n (options?.indexes ?? []) as readonly (keyof Entity | readonly (keyof Entity)[])[],\n \"never\" // HF datasets don't support client-provided keys\n );\n this.dataset = dataset;\n this.config = config;\n this.split = split;\n this.token = options?.token;\n this.baseUrl = options?.baseUrl ?? \"https://datasets-server.huggingface.co\";\n }\n\n /**\n * Factory method to create a HuggingFaceTabularStorage instance with auto-detected schema.\n * Fetches the dataset features and converts them to a JSON Schema.\n *\n * @param dataset - HuggingFace dataset name\n * @param config - Dataset configuration\n * @param split - Dataset split\n * @param options - Optional configuration\n * @returns A new HuggingFaceTabularStorage instance with auto-detected schema\n */\n static async fromDataset<Entity = any>(\n dataset: string,\n config: string,\n split: string,\n options?: HuggingFaceTabularStorageOptions\n ): Promise<\n HuggingFaceTabularStorage<DataPortSchemaObject, readonly [\"row_idx\"], Entity, number, any, any>\n > {\n const baseUrl = options?.baseUrl ?? \"https://datasets-server.huggingface.co\";\n const token = options?.token;\n\n // Fetch first rows to get features\n const url = new URL(`${baseUrl}/first-rows`);\n url.searchParams.set(\"dataset\", dataset);\n url.searchParams.set(\"config\", config);\n url.searchParams.set(\"split\", split);\n\n const headers: Record<string, string> = {};\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n if (!response.ok) {\n throw new Error(\n `Failed to fetch dataset features: ${response.status} ${response.statusText}`\n );\n }\n\n const data: HfFirstRowsResponse = await response.json();\n\n // Convert HF features to JSON Schema\n const properties: Record<string, any> = {};\n const required: string[] = [];\n\n // Add row_idx as primary key (auto-generated by HF)\n properties[\"row_idx\"] = { type: \"integer\", \"x-auto-generated\": true };\n required.push(\"row_idx\");\n\n for (const feature of data.features) {\n const jsonSchema = hfFeatureToJsonSchema(feature.type);\n properties[feature.name] = jsonSchema;\n // HF datasets typically don't have null values unless specified\n required.push(feature.name);\n }\n\n const schema: DataPortSchemaObject = {\n type: \"object\",\n properties,\n required,\n additionalProperties: false,\n };\n\n return new HuggingFaceTabularStorage(\n dataset,\n config,\n split,\n schema,\n [\"row_idx\"] as const,\n options\n ) as any;\n }\n\n /**\n * Sets up the database by validating the dataset exists and schema matches\n */\n async setupDatabase(): Promise<void> {\n // Fetch first rows to validate dataset exists\n const data = await this.fetchApi<HfFirstRowsResponse>(\"/first-rows\", {});\n\n // Validate that schema columns match HF features (if schema was user-provided)\n const schemaColumns = Object.keys(this.schema.properties);\n const hfColumns = data.features.map((f) => f.name);\n\n // Check if row_idx is in schema (indicates auto-detected schema)\n const hasRowIdx = schemaColumns.includes(\"row_idx\");\n\n if (!hasRowIdx) {\n // User-provided schema - validate columns match\n for (const column of schemaColumns) {\n if (!hfColumns.includes(column) && !this.primaryKeyNames.includes(column as any)) {\n throw new Error(`Schema column \"${column}\" not found in HuggingFace dataset features`);\n }\n }\n }\n }\n\n /**\n * Retrieves a value by its key using the /filter endpoint\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const keyObj = this.separateKeyValueFromCombined({ ...key } as any).key;\n const whereConditions: string[] = [];\n\n for (const [k, v] of Object.entries(keyObj as Record<string, any>)) {\n if (typeof v === \"string\") {\n // Escape backslashes first, then single quotes\n const escaped = v.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${v}`);\n }\n }\n\n const where = whereConditions.join(\" AND \");\n const data = await this.fetchApi<HfFilterResponse>(\"/filter\", { where, limit: \"1\" });\n\n if (data.rows.length > 0) {\n const entity = this.rowToEntity(data.rows[0]);\n this.events.emit(\"get\", key, entity);\n return entity;\n }\n\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n\n /**\n * Retrieves all entities by paginating through the /rows endpoint\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n\n const allEntities: Entity[] = [];\n let offset = 0;\n const pageSize = 100; // HF max per request\n\n while (true) {\n const page = await this.getBulk(offset, pageSize);\n\n if (!page || page.length === 0) {\n break;\n }\n\n allEntities.push(...page);\n offset += page.length;\n\n // If we got fewer records than requested, we've reached the end\n if (page.length < pageSize) {\n break;\n }\n }\n\n if (allEntities.length === 0) return undefined;\n\n let results = allEntities;\n\n // Apply JS-side orderBy\n if (options?.orderBy && options.orderBy.length > 0) {\n results = [...results];\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n // Apply offset\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n return results.length > 0 ? results : undefined;\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 data = await this.fetchApi<HfRowsResponse>(\"/rows\", {\n offset: offset.toString(),\n length: Math.min(limit, 100).toString(), // HF max is 100 per request\n });\n\n if (data.rows.length === 0) {\n return undefined;\n }\n\n const entities: Entity[] = [];\n for (const row of data.rows) {\n entities.push(this.rowToEntity(row));\n }\n\n return entities;\n }\n\n /**\n * Returns the number of rows in the dataset using the /size endpoint\n */\n async size(): Promise<number> {\n const data = await this.fetchApi<HfSizeResponse>(\"/size\", {});\n return data.size.num_rows;\n }\n\n /**\n * Write operations are not supported - throws readonly error\n */\n async put(_value: InsertType): Promise<Entity> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Write operations are not supported - throws readonly error\n */\n async putBulk(_values: InsertType[]): Promise<Entity[]> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async delete(_value: PrimaryKey | Entity): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async deleteAll(): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Queries entities using the /filter endpoint for equality criteria.\n * Non-equality operators are not supported by the HuggingFace API.\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\n // Build WHERE clause — only equality is supported by HF API\n const whereConditions: string[] = [];\n for (const [k, v] of Object.entries(criteria)) {\n if (v === undefined || v === null) continue;\n if (isSearchCondition(v)) {\n if (v.operator !== \"=\") {\n throw new StorageUnsupportedError(\n `Operator \"${v.operator}\" in query`,\n \"HuggingFaceTabularStorage\"\n );\n }\n const val = v.value;\n if (typeof val === \"string\") {\n const escaped = val.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${val}`);\n }\n } else {\n if (typeof v === \"string\") {\n const escaped = v.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${v}`);\n }\n }\n }\n\n if (whereConditions.length === 0) {\n return undefined;\n }\n\n const where = whereConditions.join(\" AND \");\n const allEntities: Entity[] = [];\n let fetchOffset = 0;\n const fetchLimit = 100;\n\n while (true) {\n const data = await this.fetchApi<HfFilterResponse>(\"/filter\", {\n where,\n offset: fetchOffset.toString(),\n limit: fetchLimit.toString(),\n });\n\n for (const row of data.rows) {\n allEntities.push(this.rowToEntity(row));\n }\n\n fetchOffset += data.rows.length;\n\n if (fetchOffset >= data.num_rows_total || data.rows.length < fetchLimit) {\n break;\n }\n }\n\n let results = allEntities;\n\n // Apply JS-side orderBy\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n // Apply offset\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n if (results.length > 0) {\n this.events.emit(\"query\", criteria as Partial<Entity>, results);\n return results;\n } else {\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async deleteSearch(_criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Subscriptions are not supported - HF datasets are static\n */\n subscribeToChanges(\n _callback: (change: TabularChangePayload<Entity>) => void,\n _options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"HuggingFaceTabularStorage does not support subscriptions\");\n }\n\n /**\n * No resources to clean up\n */\n destroy(): void {\n // No-op - no resources to clean up\n }\n\n /**\n * Helper method to fetch from the HuggingFace Dataset Viewer API\n */\n private async fetchApi<T>(endpoint: string, params: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n url.searchParams.set(\"dataset\", this.dataset);\n url.searchParams.set(\"config\", this.config);\n url.searchParams.set(\"split\", this.split);\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n\n const headers: Record<string, string> = {};\n if (this.token) {\n headers[\"Authorization\"] = `Bearer ${this.token}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n if (!response.ok) {\n throw new Error(`HuggingFace API error: ${response.status} ${response.statusText}`);\n }\n\n return await response.json();\n }\n\n /**\n * Converts a HF row to an Entity\n */\n private rowToEntity(row: { row_idx: number; row: Record<string, any> }): Entity {\n return { row_idx: row.row_idx, ...row.row } as Entity;\n }\n}\n\n/**\n * Converts a HuggingFace feature type to a JSON Schema type definition\n */\nfunction hfFeatureToJsonSchema(feature: any): any {\n // Handle Value types\n if (feature._type === \"Value\") {\n switch (feature.dtype) {\n case \"string\":\n return { type: \"string\" };\n case \"int64\":\n case \"int32\":\n case \"int16\":\n case \"int8\":\n case \"uint64\":\n case \"uint32\":\n case \"uint16\":\n case \"uint8\":\n return { type: \"integer\" };\n case \"float64\":\n case \"float32\":\n case \"float16\":\n return { type: \"number\" };\n case \"bool\":\n return { type: \"boolean\" };\n default:\n return {}; // any type\n }\n }\n\n // Handle ClassLabel types\n if (feature._type === \"ClassLabel\") {\n return { type: \"integer\" };\n }\n\n // Handle Sequence types\n if (feature._type === \"Sequence\") {\n return {\n type: \"array\",\n items: hfFeatureToJsonSchema(feature.feature),\n };\n }\n\n // Handle other types as any\n return {};\n}\n",
|
|
7
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { BaseError } from \"@workglow/util\";\n\nexport class StorageError extends BaseError {\n static override readonly type: string = \"StorageError\";\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class StorageValidationError extends StorageError {\n static override readonly type: string = \"StorageValidationError\";\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class StorageEmptyCriteriaError extends StorageValidationError {\n static override readonly type: string = \"StorageEmptyCriteriaError\";\n constructor() {\n super(\"Query criteria must not be empty. Use getAll() to retrieve all records.\");\n }\n}\n\nexport class StorageInvalidLimitError extends StorageValidationError {\n static override readonly type: string = \"StorageInvalidLimitError\";\n constructor(limit: number) {\n super(`Query limit must be greater than 0, got ${limit}`);\n }\n}\n\nexport class StorageInvalidColumnError extends StorageValidationError {\n static override readonly type: string = \"StorageInvalidColumnError\";\n constructor(column: string) {\n super(`Column \"${column}\" does not exist in the schema`);\n }\n}\n\nexport class StorageUnsupportedError extends StorageError {\n static override readonly type: string = \"StorageUnsupportedError\";\n constructor(operation: string, backend: string) {\n super(`${operation} is not supported for ${backend}`);\n }\n}\n",
|
|
8
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, getLogger } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport { InMemoryTabularStorage } from \"./InMemoryTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n ITabularStorage,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const CACHED_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.cached\"\n);\n\n/**\n * A tabular repository wrapper that adds caching layer to a durable repository.\n * Uses InMemoryTabularStorage or SharedInMemoryTabularStorage as a cache\n * for faster access to frequently used data.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class CachedTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n public readonly cache: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private durable: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private cacheInitialized = false;\n private cacheInitPromise: Promise<void> | null = null;\n\n /**\n * Creates a new CachedTabularStorage instance\n * @param durable - The durable repository to use as the source of truth\n * @param cache - Optional cache repository (InMemoryTabularStorage or SharedInMemoryTabularStorage).\n * If not provided, a new InMemoryTabularStorage will be created.\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 durable: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>,\n cache?: ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>,\n schema?: Schema,\n primaryKeyNames?: PrimaryKeyNames,\n indexes?: readonly (keyof Entity | readonly (keyof Entity)[])[],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n // Extract schema and primaryKeyNames from durable repository if not provided\n // Note: This is a limitation - we can't always extract these from an interface\n // So we require them to be provided or assume they match\n if (!schema || !primaryKeyNames) {\n throw new Error(\n \"Schema and primaryKeyNames must be provided when creating CachedTabularStorage\"\n );\n }\n\n super(schema, primaryKeyNames, indexes || [], clientProvidedKeys);\n this.durable = durable;\n\n // Create cache if not provided\n if (cache) {\n this.cache = cache;\n } else {\n this.cache = new InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>(\n schema,\n primaryKeyNames,\n indexes || [],\n clientProvidedKeys\n );\n }\n\n // Forward events from both cache and durable\n this.setupEventForwarding();\n }\n\n /**\n * Sets up event forwarding from cache and durable repositories\n */\n private setupEventForwarding(): void {\n // Forward cache events\n this.cache.on(\"put\", (entity) => {\n this.events.emit(\"put\", entity);\n });\n this.cache.on(\"get\", (key, entity) => {\n this.events.emit(\"get\", key, entity);\n });\n this.cache.on(\"query\", (key, entities) => {\n this.events.emit(\"query\", key, entities);\n });\n this.cache.on(\"delete\", (key) => {\n this.events.emit(\"delete\", key);\n });\n this.cache.on(\"clearall\", () => {\n this.events.emit(\"clearall\");\n });\n }\n\n /**\n * Initializes the cache by loading all data from the durable repository.\n * Uses a promise-based lock so concurrent callers await the same initialization.\n */\n private async initializeCache(): Promise<void> {\n if (this.cacheInitialized) return;\n\n if (this.cacheInitPromise) {\n return this.cacheInitPromise;\n }\n\n this.cacheInitPromise = (async () => {\n try {\n const all = await this.durable.getAll();\n if (all && all.length > 0) {\n await this.cache.putBulk(all);\n }\n this.cacheInitialized = true;\n } catch (error) {\n getLogger().warn(\"Failed to initialize cache from durable repository:\", { error });\n // Don't mark as initialized on error — allow retry on next access\n } finally {\n this.cacheInitPromise = null;\n }\n })();\n\n return this.cacheInitPromise;\n }\n\n /**\n * Stores a key-value pair in both cache and durable repository\n * @param value - The combined object to store\n * @returns The stored entity\n * @emits 'put' event with the stored entity when successful\n */\n async put(value: InsertType): Promise<Entity> {\n await this.initializeCache();\n\n // Write to durable first (source of truth)\n const result = await this.durable.put(value);\n\n // Then update cache\n await this.cache.put(result);\n\n return result;\n }\n\n /**\n * Stores multiple key-value pairs in both cache and durable repository\n * @param values - Array of combined objects to store\n * @returns Array of stored entities\n * @emits 'put' event for each value stored\n */\n async putBulk(values: InsertType[]): Promise<Entity[]> {\n await this.initializeCache();\n\n // Write to durable first (source of truth)\n const results = await this.durable.putBulk(values);\n\n // Then update cache\n await this.cache.putBulk(results);\n\n return results;\n }\n\n /**\n * Retrieves a value by its key, checking cache first, then durable repository\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n await this.initializeCache();\n\n // Try cache first\n let result = await this.cache.get(key);\n\n // If not in cache, get from durable and cache it\n if (result === undefined) {\n result = await this.durable.get(key);\n if (result) {\n await this.cache.put(result);\n }\n }\n\n return result;\n }\n\n /**\n * Deletes an entry from both cache and durable repository\n * @param value - The primary key object or entity of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.delete(value);\n\n // Then delete from cache\n await this.cache.delete(value);\n }\n\n /**\n * Removes all entries from both cache and durable repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.deleteAll();\n\n // Then delete from cache\n await this.cache.deleteAll();\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n await this.initializeCache();\n\n // Try cache first (without options for population check)\n let results = await this.cache.getAll();\n\n // If cache is empty, get from durable and populate cache\n if (!results || results.length === 0) {\n results = await this.durable.getAll();\n if (results && results.length > 0) {\n await this.cache.putBulk(results);\n }\n }\n\n // If options provided, apply them via the cache\n if (options && results && results.length > 0) {\n return await this.cache.getAll(options);\n }\n\n return results;\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n await this.initializeCache();\n\n // Get size from durable (source of truth)\n return await this.durable.size();\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 await this.initializeCache();\n\n // Delegate to durable storage (source of truth) to avoid inconsistency\n return await this.durable.getBulk(offset, limit);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering and limit.\n * Delegates to the cache (which has all data after initialization) for best performance.\n * Falls back to durable if cache returns no results.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering and limit 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 await this.initializeCache();\n return await this.cache.query(criteria, options);\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 await this.initializeCache();\n\n // Delete from durable first (source of truth)\n await this.durable.deleteSearch(criteria);\n\n // Then delete from cache\n await this.cache.deleteSearch(criteria);\n }\n\n /**\n * Invalidates the cache by clearing it and resetting initialization flag\n */\n async invalidateCache(): Promise<void> {\n await this.cache.deleteAll();\n this.cacheInitialized = false;\n }\n\n /**\n * Refreshes the cache by reloading all data from the durable repository\n */\n async refreshCache(): Promise<void> {\n await this.cache.deleteAll();\n this.cacheInitialized = false;\n await this.initializeCache();\n }\n\n /**\n * Subscribes to changes in the repository.\n * Delegates to the durable repository to detect changes (including from other sources).\n * Also updates the cache when changes are detected.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n */\n override subscribeToChanges(\n callback: (change: any) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Subscribe to durable repository to detect all changes\n return this.durable.subscribeToChanges(async (change) => {\n // Update cache based on the change\n if (change.type === \"INSERT\" || change.type === \"UPDATE\") {\n if (change.new) {\n await this.cache.put(change.new);\n }\n } else if (change.type === \"DELETE\") {\n if (change.old) {\n await this.cache.delete(change.old);\n }\n }\n\n // Forward the change to the callback\n callback(change);\n }, options);\n }\n\n /**\n * Destroys the durable and cache repositories.\n */\n override destroy(): void {\n this.durable.destroy();\n this.cache.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 { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const MEMORY_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.inMemory\"\n);\n\n/**\n * A generic in-memory key-value repository implementation.\n * Provides a simple, non-persistent storage solution suitable for testing and caching scenarios.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class InMemoryTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Internal storage using a Map with fingerprint strings as keys */\n values = new Map<string, Entity>();\n /** Counter for auto-incrementing integer keys */\n private autoIncrementCounter = 0;\n /** Tracks whether the last put was an insert (new key) or update (existing key) */\n private _lastPutWasInsert = false;\n\n /**\n * Creates a new InMemoryTabularStorage instance\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 schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n }\n\n /**\n * Sets up the database for the repository (no-op for in-memory)\n */\n override async setupDatabase(): Promise<void> {\n // No setup needed for in-memory storage\n }\n\n /**\n * Generates a key value for auto-generated keys\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"autoincrement\") {\n return ++this.autoIncrementCounter;\n } else {\n return uuid4();\n }\n }\n\n /**\n * Stores a key-value pair in the repository\n * @param value - The combined object to store (may be missing auto-generated keys)\n * @returns The stored entity with all keys filled in\n * @emits 'put' event with the stored entity when successful\n */\n async put(value: InsertType): Promise<Entity> {\n let entityToStore = value as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = this.autoGeneratedKeyName as string;\n const clientProvidedValue = (value as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n // Always generate, ignore client value\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n // Always use client value, error if missing\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\" - generate only if client didn't provide\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy!);\n entityToStore = { ...value, [keyName]: generatedValue } as Entity;\n }\n }\n\n const { key } = this.separateKeyValueFromCombined(entityToStore);\n const id = await makeFingerprint(key);\n this._lastPutWasInsert = !this.values.has(id);\n this.values.set(id, entityToStore);\n this.events.emit(\"put\", entityToStore);\n return entityToStore;\n }\n\n /**\n * Stores multiple key-value pairs in the repository in a bulk operation\n * @param values - Array of combined objects to store (may be missing auto-generated keys)\n * @returns Array of stored entities with all keys filled in\n * @emits 'put' event for each value stored\n */\n async putBulk(values: InsertType[]): Promise<Entity[]> {\n return await Promise.all(values.map(async (value) => this.put(value)));\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const id = await makeFingerprint(key);\n const out = this.values.get(id);\n this.events.emit(\"get\", key, out);\n return out;\n }\n\n /**\n * Deletes an entry by its key\n * @param key - The primary key object of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const id = await makeFingerprint(key);\n this.values.delete(id);\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n this.values.clear();\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let all = Array.from(this.values.values());\n\n if (options?.orderBy && options.orderBy.length > 0) {\n all.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n all = all.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n all = all.slice(0, options.limit);\n }\n\n return all.length > 0 ? all : undefined;\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n return this.values.size;\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 all = Array.from(this.values.values());\n\n // Ensure deterministic ordering by sorting by primary key(s) before pagination\n all.sort((a, b) => {\n for (const key of this.primaryKeyNames) {\n const aVal = (a as Record<string, string | number>)[key as string];\n const bVal = (b as Record<string, string | number>)[key as string];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n }\n return 0;\n });\n\n const page = all.slice(offset, offset + limit);\n return page.length > 0 ? page : undefined;\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 // Convert to array first to avoid iterator issues when modifying the Map\n const entries = Array.from(this.values.entries());\n\n const entriesToDelete = entries.filter(([_, entity]) => {\n // All criteria must match (AND logic)\n for (const column of criteriaKeys) {\n const criterion = criteria[column];\n const columnValue = entity[column];\n\n if (isSearchCondition(criterion)) {\n const { value, operator } = criterion;\n // Cast needed for generic comparison operators across Entity value types\n const v = value as string | number;\n const cv = columnValue as string | number | null | undefined;\n switch (operator) {\n case \"=\":\n if (cv !== v) return false;\n break;\n case \"<\":\n if (cv === null || cv === undefined || !(cv < v)) return false;\n break;\n case \"<=\":\n if (cv === null || cv === undefined || !(cv <= v)) return false;\n break;\n case \">\":\n if (cv === null || cv === undefined || !(cv > v)) return false;\n break;\n case \">=\":\n if (cv === null || cv === undefined || !(cv >= v)) return false;\n break;\n default:\n return false;\n }\n } else {\n // Direct value means equality\n if (columnValue !== criterion) return false;\n }\n }\n return true;\n });\n\n // Delete the filtered entries and emit events for each\n for (const [id, entity] of entriesToDelete) {\n this.values.delete(id);\n const { key } = this.separateKeyValueFromCombined(entity);\n this.events.emit(\"delete\", key as keyof Entity);\n }\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\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n\n let results: Entity[] = Array.from(this.values.values()).filter((entity) => {\n for (const column of criteriaKeys) {\n const criterion = criteria[column];\n const columnValue = entity[column];\n\n if (isSearchCondition(criterion)) {\n const { value, operator } = criterion;\n const v = value as string | number;\n const cv = columnValue as string | number | null | undefined;\n switch (operator) {\n case \"=\":\n if (cv !== v) return false;\n break;\n case \"<\":\n if (cv === null || cv === undefined || !(cv < v)) return false;\n break;\n case \"<=\":\n if (cv === null || cv === undefined || !(cv <= v)) return false;\n break;\n case \">\":\n if (cv === null || cv === undefined || !(cv > v)) return false;\n break;\n case \">=\":\n if (cv === null || cv === undefined || !(cv >= v)) return false;\n break;\n default:\n return false;\n }\n } else {\n if (columnValue !== criterion) return false;\n }\n }\n return true;\n });\n\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n return result;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Since InMemory is both client and server, changes are detected via local events.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for in-memory)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n const handlePut = (entity: Entity) => {\n callback({ type: this._lastPutWasInsert ? \"INSERT\" : \"UPDATE\", new: entity });\n };\n\n const handleDelete = (_key: keyof Entity) => {\n callback({ type: \"DELETE\" });\n };\n\n const handleClearAll = () => {\n callback({ type: \"DELETE\" });\n };\n\n this.events.on(\"put\", handlePut);\n this.events.on(\"delete\", handleDelete);\n this.events.on(\"clearall\", handleClearAll);\n\n return () => {\n this.events.off(\"put\", handlePut);\n this.events.off(\"delete\", handleDelete);\n this.events.off(\"clearall\", handleClearAll);\n };\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n this.values.clear();\n }\n}\n",
|
|
10
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { StorageUnsupportedError } from \"./StorageError\";\n\nexport const HF_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.huggingface\"\n);\n\n/**\n * HuggingFace Dataset Viewer API response types\n */\ninterface HfFirstRowsResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n}\n\ninterface HfRowsResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n num_rows_total: number;\n num_rows_per_page: number;\n partial: boolean;\n}\n\ninterface HfFilterResponse {\n features: Array<{ feature_idx: number; name: string; type: any }>;\n rows: Array<{ row_idx: number; row: Record<string, any>; truncated_cells: any[] }>;\n num_rows_total: number;\n num_rows_per_page: number;\n partial: boolean;\n}\n\ninterface HfSizeResponse {\n size: {\n dataset: string;\n config: string;\n split: string;\n num_bytes_original_files: number;\n num_bytes_parquet_files: number;\n num_bytes_memory: number;\n num_rows: number;\n num_columns: number;\n };\n partial: boolean;\n}\n\n/**\n * Options for HuggingFaceTabularStorage\n */\nexport interface HuggingFaceTabularStorageOptions {\n /** HuggingFace API token for private datasets */\n token?: string;\n /** Base URL for the HuggingFace Dataset Viewer API */\n baseUrl?: string;\n /** Indexes for optimizing search operations */\n indexes?: readonly (keyof any | readonly (keyof any)[])[];\n}\n\n/**\n * Read-only tabular storage backed by HuggingFace Dataset Viewer API.\n * Supports both user-provided schemas and auto-detection from HF features.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class HuggingFaceTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private readonly dataset: string;\n private readonly config: string;\n private readonly split: string;\n private readonly token?: string;\n private readonly baseUrl: string;\n\n /**\n * Creates a new HuggingFaceTabularStorage instance\n * @param dataset - HuggingFace dataset name (e.g., \"cornell-movie-review-data/rotten_tomatoes\")\n * @param config - Dataset configuration (e.g., \"default\")\n * @param split - Dataset split (e.g., \"train\", \"test\", \"validation\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param options - Optional configuration including token, baseUrl, and indexes\n */\n constructor(\n dataset: string,\n config: string,\n split: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n options?: HuggingFaceTabularStorageOptions\n ) {\n super(\n schema,\n primaryKeyNames,\n (options?.indexes ?? []) as readonly (keyof Entity | readonly (keyof Entity)[])[],\n \"never\" // HF datasets don't support client-provided keys\n );\n this.dataset = dataset;\n this.config = config;\n this.split = split;\n this.token = options?.token;\n this.baseUrl = options?.baseUrl ?? \"https://datasets-server.huggingface.co\";\n }\n\n /**\n * Factory method to create a HuggingFaceTabularStorage instance with auto-detected schema.\n * Fetches the dataset features and converts them to a JSON Schema.\n *\n * @param dataset - HuggingFace dataset name\n * @param config - Dataset configuration\n * @param split - Dataset split\n * @param options - Optional configuration\n * @returns A new HuggingFaceTabularStorage instance with auto-detected schema\n */\n static async fromDataset<Entity = any>(\n dataset: string,\n config: string,\n split: string,\n options?: HuggingFaceTabularStorageOptions\n ): Promise<\n HuggingFaceTabularStorage<DataPortSchemaObject, readonly [\"row_idx\"], Entity, number, any, any>\n > {\n const baseUrl = options?.baseUrl ?? \"https://datasets-server.huggingface.co\";\n const token = options?.token;\n\n // Fetch first rows to get features\n const url = new URL(`${baseUrl}/first-rows`);\n url.searchParams.set(\"dataset\", dataset);\n url.searchParams.set(\"config\", config);\n url.searchParams.set(\"split\", split);\n\n const headers: Record<string, string> = {};\n if (token) {\n headers[\"Authorization\"] = `Bearer ${token}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n if (!response.ok) {\n throw new Error(\n `Failed to fetch dataset features: ${response.status} ${response.statusText}`\n );\n }\n\n const data: HfFirstRowsResponse = await response.json();\n\n // Convert HF features to JSON Schema\n const properties: Record<string, any> = {};\n const required: string[] = [];\n\n // Add row_idx as primary key (auto-generated by HF)\n properties[\"row_idx\"] = { type: \"integer\", \"x-auto-generated\": true };\n required.push(\"row_idx\");\n\n for (const feature of data.features) {\n const jsonSchema = hfFeatureToJsonSchema(feature.type);\n properties[feature.name] = jsonSchema;\n // HF datasets typically don't have null values unless specified\n required.push(feature.name);\n }\n\n const schema: DataPortSchemaObject = {\n type: \"object\",\n properties,\n required,\n additionalProperties: false,\n };\n\n return new HuggingFaceTabularStorage(\n dataset,\n config,\n split,\n schema,\n [\"row_idx\"] as const,\n options\n ) as any;\n }\n\n /**\n * Sets up the database by validating the dataset exists and schema matches\n */\n override async setupDatabase(): Promise<void> {\n // Fetch first rows to validate dataset exists\n const data = await this.fetchApi<HfFirstRowsResponse>(\"/first-rows\", {});\n\n // Validate that schema columns match HF features (if schema was user-provided)\n const schemaColumns = Object.keys(this.schema.properties);\n const hfColumns = data.features.map((f) => f.name);\n\n // Check if row_idx is in schema (indicates auto-detected schema)\n const hasRowIdx = schemaColumns.includes(\"row_idx\");\n\n if (!hasRowIdx) {\n // User-provided schema - validate columns match\n for (const column of schemaColumns) {\n if (!hfColumns.includes(column) && !this.primaryKeyNames.includes(column as any)) {\n throw new Error(`Schema column \"${column}\" not found in HuggingFace dataset features`);\n }\n }\n }\n }\n\n /**\n * Retrieves a value by its key using the /filter endpoint\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const keyObj = this.separateKeyValueFromCombined({ ...key } as any).key;\n const whereConditions: string[] = [];\n\n for (const [k, v] of Object.entries(keyObj as Record<string, any>)) {\n if (typeof v === \"string\") {\n // Escape backslashes first, then single quotes\n const escaped = v.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${v}`);\n }\n }\n\n const where = whereConditions.join(\" AND \");\n const data = await this.fetchApi<HfFilterResponse>(\"/filter\", { where, limit: \"1\" });\n\n if (data.rows.length > 0) {\n const entity = this.rowToEntity(data.rows[0]);\n this.events.emit(\"get\", key, entity);\n return entity;\n }\n\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n\n /**\n * Retrieves all entities by paginating through the /rows endpoint\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n\n const allEntities: Entity[] = [];\n let offset = 0;\n const pageSize = 100; // HF max per request\n\n while (true) {\n const page = await this.getBulk(offset, pageSize);\n\n if (!page || page.length === 0) {\n break;\n }\n\n allEntities.push(...page);\n offset += page.length;\n\n // If we got fewer records than requested, we've reached the end\n if (page.length < pageSize) {\n break;\n }\n }\n\n if (allEntities.length === 0) return undefined;\n\n let results = allEntities;\n\n // Apply JS-side orderBy\n if (options?.orderBy && options.orderBy.length > 0) {\n results = [...results];\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n // Apply offset\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n return results.length > 0 ? results : undefined;\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 data = await this.fetchApi<HfRowsResponse>(\"/rows\", {\n offset: offset.toString(),\n length: Math.min(limit, 100).toString(), // HF max is 100 per request\n });\n\n if (data.rows.length === 0) {\n return undefined;\n }\n\n const entities: Entity[] = [];\n for (const row of data.rows) {\n entities.push(this.rowToEntity(row));\n }\n\n return entities;\n }\n\n /**\n * Returns the number of rows in the dataset using the /size endpoint\n */\n async size(): Promise<number> {\n const data = await this.fetchApi<HfSizeResponse>(\"/size\", {});\n return data.size.num_rows;\n }\n\n /**\n * Write operations are not supported - throws readonly error\n */\n async put(_value: InsertType): Promise<Entity> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Write operations are not supported - throws readonly error\n */\n async putBulk(_values: InsertType[]): Promise<Entity[]> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async delete(_value: PrimaryKey | Entity): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async deleteAll(): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Queries entities using the /filter endpoint for equality criteria.\n * Non-equality operators are not supported by the HuggingFace API.\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\n // Build WHERE clause — only equality is supported by HF API\n const whereConditions: string[] = [];\n for (const [k, v] of Object.entries(criteria)) {\n if (v === undefined || v === null) continue;\n if (isSearchCondition(v)) {\n if (v.operator !== \"=\") {\n throw new StorageUnsupportedError(\n `Operator \"${v.operator}\" in query`,\n \"HuggingFaceTabularStorage\"\n );\n }\n const val = v.value;\n if (typeof val === \"string\") {\n const escaped = val.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${val}`);\n }\n } else {\n if (typeof v === \"string\") {\n const escaped = v.replace(/\\\\/g, \"\\\\\\\\\").replace(/'/g, \"\\\\'\");\n whereConditions.push(`${k}='${escaped}'`);\n } else {\n whereConditions.push(`${k}=${v}`);\n }\n }\n }\n\n if (whereConditions.length === 0) {\n return undefined;\n }\n\n const where = whereConditions.join(\" AND \");\n const allEntities: Entity[] = [];\n let fetchOffset = 0;\n const fetchLimit = 100;\n\n while (true) {\n const data = await this.fetchApi<HfFilterResponse>(\"/filter\", {\n where,\n offset: fetchOffset.toString(),\n limit: fetchLimit.toString(),\n });\n\n for (const row of data.rows) {\n allEntities.push(this.rowToEntity(row));\n }\n\n fetchOffset += data.rows.length;\n\n if (fetchOffset >= data.num_rows_total || data.rows.length < fetchLimit) {\n break;\n }\n }\n\n let results = allEntities;\n\n // Apply JS-side orderBy\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n // Apply offset\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n // Apply limit\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n if (results.length > 0) {\n this.events.emit(\"query\", criteria as Partial<Entity>, results);\n return results;\n } else {\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n }\n\n /**\n * Delete operations are not supported - throws readonly error\n */\n async deleteSearch(_criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n throw new Error(\"HuggingFaceTabularStorage is readonly\");\n }\n\n /**\n * Subscriptions are not supported - HF datasets are static\n */\n override subscribeToChanges(\n _callback: (change: TabularChangePayload<Entity>) => void,\n _options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"HuggingFaceTabularStorage does not support subscriptions\");\n }\n\n /**\n * No resources to clean up\n */\n override destroy(): void {\n // No-op - no resources to clean up\n }\n\n /**\n * Helper method to fetch from the HuggingFace Dataset Viewer API\n */\n private async fetchApi<T>(endpoint: string, params: Record<string, string>): Promise<T> {\n const url = new URL(`${this.baseUrl}${endpoint}`);\n url.searchParams.set(\"dataset\", this.dataset);\n url.searchParams.set(\"config\", this.config);\n url.searchParams.set(\"split\", this.split);\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n\n const headers: Record<string, string> = {};\n if (this.token) {\n headers[\"Authorization\"] = `Bearer ${this.token}`;\n }\n\n const response = await fetch(url.toString(), { headers });\n if (!response.ok) {\n throw new Error(`HuggingFace API error: ${response.status} ${response.statusText}`);\n }\n\n return await response.json();\n }\n\n /**\n * Converts a HF row to an Entity\n */\n private rowToEntity(row: { row_idx: number; row: Record<string, any> }): Entity {\n return { row_idx: row.row_idx, ...row.row } as Entity;\n }\n}\n\n/**\n * Converts a HuggingFace feature type to a JSON Schema type definition\n */\nfunction hfFeatureToJsonSchema(feature: any): any {\n // Handle Value types\n if (feature._type === \"Value\") {\n switch (feature.dtype) {\n case \"string\":\n return { type: \"string\" };\n case \"int64\":\n case \"int32\":\n case \"int16\":\n case \"int8\":\n case \"uint64\":\n case \"uint32\":\n case \"uint16\":\n case \"uint8\":\n return { type: \"integer\" };\n case \"float64\":\n case \"float32\":\n case \"float16\":\n return { type: \"number\" };\n case \"bool\":\n return { type: \"boolean\" };\n default:\n return {}; // any type\n }\n }\n\n // Handle ClassLabel types\n if (feature._type === \"ClassLabel\") {\n return { type: \"integer\" };\n }\n\n // Handle Sequence types\n if (feature._type === \"Sequence\") {\n return {\n type: \"array\",\n items: hfFeatureToJsonSchema(feature.feature),\n };\n }\n\n // Handle other types as any\n return {};\n}\n",
|
|
11
11
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n createServiceToken,\n globalServiceRegistry,\n registerInputResolver,\n ServiceRegistry,\n} from \"@workglow/util\";\nimport { AnyTabularStorage } from \"./ITabularStorage\";\n\n/**\n * Service token for the tabular repository registry\n * Maps repository IDs to ITabularStorage instances\n */\nexport const TABULAR_REPOSITORIES = createServiceToken<Map<string, AnyTabularStorage>>(\n \"storage.tabular.repositories\"\n);\n\n// Register default factory if not already registered\nif (!globalServiceRegistry.has(TABULAR_REPOSITORIES)) {\n globalServiceRegistry.register(\n TABULAR_REPOSITORIES,\n (): Map<string, AnyTabularStorage> => new Map(),\n true\n );\n}\n\n/**\n * Gets the global tabular repository registry\n * @returns Map of tabular repository ID to instance\n */\nexport function getGlobalTabularRepositories(): Map<string, AnyTabularStorage> {\n return globalServiceRegistry.get(TABULAR_REPOSITORIES);\n}\n\n/**\n * Registers a tabular repository globally by ID\n * @param id The unique identifier for this repository\n * @param repository The repository instance to register\n */\nexport function registerTabularRepository(id: string, repository: AnyTabularStorage): void {\n const repos = getGlobalTabularRepositories();\n repos.set(id, repository);\n}\n\n/**\n * Gets a tabular repository by ID from the global registry\n * @param id The repository identifier\n * @returns The repository instance or undefined if not found\n */\nexport function getTabularRepository(id: string): AnyTabularStorage | undefined {\n return getGlobalTabularRepositories().get(id);\n}\n\n/**\n * Resolves a repository ID to an instance from the registry.\n * Used by the input resolver system.\n */\nfunction resolveRepositoryFromRegistry(\n id: string,\n format: string,\n registry: ServiceRegistry\n): AnyTabularStorage {\n const repos = registry.has(TABULAR_REPOSITORIES)\n ? registry.get(TABULAR_REPOSITORIES)\n : getGlobalTabularRepositories();\n const repo = repos.get(id);\n if (!repo) {\n throw new Error(`Tabular storage \"${id}\" not found in registry`);\n }\n return repo;\n}\n\n// Register the repository resolver for format: \"storage:tabular\"\nregisterInputResolver(\"storage:tabular\", resolveRepositoryFromRegistry);\n",
|
|
12
12
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { getTelemetryProvider, SpanStatusCode } from \"@workglow/util\";\n\n/**\n * Executes an async function within a telemetry span.\n */\nexport async function traced<T>(\n spanName: string,\n storageName: string,\n fn: () => Promise<T>\n): Promise<T> {\n const telemetry = getTelemetryProvider();\n if (!telemetry.isEnabled) return fn();\n const span = telemetry.startSpan(spanName, {\n attributes: { \"workglow.storage.name\": storageName },\n });\n try {\n const result = await fn();\n span.setStatus(SpanStatusCode.OK);\n return result;\n } catch (err) {\n span.setStatus(SpanStatusCode.ERROR, err instanceof Error ? err.message : String(err));\n throw err;\n } finally {\n span.end();\n }\n}\n",
|
|
13
13
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type {\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n ITabularStorage,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularEventListener,\n TabularEventName,\n TabularEventParameters,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { traced } from \"../util/traced\";\n\n/**\n * Telemetry wrapper for any ITabularStorage implementation.\n * Creates spans for all storage operations.\n */\nexport class TelemetryTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n InsertType = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> implements ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, InsertType> {\n constructor(\n protected readonly storageName: string,\n protected readonly inner: ITabularStorage<\n Schema,\n PrimaryKeyNames,\n Entity,\n PrimaryKey,\n InsertType\n >\n ) {}\n\n put(value: InsertType): Promise<Entity> {\n return traced(\"workglow.storage.tabular.put\", this.storageName, () => this.inner.put(value));\n }\n\n putBulk(values: InsertType[]): Promise<Entity[]> {\n return traced(\"workglow.storage.tabular.putBulk\", this.storageName, () =>\n this.inner.putBulk(values)\n );\n }\n\n get(key: PrimaryKey): Promise<Entity | undefined> {\n return traced(\"workglow.storage.tabular.get\", this.storageName, () => this.inner.get(key));\n }\n\n delete(key: PrimaryKey | Entity): Promise<void> {\n return traced(\"workglow.storage.tabular.delete\", this.storageName, () =>\n this.inner.delete(key)\n );\n }\n\n getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n return traced(\"workglow.storage.tabular.getAll\", this.storageName, () =>\n this.inner.getAll(options)\n );\n }\n\n deleteAll(): Promise<void> {\n return traced(\"workglow.storage.tabular.deleteAll\", this.storageName, () =>\n this.inner.deleteAll()\n );\n }\n\n size(): Promise<number> {\n return traced(\"workglow.storage.tabular.size\", this.storageName, () => this.inner.size());\n }\n\n deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n return traced(\"workglow.storage.tabular.deleteSearch\", this.storageName, () =>\n this.inner.deleteSearch(criteria)\n );\n }\n\n getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n return traced(\"workglow.storage.tabular.getBulk\", this.storageName, () =>\n this.inner.getBulk(offset, limit)\n );\n }\n\n query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n return traced(\"workglow.storage.tabular.query\", this.storageName, () =>\n this.inner.query(criteria, options)\n );\n }\n\n // Forwarded directly (async generators, not worth tracing)\n records(pageSize?: number): AsyncGenerator<Entity, void, undefined> {\n return this.inner.records(pageSize);\n }\n\n pages(pageSize?: number): AsyncGenerator<Entity[], void, undefined> {\n return this.inner.pages(pageSize);\n }\n\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n return this.inner.subscribeToChanges(callback, options);\n }\n\n setupDatabase(): Promise<void> {\n return this.inner.setupDatabase();\n }\n\n destroy(): void {\n return this.inner.destroy();\n }\n\n [Symbol.dispose](): void {\n return this.inner[Symbol.dispose]();\n }\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.inner[Symbol.asyncDispose]();\n }\n\n // Event delegation — no telemetry needed\n on<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void {\n this.inner.on(name, fn);\n }\n\n off<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void {\n this.inner.off(name, fn);\n }\n\n emit<Event extends TabularEventName>(\n name: Event,\n ...args: TabularEventParameters<Event, PrimaryKey, Entity>\n ): void {\n this.inner.emit(name, ...args);\n }\n\n once<Event extends TabularEventName>(\n name: Event,\n fn: TabularEventListener<Event, PrimaryKey, Entity>\n ): void {\n this.inner.once(name, fn);\n }\n\n waitOn<Event extends TabularEventName>(\n name: Event\n ): Promise<TabularEventParameters<Event, PrimaryKey, Entity>> {\n return this.inner.waitOn(name);\n }\n}\n",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type { EventParameters } from \"@workglow/util\";\nimport type {\n AutoGeneratedKeys,\n InsertEntity,\n ITabularStorage,\n SimplifyPrimaryKey,\n TabularEventListeners,\n} from \"../tabular/ITabularStorage\";\n\nexport type AnyVectorStorage = IVectorStorage<any, any, any, any>;\n\n/**\n * Options for vector search operations\n */\nexport interface VectorSearchOptions<\n Metadata extends Record<string, unknown> | undefined = Record<string, unknown>,\n> {\n readonly topK?: number;\n readonly filter?: Partial<Metadata>;\n readonly scoreThreshold?: number;\n}\n\n/**\n * Options for hybrid search (vector + full-text)\n */\nexport interface HybridSearchOptions<\n Metadata extends Record<string, unknown> | undefined = Record<string, unknown>,\n> extends VectorSearchOptions<Metadata> {\n readonly textQuery: string;\n readonly vectorWeight?: number;\n}\n\n/**\n * Type definitions for document chunk vector repository events\n */\nexport interface VectorEventListeners<PrimaryKey, Entity> extends TabularEventListeners<\n PrimaryKey,\n Entity\n> {\n similaritySearch: (query: TypedArray, results: (Entity & { score: number })[]) => void;\n hybridSearch: (query: TypedArray, results: (Entity & { score: number })[]) => void;\n}\n\nexport type VectorEventName = keyof VectorEventListeners<any, any>;\nexport type VectorEventListener<\n Event extends VectorEventName,\n PrimaryKey,\n Entity,\n> = VectorEventListeners<PrimaryKey, Entity>[Event];\n\nexport type VectorEventParameters<\n Event extends VectorEventName,\n PrimaryKey,\n Entity,\n> = EventParameters<VectorEventListeners<PrimaryKey, Entity>, Event>;\n\n/**\n * Interface defining the contract for vector storage repositories.\n * These repositories store vector embeddings with metadata.\n * Extends ITabularStorage to provide standard storage operations,\n * plus vector-specific similarity search capabilities.\n * Supports various vector types including quantized formats.\n *\n * @typeParam Schema - The schema definition for the entity using JSON Schema\n * @typeParam PrimaryKeyNames - Array of property names that form the primary key\n * @typeParam Entity - The entity type\n */\nexport interface IVectorStorage<\n Metadata extends Record<string, unknown> | undefined,\n Schema extends DataPortSchemaObject,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]> = ReadonlyArray<\n keyof Schema[\"properties\"]\n >,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n InsertType = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> extends ITabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, InsertType> {\n /**\n * Get the vector dimension\n * @returns The vector dimension\n */\n getVectorDimensions(): number;\n\n /**\n * Search for similar vectors using similarity scoring\n * @param query - Query vector to compare against\n * @param options - Search options (topK, filter, scoreThreshold)\n * @returns Array of search results sorted by similarity (highest first)\n */\n similaritySearch(\n query: TypedArray,\n options?: VectorSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]>;\n\n /**\n * Hybrid search combining vector similarity with full-text search\n * This is optional and may not be supported by all implementations\n * @param query - Query vector to compare against\n * @param options - Hybrid search options including text query\n * @returns Array of search results sorted by combined relevance\n */\n hybridSearch?(\n query: TypedArray,\n options: HybridSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]>;\n}\n\n/**\n * TODO: Given a schema, return the vector column by searching for a property with a TypedArray format (or TypedArray:xxx format)\n */\n\nexport function getVectorProperty<Schema extends DataPortSchemaObject>(\n schema: Schema\n): keyof Schema[\"properties\"] | undefined {\n for (const [key, value] of Object.entries<JsonSchema>(schema.properties)) {\n if (\n typeof value !== \"boolean\" &&\n value.type === \"array\" &&\n (value.format === \"TypedArray\" || value.format?.startsWith(\"TypedArray:\"))\n ) {\n return key;\n }\n }\n return undefined;\n}\n\n/**\n * Given a schema, return the property which is an object with format \"metadata\"\n */\nexport function getMetadataProperty<Schema extends DataPortSchemaObject>(\n schema: Schema\n): keyof Schema[\"properties\"] | undefined {\n for (const [key, value] of Object.entries<JsonSchema>(schema.properties)) {\n if (typeof value !== \"boolean\" && value.type === \"object\" && value.format === \"metadata\") {\n return key;\n }\n }\n return undefined;\n}\n",
|
|
28
28
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type {\n AutoGeneratedKeys,\n InsertEntity,\n SimplifyPrimaryKey,\n} from \"../tabular/ITabularStorage\";\nimport { TelemetryTabularStorage } from \"../tabular/TelemetryTabularStorage\";\nimport { traced } from \"../util/traced\";\nimport type { HybridSearchOptions, IVectorStorage, VectorSearchOptions } from \"./IVectorStorage\";\n\n/**\n * Telemetry wrapper for any IVectorStorage implementation.\n * Extends TelemetryTabularStorage and adds spans for vector-specific operations.\n */\nexport class TelemetryVectorStorage<\n Metadata extends Record<string, unknown> | undefined,\n Schema extends DataPortSchemaObject,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]> = ReadonlyArray<\n keyof Schema[\"properties\"]\n >,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n InsertType = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n>\n extends TelemetryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, InsertType>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames, PrimaryKey, InsertType>\n{\n private readonly vectorInner: IVectorStorage<\n Metadata,\n Schema,\n Entity,\n PrimaryKeyNames,\n PrimaryKey,\n InsertType\n >;\n\n constructor(\n storageName: string,\n inner: IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames, PrimaryKey, InsertType>\n ) {\n super(storageName, inner);\n this.vectorInner = inner;\n }\n\n getVectorDimensions(): number {\n return this.vectorInner.getVectorDimensions();\n }\n\n similaritySearch(\n query: TypedArray,\n options?: VectorSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]> {\n return traced(\"workglow.storage.vector.similaritySearch\", this.storageName, () =>\n this.vectorInner.similaritySearch(query, options)\n );\n }\n\n hybridSearch(\n query: TypedArray,\n options: HybridSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]> {\n if (!this.vectorInner.hybridSearch) {\n throw new Error(\"hybridSearch is not supported by the underlying storage implementation\");\n }\n return traced(\"workglow.storage.vector.hybridSearch\", this.storageName, () =>\n this.vectorInner.hybridSearch!(query, options)\n );\n }\n}\n",
|
|
29
29
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { CredentialPutOptions, ICredentialStore } from \"@workglow/util\";\nimport { decrypt, encrypt } from \"@workglow/util\";\nimport type { IKvStorage } from \"../kv/IKvStorage\";\n\n/**\n * Serialized form of a credential stored in the KV backend\n */\ninterface StoredCredential {\n readonly encrypted: string;\n readonly iv: string;\n readonly label: string | undefined;\n readonly provider: string | undefined;\n readonly createdAt: string;\n readonly updatedAt: string;\n readonly expiresAt: string | undefined;\n}\n\n/**\n * Credential store that encrypts values with AES-256-GCM before persisting\n * them to an {@link IKvStorage} backend.\n *\n * Works with any KV backend (SQLite, PostgreSQL, IndexedDB, in-memory, etc.).\n * Uses the Web Crypto API (available in Node 20+, Bun, and browsers).\n *\n * @example\n * ```ts\n * import { SqliteKvStorage } from \"@workglow/storage\";\n *\n * const kv = new SqliteKvStorage(\":memory:\");\n * const store = new EncryptedKvCredentialStore(kv, \"my-encryption-key\");\n *\n * await store.put(\"openai-api-key\", \"sk-...\", { provider: \"openai\" });\n * const key = await store.get(\"openai-api-key\"); // \"sk-...\"\n * ```\n */\nexport class EncryptedKvCredentialStore implements ICredentialStore {\n /** Per-instance cache of derived CryptoKey instances keyed by base64(salt). */\n private readonly keyCache = new Map<string, CryptoKey>();\n\n constructor(\n private readonly kv: IKvStorage<string, StoredCredential>,\n private readonly passphrase: string\n ) {\n if (!passphrase) {\n throw new Error(\"EncryptedKvCredentialStore requires a non-empty passphrase.\");\n }\n }\n\n async get(key: string): Promise<string | undefined> {\n const raw = (await this.kv.get(key)) as StoredCredential | undefined;\n if (!raw) return undefined;\n\n if (raw.expiresAt && new Date(raw.expiresAt) <= new Date()) {\n await this.kv.delete(key);\n return undefined;\n }\n\n return decrypt(raw.encrypted, raw.iv, this.passphrase, this.keyCache);\n }\n\n async put(key: string, value: string, options?: CredentialPutOptions): Promise<void> {\n const now = new Date();\n const existing = (await this.kv.get(key)) as StoredCredential | undefined;\n\n const { encrypted, iv } = await encrypt(value, this.passphrase, this.keyCache);\n\n const stored: StoredCredential = {\n encrypted,\n iv,\n label: options?.label ?? existing?.label,\n provider: options?.provider ?? existing?.provider,\n createdAt: existing?.createdAt ?? now.toISOString(),\n updatedAt: now.toISOString(),\n expiresAt: options?.expiresAt ? options.expiresAt.toISOString() : existing?.expiresAt,\n };\n\n await this.kv.put(key, stored);\n }\n\n async delete(key: string): Promise<boolean> {\n const exists = (await this.kv.get(key)) !== undefined;\n if (exists) {\n await this.kv.delete(key);\n }\n return exists;\n }\n\n async has(key: string): Promise<boolean> {\n const raw = (await this.kv.get(key)) as StoredCredential | undefined;\n if (!raw) return false;\n\n if (raw.expiresAt && new Date(raw.expiresAt) <= new Date()) {\n await this.kv.delete(key);\n return false;\n }\n return true;\n }\n\n async keys(): Promise<readonly string[]> {\n const all = await this.kv.getAll();\n if (!all) return [];\n\n const now = new Date();\n const result: string[] = [];\n for (const entry of all) {\n if (entry.value.expiresAt && new Date(entry.value.expiresAt) <= now) {\n await this.kv.delete(entry.key);\n continue;\n }\n result.push(entry.key);\n }\n return result;\n }\n\n async deleteAll(): Promise<void> {\n await this.kv.deleteAll();\n }\n}\n",
|
|
30
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, getLogger, makeFingerprint, sleep, uuid4 } from \"@workglow/util\";\nimport { mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { PollingSubscriptionManager } from \"../util/PollingSubscriptionManager\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { StorageUnsupportedError } from \"./StorageError\";\n\nexport const FS_FOLDER_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.fsFolder\"\n);\n\n/**\n * A tabular repository implementation that uses the filesystem for storage.\n * Each row is stored as a separate JSON file in the specified directory.\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 FsFolderTabularStorage<\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 = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private folderPath: string;\n /** Counter for auto-incrementing integer keys */\n private autoIncrementCounter = 0;\n /** Shared polling subscription manager */\n private pollingManager: PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n\n /**\n * Creates a new FsFolderTabularStorage instance.\n *\n * @param folderPath - The directory path where the JSON files will be stored\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 - Note: indexes are not supported in this implementation.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n folderPath: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.folderPath = path.join(folderPath);\n }\n\n /**\n * Sets up the directory for the repository (creates directory)\n */\n async setupDirectory(): Promise<void> {\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch (error) {\n // CI system sometimes has issues temporarily\n await new Promise((resolve) => setTimeout(resolve, 0));\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch {\n // Ignore error if directory already exists\n }\n }\n }\n\n /**\n * Generates a key value for auto-generated keys\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected generateKeyValue(columnName: string, strategy: KeyGenerationStrategy): string | number {\n if (strategy === \"autoincrement\") {\n return ++this.autoIncrementCounter;\n } else {\n return uuid4();\n }\n }\n\n /**\n * Stores a row in the repository\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The stored entity\n * @emits 'put' event when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n let entityToStore = entity as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = this.autoGeneratedKeyName as string;\n const clientProvidedValue = (entity as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy!);\n entityToStore = { ...entity, [keyName]: generatedValue } as Entity;\n }\n }\n\n await this.setupDirectory();\n const filePath = await this.getFilePath(entityToStore);\n try {\n await writeFile(filePath, JSON.stringify(entityToStore));\n } catch (error) {\n // CI system sometimes has issues temporarily — retry once\n await sleep(1);\n try {\n await writeFile(filePath, JSON.stringify(entityToStore));\n } catch (retryError) {\n throw new Error(\n `Failed to write file \"${filePath}\" after retry: ${retryError instanceof Error ? retryError.message : String(retryError)}`,\n { cause: retryError }\n );\n }\n }\n this.events.emit(\"put\", entityToStore);\n return entityToStore;\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation\n * @param entities - Array of entities to store (may be missing auto-generated keys)\n * @returns Array of stored entities\n * @emits 'put' event for each entity stored\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n await this.setupDirectory();\n return await Promise.all(entities.map(async (entity) => this.put(entity)));\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n await this.setupDirectory();\n const filePath = await this.getFilePath(key);\n try {\n const buf = await readFile(filePath);\n const data = buf.toString(\"utf8\");\n const entity = JSON.parse(data) as Entity;\n this.events.emit(\"get\", key, entity);\n return entity;\n } catch (error) {\n this.events.emit(\"get\", key, undefined);\n return undefined; // File not found or read error\n }\n }\n\n /**\n * Deletes an entry by its key\n * @param key - The primary key object of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.setupDirectory();\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const filePath = await this.getFilePath(key);\n try {\n await rm(filePath);\n } catch (error) {\n console.error(\"Error deleting file\", filePath, error);\n }\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all rows stored in the repository\n * @returns Array of combined objects (rows) if found, undefined otherwise\n */\n async getAll(): Promise<Entity[] | undefined> {\n await this.setupDirectory();\n try {\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n if (jsonFiles.length === 0) {\n return undefined;\n }\n const results = await Promise.allSettled(\n jsonFiles.map(async (file) => {\n const buf = await readFile(path.join(this.folderPath, file));\n const content = buf.toString(\"utf8\");\n const data = JSON.parse(content) as Entity;\n return data;\n })\n );\n\n const values = results\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n return values.length > 0 ? values : undefined;\n } catch (error) {\n console.error(\"Error in getAll:\", error);\n throw error;\n }\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.setupDirectory();\n // Delete all files in the folder\n try {\n await rm(this.folderPath, { recursive: true, force: true });\n } catch (error) {\n console.error(\"Error deleting folder\", this.folderPath, error);\n await rm(this.folderPath, { recursive: true, force: true });\n }\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of stored rows\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n await this.setupDirectory();\n // Count all files in the folder ending in .json\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n return jsonFiles.length;\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 await this.setupDirectory();\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n\n if (jsonFiles.length === 0) {\n return undefined;\n }\n\n // Read all files in parallel, skipping corrupted files\n const results = await Promise.allSettled(\n jsonFiles.map(async (file) => {\n const filePath = path.join(this.folderPath, file);\n try {\n const content = await readFile(filePath, \"utf8\");\n return JSON.parse(content) as Entity;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to read or parse \"${filePath}\": ${message}`);\n }\n })\n );\n const allEntities: Entity[] = [];\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n allEntities.push(result.value);\n } else {\n getLogger().warn(`Skipping corrupted file in getBulk: ${result.reason?.message ?? result.reason}`);\n }\n }\n\n // Sort by primary key to ensure deterministic ordering\n // TODO: rethink this, it's not efficient to sort all entities every time\n allEntities.sort((a, b) => {\n for (const key of this.primaryKeyNames) {\n const aVal = (a as Record<string, string | number>)[key as string];\n const bVal = (b as Record<string, string | number>)[key as string];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n }\n return 0;\n });\n\n // Slice the sorted array to get the page\n const page = allEntities.slice(offset, offset + limit);\n return page.length > 0 ? page : undefined;\n }\n\n /**\n * Generates the full filesystem path for a given key.\n * @private\n */\n private async getFilePath(value: PrimaryKey | Entity): Promise<string> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const filename = await this.getKeyAsIdString(key);\n const fullPath = path.join(this.folderPath, `${filename}.json`);\n return fullPath;\n }\n\n /**\n * Query is not supported for filesystem repository.\n * @throws StorageUnsupportedError always\n */\n async query(\n _criteria: SearchCriteria<Entity>,\n _options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n throw new StorageUnsupportedError(\"query\", \"FsFolderTabularStorage\");\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Not supported for filesystem repository.\n *\n * @param _criteria - Object with column names as keys and values or SearchConditions\n * @throws Error always - deleteSearch is not supported for filesystem storage\n */\n async deleteSearch(_criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n throw new Error(\"deleteSearch is not supported for FsFolderTabularStorage\");\n }\n\n /**\n * Gets or creates the shared polling subscription manager.\n * This ensures all subscriptions share a single polling loop per interval.\n */\n private getPollingManager(): PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.pollingManager) {\n this.pollingManager = new PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n (a, b) => JSON.stringify(a) === JSON.stringify(b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n }\n );\n }\n return this.pollingManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since filesystem has no native change notification support.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDirectory() here to keep the method synchronous\n // The getAll() method in the polling manager will call setupDirectory() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getPollingManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n if (this.pollingManager) {\n this.pollingManager.destroy();\n this.pollingManager = null;\n }\n super.destroy();\n }\n}\n",
|
|
31
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n type TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { Pool } from \"@workglow/storage/postgres\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\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 Entity | readonly (keyof 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 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 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 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 let paramIndex = 1;\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 * 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 * 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 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 destroy(): void {\n super.destroy();\n }\n}\n",
|
|
32
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AutoGeneratedKeys,\n InsertEntity,\n SimplifyPrimaryKey,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\n// BaseTabularStorage is a tabular store that uses SQLite and Postgres use as common code\n\n/**\n * Base class for SQL-based tabular repositories that implements common functionality\n * for both SQLite and PostgreSQL database implementations.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport abstract class BaseSqlTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /**\n * Creates a new instance of BaseSqlTabularStorage\n * @param table - The name of the database table to use for storage\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 protected readonly table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.validateTableAndSchema();\n }\n\n /**\n * Maps JavaScript/TypeScript types to their corresponding SQL type\n * Must be implemented by derived classes for specific SQL dialects\n */\n protected abstract mapTypeToSQL(typeDef: JsonSchema): string;\n\n /**\n * Generates the SQL column definitions for primary key fields\n * @returns SQL string containing primary key column definitions\n */\n protected constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields\n * @returns SQL string containing value column definitions\n */\n protected 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 // Check if the property is nullable based on schema definition or if it's not required\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType}${nullable ? \" NULL\" : \" NOT NULL\"}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Determines if a schema type allows null values\n * @param typeDef - The schema type definition\n * @returns true if the type allows null values\n */\n protected isNullable(typeDef: JsonSchema): boolean {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n // Check for direct null type\n if (typeDef.type === \"null\") {\n return true;\n }\n\n // Check for type as an array that includes null (e.g., type: [\"null\", \"string\"])\n if (Array.isArray(typeDef.type)) {\n return typeDef.type.includes(\"null\");\n }\n\n // Check for union types that include null (anyOf)\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n return typeDef.anyOf.some((type: any) => type.type === \"null\");\n }\n\n // Check for union types that include null (oneOf)\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n return typeDef.oneOf.some((type: any) => type.type === \"null\");\n }\n\n return false;\n }\n\n /**\n * Returns a comma-separated list of primary key column names\n * @returns Formatted string of primary key column names\n */\n protected primaryKeyColumnList($delimiter: string = \"\"): string {\n return $delimiter + this.primaryKeyColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n }\n\n /**\n * Returns a comma-separated list of value column names\n * @returns Formatted string of value column names\n */\n protected valueColumnList($delimiter: string = \"\"): string {\n return $delimiter + this.valueColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n }\n\n /**\n * Gets the real underlying type from possibly union types\n * For example, for a union with null, this extracts the non-null type\n * @param typeDef - The schema to extract from\n * @returns The non-null type from the schema\n */\n protected getNonNullType(typeDef: JsonSchema): JsonSchema {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n const nonNullType = typeDef.anyOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n const nonNullType = typeDef.oneOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n return typeDef;\n }\n\n /**\n * Converts a value object into an ordered array based on the valueSchema\n * This ensures consistent parameter ordering for SQL queries\n * @param value - The value object to convert\n * @returns Array of values ordered according to the schema\n * @throws Error if a required field is missing\n */\n protected getValueAsOrderedArray(value: Value): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const valueAsRecord = value as Record<string, Entity[keyof Entity]>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (Object.prototype.hasOwnProperty.call(valueAsRecord, key)) {\n const val = valueAsRecord[key];\n // Convert undefined to null for optional fields\n if (val === undefined && !requiredSet.has(key)) {\n orderedParams.push(null);\n } else {\n orderedParams.push(this.jsToSqlValue(key, val));\n }\n } else {\n // If the field is required, throw an error\n if (requiredSet.has(key)) {\n throw new Error(`Missing required value field: ${key}`);\n }\n // If the field is optional, use null\n orderedParams.push(null);\n }\n }\n return orderedParams;\n }\n\n /**\n * Converts a primary key object into an ordered array based on the schema\n * This ensures consistent parameter ordering for storage operations\n * @param key - The primary key object to convert\n * @returns Array of key values ordered according to the schema\n */\n protected getPrimaryKeyAsOrderedArray(key: PrimaryKey): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const keyObj = key as Record<string, Entity[keyof Entity]>;\n for (const k of Object.keys(this.primaryKeySchema.properties)) {\n if (k in keyObj) {\n const value = keyObj[k];\n if (value === null) {\n throw new Error(`Primary key field ${k} cannot be null`);\n }\n orderedParams.push(this.jsToSqlValue(k, value));\n } else {\n throw new Error(`Missing required primary key field: ${k}`);\n }\n }\n return orderedParams;\n }\n\n protected jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as ValueOptionType;\n }\n\n // Handle null values for nullable columns\n if (value === null && this.isNullable(typeDef)) {\n return null;\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as ValueOptionType;\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (value instanceof Uint8Array) {\n return value;\n }\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value);\n }\n if (Array.isArray(value)) {\n return new Uint8Array(value);\n }\n return value as ValueOptionType;\n } else if (value instanceof Date) {\n // Convert all Date objects to ISO string regardless of type definition\n return value.toISOString();\n } else {\n return value as ValueOptionType;\n }\n }\n\n protected sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n // Get the type definition\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as Entity[keyof Entity];\n }\n\n // Handle null values\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as Entity[keyof Entity];\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value) as Entity[keyof Entity];\n }\n if (value instanceof Uint8Array) {\n return value as Entity[keyof Entity];\n }\n return value as Entity[keyof Entity];\n } else {\n return value as Entity[keyof Entity];\n }\n }\n\n /**\n * Validates table name and schema configurations\n * Checks for:\n * 1. Valid table name format\n * 2. Valid schema key names\n * 3. No duplicate keys between primary key and value schemas\n * This is a sanity check to make sure the table and schema are valid,\n * and to prevent dumb mistakes and mischevious behavior.\n * @throws Error if validation fails\n */\n protected validateTableAndSchema(): void {\n // Validate table name\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(this.table)) {\n throw new Error(\n \"Table name must start with a letter and contain only letters, digits, and underscores, got: \" +\n this.table\n );\n }\n\n // Validate schema keys\n const validateSchemaKeys = (schema: DataPortSchemaObject) => {\n for (const key in schema.properties) {\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) {\n throw new Error(\n \"Schema keys must start with a letter and contain only letters, digits, and underscores, got: \" +\n key\n );\n }\n }\n };\n\n validateSchemaKeys(this.primaryKeySchema);\n validateSchemaKeys(this.valueSchema);\n\n // Check for key name collisions between schemas\n const primaryKeys = new Set(Object.keys(this.primaryKeySchema.properties));\n const valueKeys = Object.keys(this.valueSchema.properties);\n const duplicates = valueKeys.filter((key) => primaryKeys.has(key));\n if (duplicates.length > 0) {\n throw new Error(`Duplicate keys found in schemas: ${duplicates.join(\", \")}`);\n }\n }\n}\n",
|
|
33
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Sqlite } from \"@workglow/storage/sqlite\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption, KeyGenerationStrategy } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\n// Define local type for SQL operations\ntype ExcludeDateKeyOptionType = Exclude<string | number | bigint, Date>;\n\nexport const SQLITE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.sqlite\"\n);\n\n// SqliteTabularStorage is a key-value store that uses SQLite as the backend for\n// in app data.\n\n/**\n * A SQLite-based key-value repository implementation.\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SqliteTabularStorage<\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 /** The SQLite database instance */\n private db: Sqlite.Database;\n\n /** Protected accessor for subclasses that need direct database access */\n protected get database(): Sqlite.Database {\n return this.db;\n }\n\n /**\n * Creates a new SQLite key-value repository\n * @param dbOrPath - Either a Database instance or a path to the SQLite database file\n * @param table - The name of the table to use for storage (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 dbOrPath: string | Sqlite.Database,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n if (typeof dbOrPath === \"string\") {\n this.db = new Sqlite.Database(dbOrPath);\n } else {\n this.db = dbOrPath;\n }\n }\n\n /**\n * Override to handle SQLite's INTEGER PRIMARY KEY for auto-increment\n */\n protected 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 with autoincrement strategy\n if (this.isAutoGeneratedKey(key) && this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // SQLite uses INTEGER PRIMARY KEY for auto-increment\n return `${$delimiter}${key}${$delimiter} INTEGER PRIMARY KEY AUTOINCREMENT`;\n }\n const sqlType = this.mapTypeToSQL(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Creates the database table if it doesn't exist with the defined schema.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n // For auto-generated INTEGER PRIMARY KEY, we don't use the PRIMARY KEY constraint separately\n const hasAutoIncrementKey =\n this.hasAutoGeneratedKey() && this.autoGeneratedKeyStrategy === \"autoincrement\";\n\n const sql = hasAutoIncrementKey\n ? `\n CREATE TABLE IF NOT EXISTS \\`${this.table}\\` (\n ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()}\n )\n `\n : `\n CREATE TABLE IF NOT EXISTS \\`${this.table}\\` (\n ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n this.db.exec(sql);\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 searchSpec of this.indexes) {\n // Handle both single column and compound indexes\n const columns = Array.isArray(searchSpec) ? searchSpec : [searchSpec];\n\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 this.db.exec(\n `CREATE INDEX IF NOT EXISTS \\`${indexName}\\` ON \\`${this.table}\\` (${columnList})`\n );\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Convert JS values to SQLite-compatible values. Ensures booleans are stored as 0/1.\n */\n protected jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n if (value !== null && value !== undefined && typeof value === \"object\") {\n // Handle special types that should be passed to base class\n if (value instanceof Date) {\n return super.jsToSqlValue(column, value);\n }\n if (value instanceof Uint8Array) {\n return super.jsToSqlValue(column, value);\n }\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return super.jsToSqlValue(column, value);\n }\n // Convert ALL other objects and arrays to JSON string\n return JSON.stringify(value) as ValueOptionType;\n }\n\n // Handle null values\n if (value === null) {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef && this.isNullable(typeDef)) {\n return null;\n }\n // If not nullable, fall through to base class\n }\n\n // Schema-based type handling for non-object/array values\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n const actualType = this.getNonNullType(typeDef);\n const isObject =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"object\");\n const isArray =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"array\");\n const isBoolean =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"boolean\");\n if (isBoolean) {\n if (typeof value === \"boolean\") return value ? 1 : 0;\n if (typeof value === \"number\") return value ? 1 : 0;\n if (typeof value === \"string\")\n return value === \"1\" || value.toLowerCase() === \"true\" ? 1 : 0;\n }\n // Note: Objects/arrays are already handled above by runtime check\n // This check is here for cases where schema says object but runtime value isn't\n if ((isObject || isArray) && value !== null && typeof value === \"object\") {\n // Double-check: if schema says object/array but wasn't caught by runtime check above\n if (\n !(value instanceof Date) &&\n !(value instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(value instanceof Buffer))\n ) {\n if (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype) {\n return JSON.stringify(value) as ValueOptionType;\n }\n }\n }\n }\n\n const result = super.jsToSqlValue(column, value);\n\n // Final safety check: ensure we never return an object or array\n // The base class should not return objects, but if it does, convert them\n if (result !== null && typeof result === \"object\") {\n // TypeScript now knows result is an object (not null), so we can use instanceof\n const resultObj = result as object;\n if (\n !(resultObj instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(resultObj instanceof Buffer))\n ) {\n // Convert any remaining objects/arrays to JSON string\n return JSON.stringify(resultObj) as ValueOptionType;\n }\n }\n\n return result;\n }\n\n /**\n * Convert SQLite values to JS values. Ensures 0/1 become booleans where schema says boolean.\n */\n protected 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 const isObject =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"object\");\n const isArray =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"array\");\n const isBoolean =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"boolean\");\n\n if (isBoolean) {\n if (typeof value === \"boolean\") return value as Entity[keyof Entity];\n if (typeof value === \"number\") return (value !== 0 ? true : false) as Entity[keyof Entity];\n if (typeof value === \"string\")\n return (\n value === \"1\" || value.toLowerCase() === \"true\" ? true : false\n ) as Entity[keyof Entity];\n }\n\n // Handle array and object types - parse JSON string back to object/array\n if (isArray || isObject) {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as Entity[keyof Entity];\n } catch (e) {\n // If parsing fails, return the value as-is (might be a string that looks like JSON)\n return value as Entity[keyof Entity];\n }\n }\n // If it's already an object/array (shouldn't happen, but handle gracefully)\n return value as Entity[keyof Entity];\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Maps TypeScript/JavaScript types to their SQLite column type equivalents\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 definition\n * @returns The corresponding SQLite column type\n */\n protected mapTypeToSQL(typeDef: JsonSchema): string {\n // Get the actual non-null type for proper mapping\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 \"BLOB\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TEXT\"; // SQLite doesn't have a native TIMESTAMP\n if (actualType.format === \"date\") return \"TEXT\";\n\n // For strings with max length constraints, we can still note this in the schema\n // even though SQLite doesn't enforce VARCHAR lengths\n if (typeof actualType.maxLength === \"number\") {\n return `TEXT /* VARCHAR(${actualType.maxLength}) */`;\n }\n\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // SQLite has limited numeric types, but we can use INTEGER for integers\n // and REAL for floating point numbers\n\n // The multipleOf property in JSON Schema specifies that a number must be a\n // multiple of a given value. When set to 1, it means the number must be a\n // whole number multiple of 1, which effectively means it must be an integer.\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n return \"INTEGER\";\n }\n\n return \"REAL\";\n\n case \"boolean\":\n // SQLite uses INTEGER 0/1 for boolean\n return \"INTEGER\";\n\n case \"array\":\n case \"object\":\n return \"TEXT /* JSON */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates a key value for string UUID keys\n * Integer keys are auto-generated by SQLite's INTEGER PRIMARY KEY\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected generateKeyValue(columnName: string, strategy: KeyGenerationStrategy): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by SQLite INTEGER PRIMARY KEY\n throw new Error(\n `SQLite autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a key-value pair in the database\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 when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n const db = this.db;\n let entityToInsert = entity as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const entityRecord = entity as Record<string, unknown>;\n const clientProvidedValue = entityRecord[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldUseClientValue = false;\n if (this.clientProvidedKeys === \"never\") {\n // Always generate, ignore client value\n shouldUseClientValue = false;\n } else if (this.clientProvidedKeys === \"always\") {\n // Always use client value, error if missing\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" 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 // For UUID strategy, generate client-side if needed\n if (this.autoGeneratedKeyStrategy === \"uuid\" && !shouldUseClientValue) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n entityToInsert = { ...entity, [keyName]: generatedValue } as Entity;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\" && shouldUseClientValue) {\n // Client provided UUID, use it\n entityToInsert = entity as unknown as Entity;\n }\n // For autoincrement strategy, we handle it differently below\n }\n\n // Determine which columns to include in INSERT\n let columnsToInsert: string[] = [];\n let paramsToInsert: ValueOptionType[] = [];\n\n // Handle primary key columns\n const pkColumns = this.primaryKeyColumns();\n for (const col of pkColumns) {\n const colStr = String(col);\n // Skip autoincrement keys that should be generated by database\n if (\n this.isAutoGeneratedKey(colStr) &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n this.clientProvidedKeys !== \"always\"\n ) {\n const insertRecord = entityToInsert as Record<string, unknown>;\n const clientProvidedValue = insertRecord[colStr];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n if (this.clientProvidedKeys === \"if-missing\" && hasClientValue) {\n // Client provided value for autoincrement key in \"if-missing\" mode\n columnsToInsert.push(colStr);\n paramsToInsert.push(\n this.jsToSqlValue(colStr, clientProvidedValue as Entity[keyof Entity])\n );\n }\n // Otherwise skip it - let SQLite generate\n continue;\n }\n columnsToInsert.push(colStr);\n const value = (entityToInsert as Record<string, unknown>)[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n // Handle value columns\n const valueColumns = this.valueColumns();\n const insertRecord = entityToInsert as Record<string, unknown>;\n for (const col of valueColumns) {\n const colStr = String(col);\n columnsToInsert.push(colStr);\n const value = insertRecord[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(() => \"?\").join(\", \");\n\n const sql = `\n INSERT OR REPLACE INTO \\`${this.table}\\` (${columnList})\n VALUES (${placeholders})\n RETURNING *\n `;\n const stmt = db.prepare(sql);\n\n const params = paramsToInsert;\n\n // CRITICAL: Ensure all params are SQLite-compatible before binding\n // SQLite only accepts: string, number, bigint, boolean, null, Uint8Array\n for (let i = 0; i < params.length; i++) {\n let param = params[i];\n\n // Convert undefined to null\n if (param === undefined) {\n params[i] = null;\n continue;\n }\n\n // Convert objects/arrays to JSON string (except Uint8Array and Buffer)\n if (param !== null && typeof param === \"object\") {\n const paramObj = param as object;\n if (paramObj instanceof Uint8Array) {\n // Uint8Array is valid, keep as-is\n continue;\n }\n if (typeof Buffer !== \"undefined\" && paramObj instanceof Buffer) {\n // Buffer should be handled by jsToSqlValue, but convert to Uint8Array just in case\n params[i] = new Uint8Array(paramObj) as ValueOptionType;\n continue;\n }\n // Convert ALL other objects/arrays to JSON string\n try {\n params[i] = JSON.stringify(paramObj) as ValueOptionType;\n } catch (e) {\n throw new Error(\n `Failed to stringify param at index ${i} for column binding: ${String(e)}`\n );\n }\n continue;\n }\n }\n\n // Final validation - ensure no objects/arrays remain and log for debugging\n const invalidParams: Array<{ index: number; type: string; value: any }> = [];\n for (let i = 0; i < params.length; i++) {\n const param = params[i];\n // Check if it's a valid SQLite type\n if (\n param === null ||\n param === undefined ||\n typeof param === \"string\" ||\n typeof param === \"number\" ||\n typeof param === \"boolean\" ||\n typeof param === \"bigint\"\n ) {\n // Valid primitive types\n continue;\n }\n\n // For objects, check if it's Uint8Array or Buffer\n if (typeof param === \"object\") {\n const paramObj = param as object;\n if (\n paramObj instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && paramObj instanceof Buffer)\n ) {\n // Valid object types\n continue;\n }\n // Invalid object type\n invalidParams.push({ index: i, type: typeof param, value: param });\n } else {\n // Invalid type\n invalidParams.push({ index: i, type: typeof param, value: param });\n }\n }\n\n if (invalidParams.length > 0) {\n console.error(\"Invalid params detected:\", invalidParams);\n console.error(\n \"All params:\",\n params.map((p, i) => ({ i, type: typeof p, value: p, isArray: Array.isArray(p) }))\n );\n throw new Error(\n `Invalid SQLite params detected at indices: ${invalidParams.map((p) => p.index).join(\", \")}`\n );\n }\n\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const k in this.schema.properties) {\n updatedRecord[k] = this.sqlToJsValue(k, updatedRecord[k] as ValueOptionType);\n }\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple key-value pairs in the database in a bulk operation\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 // Each put() call will handle auto-generated keys appropriately\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 const db = this.db;\n\n // For SQLite bulk inserts with RETURNING, we need to do them individually\n // or use a transaction with multiple INSERT statements\n const updatedEntities: Entity[] = [];\n\n // Use a transaction for better performance\n const transaction = db.transaction((entitiesToInsert: any[]) => {\n for (const entity of entitiesToInsert) {\n const { key, value } = this.separateKeyValueFromCombined(entity);\n const sql = `\n INSERT OR REPLACE INTO \\`${\n this.table\n }\\` (${this.primaryKeyColumnList()} ${this.valueColumnList() ? \", \" + this.valueColumnList() : \"\"})\n VALUES (\n ${this.primaryKeyColumns()\n .map(() => \"?\")\n .join(\", \")}\n ${\n this.valueColumns().length > 0\n ? \", \" +\n this.valueColumns()\n .map(() => \"?\")\n .join(\", \")\n : \"\"\n }\n )\n RETURNING *\n `;\n const stmt = db.prepare(sql);\n const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);\n const valueParams = this.getValueAsOrderedArray(value);\n const params = [...primaryKeyParams, ...valueParams];\n\n // Ensure all params are SQLite-compatible (same validation as put method)\n for (let i = 0; i < params.length; i++) {\n let param = params[i];\n if (param === undefined) {\n params[i] = null;\n } else if (param !== null && typeof param === \"object\") {\n // TypeScript now knows param is an object (not null), so we can use instanceof\n const paramObj: object = param as object;\n if (\n !(paramObj instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(paramObj instanceof Buffer))\n ) {\n params[i] = JSON.stringify(paramObj) as ValueOptionType;\n }\n }\n }\n\n // @ts-ignore\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n for (const k in this.schema.properties) {\n // @ts-ignore\n updatedEntity[k] = this.sqlToJsValue(k, updatedEntity[k]);\n }\n\n updatedEntities.push(updatedEntity);\n }\n });\n\n transaction(entities);\n\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 key\n * @param key - The primary key object to look up\n * @returns The stored value or undefined if not found\n * @emits 'get' event 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((key) => `\\`${key}\\` = ?`)\n .join(\" AND \");\n\n const sql = `\n SELECT * FROM \\`${this.table}\\` WHERE ${whereClauses}\n `;\n const stmt = db.prepare(sql);\n const params = this.getPrimaryKeyAsOrderedArray(key);\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n const value: Entity | null = stmt.get(...(params as ValueOptionType[]));\n if (value) {\n const row = value as Record<string, unknown>;\n for (const k in this.schema.properties) {\n row[k] = this.sqlToJsValue(k, row[k] as ValueOptionType);\n }\n this.events.emit(\"get\", key, value);\n return value;\n } else {\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n }\n\n /**\n * Deletes a key-value pair from the database\n * @param key - The primary key object to delete\n * @emits 'delete' event when successful\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = this.db;\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((key) => `${key} = ?`)\n .join(\" AND \");\n const params = this.getPrimaryKeyAsOrderedArray(key);\n const stmt = db.prepare(`DELETE FROM \\`${this.table}\\` WHERE ${whereClauses}`);\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n stmt.run(...(params as ValueOptionType[]));\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 ?`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n if (options.limit === undefined) {\n sql += ` LIMIT -1`;\n }\n sql += ` OFFSET ?`;\n params.push(options.offset);\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore\n const value = params.length > 0 ? stmt.all(...params) : stmt.all();\n if (!value.length) return undefined;\n // Convert all columns according to schema for each row\n for (const row of value) {\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 return value as Entity[];\n }\n\n /**\n * Deletes all entries from the database table\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n const db = this.db;\n db.exec(`DELETE FROM \\`${this.table}\\``);\n this.events.emit(\"clearall\");\n }\n\n /**\n * Gets the total number of entries in the database table\n * @returns The count of entries\n */\n async size(): Promise<number> {\n const db = this.db;\n const stmt = db.prepare<unknown[], { count: number }>(`\n SELECT COUNT(*) AS count FROM \\`${this.table}\\`\n `);\n return stmt.get()?.count || 0;\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 stmt = db.prepare<[number, number], Entity>(`\n SELECT * FROM \\`${this.table}\\` ORDER BY ${orderByClause} LIMIT ? OFFSET ?\n `);\n const rows = stmt.all(limit, offset);\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n // Convert all columns according to schema for each row (consistent with getAll)\n for (const row of 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\n return rows;\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\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} ?`);\n params.push(this.jsToSqlValue(column as string, value));\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 const stmt = db.prepare(`DELETE FROM \\`${this.table}\\` WHERE ${whereClause}`);\n // @ts-ignore\n stmt.run(...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 ?`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n if (options.limit === undefined) {\n sql += ` LIMIT -1`;\n }\n sql += ` OFFSET ?`;\n params.push(options.offset);\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore\n const result = stmt.all(...params) as Entity[];\n\n if (result.length > 0) {\n for (const row of result) {\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);\n return result;\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Subscribes to changes in the repository.\n * NOT IMPLEMENTED for SQLite storage.\n *\n * @throws Error always - subscribeToChanges is not supported for SQLite storage\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"subscribeToChanges is not supported for SqliteTabularStorage\");\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n super.destroy();\n }\n}\n",
|
|
34
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase 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 SupabaseTabularStorage<\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 private client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\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 client: SupabaseClient,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client;\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 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 const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\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 const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\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 // 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 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 constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\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 Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected 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 numeric types - Supabase 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 * 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 // Handle auto-generated keys\n let entityToInsert = { ...entity };\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const entityRecord = entity as Record<string, unknown>;\n const clientProvidedValue = entityRecord[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldOmitKey = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldOmitKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldOmitKey = false;\n } else {\n // \"if-missing\" - omit key if client didn't provide it\n shouldOmitKey = !hasClientValue;\n }\n\n if (shouldOmitKey) {\n // Omit the auto-generated key so Supabase generates it\n delete (entityToInsert as Record<string, unknown>)[keyName];\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const normalizedEntity = { ...entityToInsert } as Record<string, unknown>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in normalizedEntity) || normalizedEntity[key] === undefined) {\n if (!requiredSet.has(key)) {\n normalizedEntity[key] = null;\n }\n }\n }\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = data as Entity;\n\n // Convert all columns 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\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 entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\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 }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\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 let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\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 data as Entity[];\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 // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\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 { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\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 // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\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 data as Entity[];\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 let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\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 switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\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 criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n\n let query = this.client.from(this.table).select(\"*\");\n\n for (const column of criteriaKeys) {\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 switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\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 this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n",
|
|
30
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, getLogger, makeFingerprint, sleep, uuid4 } from \"@workglow/util\";\nimport { mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { PollingSubscriptionManager } from \"../util/PollingSubscriptionManager\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { StorageUnsupportedError } from \"./StorageError\";\n\nexport const FS_FOLDER_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.fsFolder\"\n);\n\n/**\n * A tabular repository implementation that uses the filesystem for storage.\n * Each row is stored as a separate JSON file in the specified directory.\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 FsFolderTabularStorage<\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 = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private folderPath: string;\n /** Counter for auto-incrementing integer keys */\n private autoIncrementCounter = 0;\n /** Shared polling subscription manager */\n private pollingManager: PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n\n /**\n * Creates a new FsFolderTabularStorage instance.\n *\n * @param folderPath - The directory path where the JSON files will be stored\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 - Note: indexes are not supported in this implementation.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n folderPath: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.folderPath = path.join(folderPath);\n }\n\n /**\n * Sets up the directory for the repository (creates directory)\n */\n async setupDirectory(): Promise<void> {\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch (error) {\n // CI system sometimes has issues temporarily\n await new Promise((resolve) => setTimeout(resolve, 0));\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch {\n // Ignore error if directory already exists\n }\n }\n }\n\n /**\n * Generates a key value for auto-generated keys\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"autoincrement\") {\n return ++this.autoIncrementCounter;\n } else {\n return uuid4();\n }\n }\n\n /**\n * Stores a row in the repository\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The stored entity\n * @emits 'put' event when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n let entityToStore = entity as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = this.autoGeneratedKeyName as string;\n const clientProvidedValue = (entity as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, this.autoGeneratedKeyStrategy!);\n entityToStore = { ...entity, [keyName]: generatedValue } as Entity;\n }\n }\n\n await this.setupDirectory();\n const filePath = await this.getFilePath(entityToStore);\n try {\n await writeFile(filePath, JSON.stringify(entityToStore));\n } catch (error) {\n // CI system sometimes has issues temporarily — retry once\n await sleep(1);\n try {\n await writeFile(filePath, JSON.stringify(entityToStore));\n } catch (retryError) {\n throw new Error(\n `Failed to write file \"${filePath}\" after retry: ${retryError instanceof Error ? retryError.message : String(retryError)}`,\n { cause: retryError }\n );\n }\n }\n this.events.emit(\"put\", entityToStore);\n return entityToStore;\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation\n * @param entities - Array of entities to store (may be missing auto-generated keys)\n * @returns Array of stored entities\n * @emits 'put' event for each entity stored\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n await this.setupDirectory();\n return await Promise.all(entities.map(async (entity) => this.put(entity)));\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n await this.setupDirectory();\n const filePath = await this.getFilePath(key);\n try {\n const buf = await readFile(filePath);\n const data = buf.toString(\"utf8\");\n const entity = JSON.parse(data) as Entity;\n this.events.emit(\"get\", key, entity);\n return entity;\n } catch (error) {\n this.events.emit(\"get\", key, undefined);\n return undefined; // File not found or read error\n }\n }\n\n /**\n * Deletes an entry by its key\n * @param key - The primary key object of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.setupDirectory();\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const filePath = await this.getFilePath(key);\n try {\n await rm(filePath);\n } catch (error) {\n console.error(\"Error deleting file\", filePath, error);\n }\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all rows stored in the repository\n * @returns Array of combined objects (rows) if found, undefined otherwise\n */\n async getAll(): Promise<Entity[] | undefined> {\n await this.setupDirectory();\n try {\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n if (jsonFiles.length === 0) {\n return undefined;\n }\n const results = await Promise.allSettled(\n jsonFiles.map(async (file) => {\n const buf = await readFile(path.join(this.folderPath, file));\n const content = buf.toString(\"utf8\");\n const data = JSON.parse(content) as Entity;\n return data;\n })\n );\n\n const values = results\n .filter((result) => result.status === \"fulfilled\")\n .map((result) => result.value);\n\n return values.length > 0 ? values : undefined;\n } catch (error) {\n console.error(\"Error in getAll:\", error);\n throw error;\n }\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.setupDirectory();\n // Delete all files in the folder\n try {\n await rm(this.folderPath, { recursive: true, force: true });\n } catch (error) {\n console.error(\"Error deleting folder\", this.folderPath, error);\n await rm(this.folderPath, { recursive: true, force: true });\n }\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of stored rows\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n await this.setupDirectory();\n // Count all files in the folder ending in .json\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n return jsonFiles.length;\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 await this.setupDirectory();\n const files = await readdir(this.folderPath);\n const jsonFiles = files.filter((file) => file.endsWith(\".json\"));\n\n if (jsonFiles.length === 0) {\n return undefined;\n }\n\n // Read all files in parallel, skipping corrupted files\n const results = await Promise.allSettled(\n jsonFiles.map(async (file) => {\n const filePath = path.join(this.folderPath, file);\n try {\n const content = await readFile(filePath, \"utf8\");\n return JSON.parse(content) as Entity;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to read or parse \"${filePath}\": ${message}`);\n }\n })\n );\n const allEntities: Entity[] = [];\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n allEntities.push(result.value);\n } else {\n getLogger().warn(\n `Skipping corrupted file in getBulk: ${result.reason?.message ?? result.reason}`\n );\n }\n }\n\n // Sort by primary key to ensure deterministic ordering\n // TODO: rethink this, it's not efficient to sort all entities every time\n allEntities.sort((a, b) => {\n for (const key of this.primaryKeyNames) {\n const aVal = (a as Record<string, string | number>)[key as string];\n const bVal = (b as Record<string, string | number>)[key as string];\n if (aVal < bVal) return -1;\n if (aVal > bVal) return 1;\n }\n return 0;\n });\n\n // Slice the sorted array to get the page\n const page = allEntities.slice(offset, offset + limit);\n return page.length > 0 ? page : undefined;\n }\n\n /**\n * Generates the full filesystem path for a given key.\n * @private\n */\n private async getFilePath(value: PrimaryKey | Entity): Promise<string> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const filename = await this.getKeyAsIdString(key);\n const fullPath = path.join(this.folderPath, `${filename}.json`);\n return fullPath;\n }\n\n /**\n * Query is not supported for filesystem repository.\n * @throws StorageUnsupportedError always\n */\n async query(\n _criteria: SearchCriteria<Entity>,\n _options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n throw new StorageUnsupportedError(\"query\", \"FsFolderTabularStorage\");\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Not supported for filesystem repository.\n *\n * @param _criteria - Object with column names as keys and values or SearchConditions\n * @throws Error always - deleteSearch is not supported for filesystem storage\n */\n async deleteSearch(_criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n throw new Error(\"deleteSearch is not supported for FsFolderTabularStorage\");\n }\n\n /**\n * Gets or creates the shared polling subscription manager.\n * This ensures all subscriptions share a single polling loop per interval.\n */\n private getPollingManager(): PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.pollingManager) {\n this.pollingManager = new PollingSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n (a, b) => JSON.stringify(a) === JSON.stringify(b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n }\n );\n }\n return this.pollingManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since filesystem has no native change notification support.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDirectory() here to keep the method synchronous\n // The getAll() method in the polling manager will call setupDirectory() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getPollingManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n override destroy(): void {\n if (this.pollingManager) {\n this.pollingManager.destroy();\n this.pollingManager = null;\n }\n super.destroy();\n }\n}\n",
|
|
31
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n type TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { Pool } from \"@workglow/storage/postgres\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\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 Entity | readonly (keyof 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 let paramIndex = 1;\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 * 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 * 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",
|
|
32
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AutoGeneratedKeys,\n InsertEntity,\n SimplifyPrimaryKey,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\n// BaseTabularStorage is a tabular store that uses SQLite and Postgres use as common code\n\n/**\n * Base class for SQL-based tabular repositories that implements common functionality\n * for both SQLite and PostgreSQL database implementations.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport abstract class BaseSqlTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /**\n * Creates a new instance of BaseSqlTabularStorage\n * @param table - The name of the database table to use for storage\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 protected readonly table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.validateTableAndSchema();\n }\n\n /**\n * Maps JavaScript/TypeScript types to their corresponding SQL type\n * Must be implemented by derived classes for specific SQL dialects\n */\n protected abstract mapTypeToSQL(typeDef: JsonSchema): string;\n\n /**\n * Generates the SQL column definitions for primary key fields\n * @returns SQL string containing primary key column definitions\n */\n protected constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields\n * @returns SQL string containing value column definitions\n */\n protected 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 // Check if the property is nullable based on schema definition or if it's not required\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType}${nullable ? \" NULL\" : \" NOT NULL\"}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Determines if a schema type allows null values\n * @param typeDef - The schema type definition\n * @returns true if the type allows null values\n */\n protected isNullable(typeDef: JsonSchema): boolean {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n // Check for direct null type\n if (typeDef.type === \"null\") {\n return true;\n }\n\n // Check for type as an array that includes null (e.g., type: [\"null\", \"string\"])\n if (Array.isArray(typeDef.type)) {\n return typeDef.type.includes(\"null\");\n }\n\n // Check for union types that include null (anyOf)\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n return typeDef.anyOf.some((type: any) => type.type === \"null\");\n }\n\n // Check for union types that include null (oneOf)\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n return typeDef.oneOf.some((type: any) => type.type === \"null\");\n }\n\n return false;\n }\n\n /**\n * Returns a comma-separated list of primary key column names\n * @returns Formatted string of primary key column names\n */\n protected primaryKeyColumnList($delimiter: string = \"\"): string {\n return $delimiter + this.primaryKeyColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n }\n\n /**\n * Returns a comma-separated list of value column names\n * @returns Formatted string of value column names\n */\n protected valueColumnList($delimiter: string = \"\"): string {\n return $delimiter + this.valueColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n }\n\n /**\n * Gets the real underlying type from possibly union types\n * For example, for a union with null, this extracts the non-null type\n * @param typeDef - The schema to extract from\n * @returns The non-null type from the schema\n */\n protected getNonNullType(typeDef: JsonSchema): JsonSchema {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n const nonNullType = typeDef.anyOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n const nonNullType = typeDef.oneOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n return typeDef;\n }\n\n /**\n * Converts a value object into an ordered array based on the valueSchema\n * This ensures consistent parameter ordering for SQL queries\n * @param value - The value object to convert\n * @returns Array of values ordered according to the schema\n * @throws Error if a required field is missing\n */\n protected getValueAsOrderedArray(value: Value): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const valueAsRecord = value as Record<string, Entity[keyof Entity]>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (Object.prototype.hasOwnProperty.call(valueAsRecord, key)) {\n const val = valueAsRecord[key];\n // Convert undefined to null for optional fields\n if (val === undefined && !requiredSet.has(key)) {\n orderedParams.push(null);\n } else {\n orderedParams.push(this.jsToSqlValue(key, val));\n }\n } else {\n // If the field is required, throw an error\n if (requiredSet.has(key)) {\n throw new Error(`Missing required value field: ${key}`);\n }\n // If the field is optional, use null\n orderedParams.push(null);\n }\n }\n return orderedParams;\n }\n\n /**\n * Converts a primary key object into an ordered array based on the schema\n * This ensures consistent parameter ordering for storage operations\n * @param key - The primary key object to convert\n * @returns Array of key values ordered according to the schema\n */\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const keyObj = key as Record<string, Entity[keyof Entity]>;\n for (const k of Object.keys(this.primaryKeySchema.properties)) {\n if (k in keyObj) {\n const value = keyObj[k];\n if (value === null) {\n throw new Error(`Primary key field ${k} cannot be null`);\n }\n orderedParams.push(this.jsToSqlValue(k, value));\n } else {\n throw new Error(`Missing required primary key field: ${k}`);\n }\n }\n return orderedParams;\n }\n\n protected jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as ValueOptionType;\n }\n\n // Handle null values for nullable columns\n if (value === null && this.isNullable(typeDef)) {\n return null;\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as ValueOptionType;\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (value instanceof Uint8Array) {\n return value;\n }\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value);\n }\n if (Array.isArray(value)) {\n return new Uint8Array(value);\n }\n return value as ValueOptionType;\n } else if (value instanceof Date) {\n // Convert all Date objects to ISO string regardless of type definition\n return value.toISOString();\n } else {\n return value as ValueOptionType;\n }\n }\n\n protected sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n // Get the type definition\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as Entity[keyof Entity];\n }\n\n // Handle null values\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as Entity[keyof Entity];\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value) as Entity[keyof Entity];\n }\n if (value instanceof Uint8Array) {\n return value as Entity[keyof Entity];\n }\n return value as Entity[keyof Entity];\n } else {\n return value as Entity[keyof Entity];\n }\n }\n\n /**\n * Validates table name and schema configurations\n * Checks for:\n * 1. Valid table name format\n * 2. Valid schema key names\n * 3. No duplicate keys between primary key and value schemas\n * This is a sanity check to make sure the table and schema are valid,\n * and to prevent dumb mistakes and mischevious behavior.\n * @throws Error if validation fails\n */\n protected validateTableAndSchema(): void {\n // Validate table name\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(this.table)) {\n throw new Error(\n \"Table name must start with a letter and contain only letters, digits, and underscores, got: \" +\n this.table\n );\n }\n\n // Validate schema keys\n const validateSchemaKeys = (schema: DataPortSchemaObject) => {\n for (const key in schema.properties) {\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) {\n throw new Error(\n \"Schema keys must start with a letter and contain only letters, digits, and underscores, got: \" +\n key\n );\n }\n }\n };\n\n validateSchemaKeys(this.primaryKeySchema);\n validateSchemaKeys(this.valueSchema);\n\n // Check for key name collisions between schemas\n const primaryKeys = new Set(Object.keys(this.primaryKeySchema.properties));\n const valueKeys = Object.keys(this.valueSchema.properties);\n const duplicates = valueKeys.filter((key) => primaryKeys.has(key));\n if (duplicates.length > 0) {\n throw new Error(`Duplicate keys found in schemas: ${duplicates.join(\", \")}`);\n }\n }\n}\n",
|
|
33
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Sqlite } from \"@workglow/storage/sqlite\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption, KeyGenerationStrategy } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\n// Define local type for SQL operations\ntype ExcludeDateKeyOptionType = Exclude<string | number | bigint, Date>;\n\nexport const SQLITE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.sqlite\"\n);\n\n// SqliteTabularStorage is a key-value store that uses SQLite as the backend for\n// in app data.\n\n/**\n * A SQLite-based key-value repository implementation.\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SqliteTabularStorage<\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 /** The SQLite database instance */\n private db: Sqlite.Database;\n\n /** Protected accessor for subclasses that need direct database access */\n protected get database(): Sqlite.Database {\n return this.db;\n }\n\n /**\n * Creates a new SQLite key-value repository\n * @param dbOrPath - Either a Database instance or a path to the SQLite database file\n * @param table - The name of the table to use for storage (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 dbOrPath: string | Sqlite.Database,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n if (typeof dbOrPath === \"string\") {\n this.db = new Sqlite.Database(dbOrPath);\n } else {\n this.db = dbOrPath;\n }\n }\n\n /**\n * Override to handle SQLite's INTEGER PRIMARY KEY for auto-increment\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 with autoincrement strategy\n if (this.isAutoGeneratedKey(key) && this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // SQLite uses INTEGER PRIMARY KEY for auto-increment\n return `${$delimiter}${key}${$delimiter} INTEGER PRIMARY KEY AUTOINCREMENT`;\n }\n const sqlType = this.mapTypeToSQL(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Creates the database table if it doesn't exist with the defined schema.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n // For auto-generated INTEGER PRIMARY KEY, we don't use the PRIMARY KEY constraint separately\n const hasAutoIncrementKey =\n this.hasAutoGeneratedKey() && this.autoGeneratedKeyStrategy === \"autoincrement\";\n\n const sql = hasAutoIncrementKey\n ? `\n CREATE TABLE IF NOT EXISTS \\`${this.table}\\` (\n ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()}\n )\n `\n : `\n CREATE TABLE IF NOT EXISTS \\`${this.table}\\` (\n ${this.constructPrimaryKeyColumns()} ${this.constructValueColumns()},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n this.db.exec(sql);\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 searchSpec of this.indexes) {\n // Handle both single column and compound indexes\n const columns = Array.isArray(searchSpec) ? searchSpec : [searchSpec];\n\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 this.db.exec(\n `CREATE INDEX IF NOT EXISTS \\`${indexName}\\` ON \\`${this.table}\\` (${columnList})`\n );\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Convert JS values to SQLite-compatible values. Ensures booleans are stored as 0/1.\n */\n protected override jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n if (value !== null && value !== undefined && typeof value === \"object\") {\n // Handle special types that should be passed to base class\n if (value instanceof Date) {\n return super.jsToSqlValue(column, value);\n }\n if (value instanceof Uint8Array) {\n return super.jsToSqlValue(column, value);\n }\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return super.jsToSqlValue(column, value);\n }\n // Convert ALL other objects and arrays to JSON string\n return JSON.stringify(value) as ValueOptionType;\n }\n\n // Handle null values\n if (value === null) {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef && this.isNullable(typeDef)) {\n return null;\n }\n // If not nullable, fall through to base class\n }\n\n // Schema-based type handling for non-object/array values\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n const actualType = this.getNonNullType(typeDef);\n const isObject =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"object\");\n const isArray =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"array\");\n const isBoolean =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"boolean\");\n if (isBoolean) {\n if (typeof value === \"boolean\") return value ? 1 : 0;\n if (typeof value === \"number\") return value ? 1 : 0;\n if (typeof value === \"string\")\n return value === \"1\" || value.toLowerCase() === \"true\" ? 1 : 0;\n }\n // Note: Objects/arrays are already handled above by runtime check\n // This check is here for cases where schema says object but runtime value isn't\n if ((isObject || isArray) && value !== null && typeof value === \"object\") {\n // Double-check: if schema says object/array but wasn't caught by runtime check above\n if (\n !(value instanceof Date) &&\n !(value instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(value instanceof Buffer))\n ) {\n if (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype) {\n return JSON.stringify(value) as ValueOptionType;\n }\n }\n }\n }\n\n const result = super.jsToSqlValue(column, value);\n\n // Final safety check: ensure we never return an object or array\n // The base class should not return objects, but if it does, convert them\n if (result !== null && typeof result === \"object\") {\n // TypeScript now knows result is an object (not null), so we can use instanceof\n const resultObj = result as object;\n if (\n !(resultObj instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(resultObj instanceof Buffer))\n ) {\n // Convert any remaining objects/arrays to JSON string\n return JSON.stringify(resultObj) as ValueOptionType;\n }\n }\n\n return result;\n }\n\n /**\n * Convert SQLite values to JS values. Ensures 0/1 become booleans where schema says boolean.\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 const isObject =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"object\");\n const isArray =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"array\");\n const isBoolean =\n typeDef === true || (typeof actualType !== \"boolean\" && actualType.type === \"boolean\");\n\n if (isBoolean) {\n if (typeof value === \"boolean\") return value as Entity[keyof Entity];\n if (typeof value === \"number\") return (value !== 0 ? true : false) as Entity[keyof Entity];\n if (typeof value === \"string\")\n return (\n value === \"1\" || value.toLowerCase() === \"true\" ? true : false\n ) as Entity[keyof Entity];\n }\n\n // Handle array and object types - parse JSON string back to object/array\n if (isArray || isObject) {\n if (typeof value === \"string\") {\n try {\n return JSON.parse(value) as Entity[keyof Entity];\n } catch (e) {\n // If parsing fails, return the value as-is (might be a string that looks like JSON)\n return value as Entity[keyof Entity];\n }\n }\n // If it's already an object/array (shouldn't happen, but handle gracefully)\n return value as Entity[keyof Entity];\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Maps TypeScript/JavaScript types to their SQLite column type equivalents\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 definition\n * @returns The corresponding SQLite column type\n */\n protected mapTypeToSQL(typeDef: JsonSchema): string {\n // Get the actual non-null type for proper mapping\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 \"BLOB\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TEXT\"; // SQLite doesn't have a native TIMESTAMP\n if (actualType.format === \"date\") return \"TEXT\";\n\n // For strings with max length constraints, we can still note this in the schema\n // even though SQLite doesn't enforce VARCHAR lengths\n if (typeof actualType.maxLength === \"number\") {\n return `TEXT /* VARCHAR(${actualType.maxLength}) */`;\n }\n\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // SQLite has limited numeric types, but we can use INTEGER for integers\n // and REAL for floating point numbers\n\n // The multipleOf property in JSON Schema specifies that a number must be a\n // multiple of a given value. When set to 1, it means the number must be a\n // whole number multiple of 1, which effectively means it must be an integer.\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n return \"INTEGER\";\n }\n\n return \"REAL\";\n\n case \"boolean\":\n // SQLite uses INTEGER 0/1 for boolean\n return \"INTEGER\";\n\n case \"array\":\n case \"object\":\n return \"TEXT /* JSON */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates a key value for string UUID keys\n * Integer keys are auto-generated by SQLite's INTEGER PRIMARY KEY\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by SQLite INTEGER PRIMARY KEY\n throw new Error(\n `SQLite autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a key-value pair in the database\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 when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n const db = this.db;\n let entityToInsert = entity as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const entityRecord = entity as Record<string, unknown>;\n const clientProvidedValue = entityRecord[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldUseClientValue = false;\n if (this.clientProvidedKeys === \"never\") {\n // Always generate, ignore client value\n shouldUseClientValue = false;\n } else if (this.clientProvidedKeys === \"always\") {\n // Always use client value, error if missing\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" 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 // For UUID strategy, generate client-side if needed\n if (this.autoGeneratedKeyStrategy === \"uuid\" && !shouldUseClientValue) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n entityToInsert = { ...entity, [keyName]: generatedValue } as Entity;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\" && shouldUseClientValue) {\n // Client provided UUID, use it\n entityToInsert = entity as unknown as Entity;\n }\n // For autoincrement strategy, we handle it differently below\n }\n\n // Determine which columns to include in INSERT\n let columnsToInsert: string[] = [];\n let paramsToInsert: ValueOptionType[] = [];\n\n // Handle primary key columns\n const pkColumns = this.primaryKeyColumns();\n for (const col of pkColumns) {\n const colStr = String(col);\n // Skip autoincrement keys that should be generated by database\n if (\n this.isAutoGeneratedKey(colStr) &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n this.clientProvidedKeys !== \"always\"\n ) {\n const insertRecord = entityToInsert as Record<string, unknown>;\n const clientProvidedValue = insertRecord[colStr];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n if (this.clientProvidedKeys === \"if-missing\" && hasClientValue) {\n // Client provided value for autoincrement key in \"if-missing\" mode\n columnsToInsert.push(colStr);\n paramsToInsert.push(\n this.jsToSqlValue(colStr, clientProvidedValue as Entity[keyof Entity])\n );\n }\n // Otherwise skip it - let SQLite generate\n continue;\n }\n columnsToInsert.push(colStr);\n const value = (entityToInsert as Record<string, unknown>)[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n // Handle value columns\n const valueColumns = this.valueColumns();\n const insertRecord = entityToInsert as Record<string, unknown>;\n for (const col of valueColumns) {\n const colStr = String(col);\n columnsToInsert.push(colStr);\n const value = insertRecord[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(() => \"?\").join(\", \");\n\n const sql = `\n INSERT OR REPLACE INTO \\`${this.table}\\` (${columnList})\n VALUES (${placeholders})\n RETURNING *\n `;\n const stmt = db.prepare(sql);\n\n const params = paramsToInsert;\n\n // CRITICAL: Ensure all params are SQLite-compatible before binding\n // SQLite only accepts: string, number, bigint, boolean, null, Uint8Array\n for (let i = 0; i < params.length; i++) {\n let param = params[i];\n\n // Convert undefined to null\n if (param === undefined) {\n params[i] = null;\n continue;\n }\n\n // Convert objects/arrays to JSON string (except Uint8Array and Buffer)\n if (param !== null && typeof param === \"object\") {\n const paramObj = param as object;\n if (paramObj instanceof Uint8Array) {\n // Uint8Array is valid, keep as-is\n continue;\n }\n if (typeof Buffer !== \"undefined\" && paramObj instanceof Buffer) {\n // Buffer should be handled by jsToSqlValue, but convert to Uint8Array just in case\n params[i] = new Uint8Array(paramObj) as ValueOptionType;\n continue;\n }\n // Convert ALL other objects/arrays to JSON string\n try {\n params[i] = JSON.stringify(paramObj) as ValueOptionType;\n } catch (e) {\n throw new Error(\n `Failed to stringify param at index ${i} for column binding: ${String(e)}`\n );\n }\n continue;\n }\n }\n\n // Final validation - ensure no objects/arrays remain and log for debugging\n const invalidParams: Array<{ index: number; type: string; value: any }> = [];\n for (let i = 0; i < params.length; i++) {\n const param = params[i];\n // Check if it's a valid SQLite type\n if (\n param === null ||\n param === undefined ||\n typeof param === \"string\" ||\n typeof param === \"number\" ||\n typeof param === \"boolean\" ||\n typeof param === \"bigint\"\n ) {\n // Valid primitive types\n continue;\n }\n\n // For objects, check if it's Uint8Array or Buffer\n if (typeof param === \"object\") {\n const paramObj = param as object;\n if (\n paramObj instanceof Uint8Array ||\n (typeof Buffer !== \"undefined\" && paramObj instanceof Buffer)\n ) {\n // Valid object types\n continue;\n }\n // Invalid object type\n invalidParams.push({ index: i, type: typeof param, value: param });\n } else {\n // Invalid type\n invalidParams.push({ index: i, type: typeof param, value: param });\n }\n }\n\n if (invalidParams.length > 0) {\n console.error(\"Invalid params detected:\", invalidParams);\n console.error(\n \"All params:\",\n params.map((p, i) => ({ i, type: typeof p, value: p, isArray: Array.isArray(p) }))\n );\n throw new Error(\n `Invalid SQLite params detected at indices: ${invalidParams.map((p) => p.index).join(\", \")}`\n );\n }\n\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const k in this.schema.properties) {\n updatedRecord[k] = this.sqlToJsValue(k, updatedRecord[k] as ValueOptionType);\n }\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple key-value pairs in the database in a bulk operation\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 // Each put() call will handle auto-generated keys appropriately\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 const db = this.db;\n\n // For SQLite bulk inserts with RETURNING, we need to do them individually\n // or use a transaction with multiple INSERT statements\n const updatedEntities: Entity[] = [];\n\n // Use a transaction for better performance\n const transaction = db.transaction((entitiesToInsert: any[]) => {\n for (const entity of entitiesToInsert) {\n const { key, value } = this.separateKeyValueFromCombined(entity);\n const sql = `\n INSERT OR REPLACE INTO \\`${\n this.table\n }\\` (${this.primaryKeyColumnList()} ${this.valueColumnList() ? \", \" + this.valueColumnList() : \"\"})\n VALUES (\n ${this.primaryKeyColumns()\n .map(() => \"?\")\n .join(\", \")}\n ${\n this.valueColumns().length > 0\n ? \", \" +\n this.valueColumns()\n .map(() => \"?\")\n .join(\", \")\n : \"\"\n }\n )\n RETURNING *\n `;\n const stmt = db.prepare(sql);\n const primaryKeyParams = this.getPrimaryKeyAsOrderedArray(key);\n const valueParams = this.getValueAsOrderedArray(value);\n const params = [...primaryKeyParams, ...valueParams];\n\n // Ensure all params are SQLite-compatible (same validation as put method)\n for (let i = 0; i < params.length; i++) {\n let param = params[i];\n if (param === undefined) {\n params[i] = null;\n } else if (param !== null && typeof param === \"object\") {\n // TypeScript now knows param is an object (not null), so we can use instanceof\n const paramObj: object = param as object;\n if (\n !(paramObj instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(paramObj instanceof Buffer))\n ) {\n params[i] = JSON.stringify(paramObj) as ValueOptionType;\n }\n }\n }\n\n // @ts-ignore\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n for (const k in this.schema.properties) {\n // @ts-ignore\n updatedEntity[k] = this.sqlToJsValue(k, updatedEntity[k]);\n }\n\n updatedEntities.push(updatedEntity);\n }\n });\n\n transaction(entities);\n\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 key\n * @param key - The primary key object to look up\n * @returns The stored value or undefined if not found\n * @emits 'get' event 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((key) => `\\`${key}\\` = ?`)\n .join(\" AND \");\n\n const sql = `\n SELECT * FROM \\`${this.table}\\` WHERE ${whereClauses}\n `;\n const stmt = db.prepare(sql);\n const params = this.getPrimaryKeyAsOrderedArray(key);\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n const value: Entity | null = stmt.get(...(params as ValueOptionType[]));\n if (value) {\n const row = value as Record<string, unknown>;\n for (const k in this.schema.properties) {\n row[k] = this.sqlToJsValue(k, row[k] as ValueOptionType);\n }\n this.events.emit(\"get\", key, value);\n return value;\n } else {\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n }\n\n /**\n * Deletes a key-value pair from the database\n * @param key - The primary key object to delete\n * @emits 'delete' event when successful\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = this.db;\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((key) => `${key} = ?`)\n .join(\" AND \");\n const params = this.getPrimaryKeyAsOrderedArray(key);\n const stmt = db.prepare(`DELETE FROM \\`${this.table}\\` WHERE ${whereClauses}`);\n // @ts-ignore - SQLite typing for variadic bindings is overly strict for our union\n stmt.run(...(params as ValueOptionType[]));\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 ?`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n if (options.limit === undefined) {\n sql += ` LIMIT -1`;\n }\n sql += ` OFFSET ?`;\n params.push(options.offset);\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore\n const value = params.length > 0 ? stmt.all(...params) : stmt.all();\n if (!value.length) return undefined;\n // Convert all columns according to schema for each row\n for (const row of value) {\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 return value as Entity[];\n }\n\n /**\n * Deletes all entries from the database table\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n const db = this.db;\n db.exec(`DELETE FROM \\`${this.table}\\``);\n this.events.emit(\"clearall\");\n }\n\n /**\n * Gets the total number of entries in the database table\n * @returns The count of entries\n */\n async size(): Promise<number> {\n const db = this.db;\n const stmt = db.prepare<unknown[], { count: number }>(`\n SELECT COUNT(*) AS count FROM \\`${this.table}\\`\n `);\n return stmt.get()?.count || 0;\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 stmt = db.prepare<[number, number], Entity>(`\n SELECT * FROM \\`${this.table}\\` ORDER BY ${orderByClause} LIMIT ? OFFSET ?\n `);\n const rows = stmt.all(limit, offset);\n\n if (!rows || rows.length === 0) {\n return undefined;\n }\n\n // Convert all columns according to schema for each row (consistent with getAll)\n for (const row of 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\n return rows;\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\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} ?`);\n params.push(this.jsToSqlValue(column as string, value));\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 const stmt = db.prepare(`DELETE FROM \\`${this.table}\\` WHERE ${whereClause}`);\n // @ts-ignore\n stmt.run(...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 ?`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n if (options.limit === undefined) {\n sql += ` LIMIT -1`;\n }\n sql += ` OFFSET ?`;\n params.push(options.offset);\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore\n const result = stmt.all(...params) as Entity[];\n\n if (result.length > 0) {\n for (const row of result) {\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);\n return result;\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Subscribes to changes in the repository.\n * NOT IMPLEMENTED for SQLite storage.\n *\n * @throws Error always - subscribeToChanges is not supported for SQLite 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 SqliteTabularStorage\");\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n super.destroy();\n }\n}\n",
|
|
34
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase 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 SupabaseTabularStorage<\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 private client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\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 client: SupabaseClient,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client;\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 const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\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 const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\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 override 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 // 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 delimiter = $delimiter || '\"';\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 Supabase 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 numeric types - Supabase 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 * 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 // Handle auto-generated keys\n let entityToInsert = { ...entity };\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const entityRecord = entity as Record<string, unknown>;\n const clientProvidedValue = entityRecord[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldOmitKey = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldOmitKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldOmitKey = false;\n } else {\n // \"if-missing\" - omit key if client didn't provide it\n shouldOmitKey = !hasClientValue;\n }\n\n if (shouldOmitKey) {\n // Omit the auto-generated key so Supabase generates it\n delete (entityToInsert as Record<string, unknown>)[keyName];\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const normalizedEntity = { ...entityToInsert } as Record<string, unknown>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in normalizedEntity) || normalizedEntity[key] === undefined) {\n if (!requiredSet.has(key)) {\n normalizedEntity[key] = null;\n }\n }\n }\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = data as Entity;\n\n // Convert all columns 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\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 entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\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 }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\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 let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\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 data as Entity[];\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 // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\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 { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\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 // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\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 data as Entity[];\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 let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\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 switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\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 criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n\n let query = this.client.from(this.table).select(\"*\");\n\n for (const column of criteriaKeys) {\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 switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\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 this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n",
|
|
35
35
|
"/**\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 { FsFolderTabularStorage } from \"../tabular/FsFolderTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, IKvStorage } from \"./IKvStorage\";\nimport { KvViaTabularStorage } from \"./KvViaTabularStorage\";\n\nexport const FS_FOLDER_JSON_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.fsFolderJson\"\n);\n\n/**\n * A key-value repository implementation that stores values as JSON files in a specified folder.\n * Uses a tabular repository abstraction for file-based persistence.\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 FsFolderJsonKvStorage extends KvViaTabularStorage {\n public tabularRepository: FsFolderTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public folderPath: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new FsFolderTabularStorage(\n folderPath,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
|
|
36
36
|
"/**\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 { mkdir, readFile, rm, unlink, writeFile } from \"fs/promises\";\nimport path from \"path\";\nimport { IKvStorage } from \"./IKvStorage\";\nimport { KvStorage } from \"./KvStorage\";\n\nexport const FS_FOLDER_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.fsFolder\"\n);\n\n/**\n * A key-value repository implementation that stores each value as a file in a specified folder.\n * Uses the file system for persistence, with each key mapped to a file path.\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 FsFolderKvStorage<\n Key extends string = string,\n Value extends any = any,\n Combined = { key: Key; value: Value },\n> extends KvStorage<Key, Value, Combined> {\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public folderPath: string,\n public pathWriter: (key: Key) => string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = { contentEncoding: \"blob\" }\n ) {\n super(keySchema, valueSchema);\n }\n\n /**\n * Sets up the directory for the repository (creates directory)\n */\n private async setupDirectory(): Promise<void> {\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch (error) {\n // CI system sometimes has issues temporarily\n await new Promise((resolve) => setTimeout(resolve, 0));\n try {\n await mkdir(this.folderPath, { recursive: true });\n } catch {\n // Ignore error if directory already exists\n }\n }\n }\n\n /**\n * Stores a row in the repository.\n * @param key - The primary key\n * @param value - The value to store\n */\n public async put(key: Key, value: Value): Promise<void> {\n const localPath = path.join(this.folderPath, this.pathWriter(key).replaceAll(\"..\", \"_\"));\n\n let content: string;\n const schemaType =\n typeof this.valueSchema === \"object\" &&\n this.valueSchema !== null &&\n \"type\" in this.valueSchema\n ? this.valueSchema.type\n : undefined;\n if (value === null) {\n content = \"\";\n } else if (schemaType === \"object\") {\n content = JSON.stringify(value);\n } else if (typeof value === \"object\") {\n // Handle 'json' type schema from tests\n content = JSON.stringify(value);\n } else {\n content = String(value);\n }\n\n await mkdir(path.dirname(localPath), { recursive: true });\n await writeFile(localPath, content);\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param items - Array of key-value pairs to store\n */\n public async putBulk(items: Array<{ key: Key; value: Value }>): Promise<void> {\n await this.setupDirectory();\n await Promise.all(items.map(async ({ key, value }) => this.put(key, value)));\n }\n\n /**\n * Retrieves a value by its key.\n * This is a convenience method that automatically converts simple types to structured format if using default schema.\n *\n * @param key - Primary key to look up (basic key like default schema)\n * @returns The stored value or undefined if not found\n */\n public async get(key: Key): Promise<Value | undefined> {\n const localPath = path.join(this.folderPath, this.pathWriter(key).replaceAll(\"..\", \"_\"));\n const typeDef = this.valueSchema;\n try {\n const encoding =\n typeof typeDef === \"object\" &&\n typeDef !== null &&\n \"contentEncoding\" in typeDef &&\n typeDef.contentEncoding === \"blob\"\n ? \"binary\"\n : \"utf-8\";\n const content = (await readFile(localPath, { encoding })).toString().trim();\n\n if (encoding === \"utf-8\") {\n const schemaType =\n typeof typeDef === \"object\" && typeDef !== null && \"type\" in typeDef\n ? typeDef.type\n : undefined;\n if (\n schemaType === \"object\" ||\n (content.startsWith(\"{\") && content.endsWith(\"}\")) ||\n (content.startsWith(\"[\") && content.endsWith(\"]\"))\n ) {\n try {\n return JSON.parse(content) as Value;\n } catch (e) {\n // If JSON parsing fails, return as string\n return content as unknown as Value;\n }\n }\n }\n\n return content as unknown as Value;\n } catch (error) {\n return undefined;\n }\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The primary key of the row to delete\n */\n public async delete(key: Key): Promise<void> {\n const localPath = path.join(this.folderPath, this.pathWriter(key).replaceAll(\"..\", \"_\"));\n await unlink(localPath);\n }\n\n /**\n * Retrieves all rows from the repository.\n * @returns An array of all rows in the repository or undefined if empty\n */\n public async getAll(): Promise<Combined[] | undefined> {\n throw new Error(\"Not implemented\");\n }\n\n /**\n * Deletes all rows from the repository.\n */\n public async deleteAll(): Promise<void> {\n const localPath = path.join(this.folderPath);\n await rm(localPath, { recursive: true });\n }\n\n /**\n * Retrieves the number of rows in the repository.\n * @returns The number of rows in the repository\n */\n public async size(): Promise<number> {\n throw new Error(\"Not implemented\");\n }\n}\n",
|
|
37
37
|
"/**\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 \"../tabular/PostgresTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, IKvStorage } from \"./IKvStorage\";\nimport { KvViaTabularStorage } from \"./KvViaTabularStorage\";\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",
|
|
@@ -43,17 +43,17 @@
|
|
|
43
43
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport type { Pool } from \"@workglow/storage/postgres\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const POSTGRES_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.postgres\"\n);\n\n/**\n * PostgreSQL implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class PostgresRateLimiterStorage implements IRateLimiterStorage {\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** The table name for execution tracking */\n protected readonly executionTableName: string;\n /** The table name for next available times */\n protected readonly nextAvailableTableName: string;\n\n constructor(\n protected readonly db: Pool,\n options?: RateLimiterStorageOptions\n ) {\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column.\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE.\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Builds WHERE clause conditions for prefix filtering.\n * @param startParam - The starting parameter number for parameterized queries\n */\n private buildPrefixWhereClause(startParam: number): {\n conditions: string;\n params: Array<string | number>;\n } {\n if (this.prefixes.length === 0) {\n return { conditions: \"\", params: [] };\n }\n const conditions = this.prefixes.map((p, i) => `${p.name} = $${startParam + i}`).join(\" AND \");\n const params = this.prefixes.map((p) => this.prefixValues[p.name]);\n return { conditions: \" AND \" + conditions, params };\n }\n\n /**\n * Gets prefix values as an array in column order.\n */\n private getPrefixParamValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n await this.db.query(`\n CREATE TABLE IF NOT EXISTS ${this.executionTableName} (\n id SERIAL PRIMARY KEY,\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `);\n\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx \n ON ${this.executionTableName} (${prefixIndexPrefix}queue_name, executed_at)\n `);\n\n // For the next_available table, we need a composite primary key with prefixes\n const primaryKeyColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n await this.db.query(`\n CREATE TABLE IF NOT EXISTS ${this.nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n next_available_at TIMESTAMP WITH TIME ZONE,\n PRIMARY KEY (${primaryKeyColumns})\n )\n `);\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n const prefixParamPlaceholders =\n prefixColumnNames.length > 0\n ? prefixColumnNames.map((_, i) => `$${i + 1}`).join(\", \") + \", \"\n : \"\";\n const queueParamNum = prefixColumnNames.length + 1;\n\n await this.db.query(\n `\n INSERT INTO ${this.executionTableName} (${prefixColumnsInsert}queue_name)\n VALUES (${prefixParamPlaceholders}$${queueParamNum})\n `,\n [...prefixParamValues, queueName]\n );\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n\n const result = await this.db.query(\n `\n SELECT COUNT(*) AS count\n FROM ${this.executionTableName}\n WHERE queue_name = $1 AND executed_at > $2${prefixConditions}\n `,\n [queueName, windowStartTime, ...prefixParams]\n );\n\n return parseInt(result.rows[0]?.count ?? \"0\", 10);\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n\n const result = await this.db.query(\n `\n SELECT executed_at\n FROM ${this.executionTableName}\n WHERE queue_name = $1${prefixConditions}\n ORDER BY executed_at ASC\n LIMIT 1 OFFSET $2\n `,\n [queueName, offset, ...prefixParams]\n );\n\n const executedAt = result.rows[0]?.executed_at;\n if (!executedAt) return undefined;\n return new Date(executedAt).toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(2);\n\n const result = await this.db.query(\n `\n SELECT next_available_at\n FROM ${this.nextAvailableTableName}\n WHERE queue_name = $1${prefixConditions}\n `,\n [queueName, ...prefixParams]\n );\n\n const nextAvailableAt = result.rows[0]?.next_available_at;\n if (!nextAvailableAt) return undefined;\n return new Date(nextAvailableAt).toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n const prefixParamPlaceholders =\n prefixColumnNames.length > 0\n ? prefixColumnNames.map((_, i) => `$${i + 1}`).join(\", \") + \", \"\n : \"\";\n const baseParamStart = prefixColumnNames.length + 1;\n\n // Build the conflict columns for upsert\n const conflictColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n await this.db.query(\n `\n INSERT INTO ${this.nextAvailableTableName} (${prefixColumnsInsert}queue_name, next_available_at)\n VALUES (${prefixParamPlaceholders}$${baseParamStart}, $${baseParamStart + 1})\n ON CONFLICT (${conflictColumns})\n DO UPDATE SET next_available_at = EXCLUDED.next_available_at\n `,\n [...prefixParamValues, queueName, nextAvailableAt]\n );\n }\n\n public async clear(queueName: string): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(2);\n\n await this.db.query(\n `DELETE FROM ${this.executionTableName} WHERE queue_name = $1${prefixConditions}`,\n [queueName, ...prefixParams]\n );\n await this.db.query(\n `DELETE FROM ${this.nextAvailableTableName} WHERE queue_name = $1${prefixConditions}`,\n [queueName, ...prefixParams]\n );\n }\n}\n",
|
|
44
44
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Sqlite } from \"@workglow/storage/sqlite\";\nimport { createServiceToken, sleep, toSQLiteTimestamp } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const SQLITE_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.sqlite\"\n);\n\n/**\n * SQLite implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class SqliteRateLimiterStorage implements IRateLimiterStorage {\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** The table name for execution tracking */\n protected readonly executionTableName: string;\n /** The table name for next available times */\n protected readonly nextAvailableTableName: string;\n\n constructor(\n protected readonly db: Sqlite.Database,\n options?: RateLimiterStorageOptions\n ) {\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (SQLite uses TEXT for uuid).\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"TEXT\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE.\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Builds WHERE clause conditions for prefix filtering.\n */\n private buildPrefixWhereClause(): string {\n if (this.prefixes.length === 0) {\n return \"\";\n }\n const conditions = this.prefixes.map((p) => `${p.name} = ?`).join(\" AND \");\n return \" AND \" + conditions;\n }\n\n /**\n * Gets prefix values as an array in column order.\n */\n private getPrefixParamValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n public async setupDatabase(): Promise<void> {\n await sleep(0);\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${this.executionTableName} (\n id INTEGER PRIMARY KEY,\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n executed_at TEXT DEFAULT CURRENT_TIMESTAMP\n );\n \n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx \n ON ${this.executionTableName} (${prefixIndexPrefix}queue_name, executed_at);\n `);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${this.nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT PRIMARY KEY,\n next_available_at TEXT\n );\n `);\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixPlaceholders =\n prefixColumnNames.length > 0 ? prefixColumnNames.map(() => \"?\").join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n\n const stmt = this.db.prepare(`\n INSERT INTO ${this.executionTableName} (${prefixColumnsInsert}queue_name)\n VALUES (${prefixPlaceholders}?)\n `);\n stmt.run(...prefixParamValues, queueName);\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const prefixConditions = this.buildPrefixWhereClause();\n const prefixParams = this.getPrefixParamValues();\n const thresholdTime = toSQLiteTimestamp(new Date(windowStartTime));\n\n const stmt = this.db.prepare<unknown[], { count: number }>(`\n SELECT COUNT(*) AS count\n FROM ${this.executionTableName}\n WHERE queue_name = ? AND executed_at > ?${prefixConditions}\n `);\n const result = stmt.get(queueName, thresholdTime!, ...prefixParams);\n return result?.count ?? 0;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const prefixConditions = this.buildPrefixWhereClause();\n const prefixParams = this.getPrefixParamValues();\n\n const stmt = this.db.prepare<unknown[], { executed_at: string }>(`\n SELECT executed_at\n FROM ${this.executionTableName}\n WHERE queue_name = ?${prefixConditions}\n ORDER BY executed_at ASC\n LIMIT 1 OFFSET ?\n `);\n const result = stmt.get(queueName, ...prefixParams, offset);\n if (!result) return undefined;\n // SQLite stores times without timezone, add Z for UTC\n return result.executed_at + \"Z\";\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const prefixConditions = this.buildPrefixWhereClause();\n const prefixParams = this.getPrefixParamValues();\n\n const stmt = this.db.prepare<unknown[], { next_available_at: string }>(`\n SELECT next_available_at\n FROM ${this.nextAvailableTableName}\n WHERE queue_name = ?${prefixConditions}\n `);\n const result = stmt.get(queueName, ...prefixParams);\n if (!result?.next_available_at) return undefined;\n // SQLite stores times without timezone, add Z for UTC\n return result.next_available_at + \"Z\";\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixPlaceholders =\n prefixColumnNames.length > 0 ? prefixColumnNames.map(() => \"?\").join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n\n const stmt = this.db.prepare(`\n INSERT INTO ${this.nextAvailableTableName} (${prefixColumnsInsert}queue_name, next_available_at)\n VALUES (${prefixPlaceholders}?, ?)\n ON CONFLICT(queue_name) DO UPDATE SET next_available_at = excluded.next_available_at\n `);\n stmt.run(...prefixParamValues, queueName, nextAvailableAt);\n }\n\n public async clear(queueName: string): Promise<void> {\n const prefixConditions = this.buildPrefixWhereClause();\n const prefixParams = this.getPrefixParamValues();\n\n this.db\n .prepare(`DELETE FROM ${this.executionTableName} WHERE queue_name = ?${prefixConditions}`)\n .run(queueName, ...prefixParams);\n this.db\n .prepare(`DELETE FROM ${this.nextAvailableTableName} WHERE queue_name = ?${prefixConditions}`)\n .run(queueName, ...prefixParams);\n }\n}\n",
|
|
45
45
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const SUPABASE_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.supabase\"\n);\n\n/**\n * Supabase implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class SupabaseRateLimiterStorage implements IRateLimiterStorage {\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** The table name for execution tracking */\n protected readonly executionTableName: string;\n /** The table name for next available times */\n protected readonly nextAvailableTableName: string;\n\n constructor(\n protected readonly client: SupabaseClient,\n options?: RateLimiterStorageOptions\n ) {\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (Supabase supports UUID natively).\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE.\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Applies prefix filters to a Supabase query builder.\n */\n private applyPrefixFilters<T>(query: T): T {\n let result = query as any;\n for (const prefix of this.prefixes) {\n result = result.eq(prefix.name, this.prefixValues[prefix.name]);\n }\n return result as T;\n }\n\n /**\n * Gets prefix values as an object for inserts.\n */\n private getPrefixInsertValues(): Record<string, string | number> {\n const values: Record<string, string | number> = {};\n for (const prefix of this.prefixes) {\n values[prefix.name] = this.prefixValues[prefix.name];\n }\n return values;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n // Create execution tracking table\n const createExecTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.executionTableName} (\n id SERIAL PRIMARY KEY,\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `;\n\n const { error: execTableError } = await this.client.rpc(\"exec_sql\", {\n query: createExecTableSql,\n });\n if (execTableError && execTableError.code !== \"42P07\") {\n throw execTableError;\n }\n\n // Create index on execution table\n const createExecIndexSql = `\n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx \n ON ${this.executionTableName} (${prefixIndexPrefix}queue_name, executed_at)\n `;\n await this.client.rpc(\"exec_sql\", { query: createExecIndexSql });\n\n // Build primary key columns\n const primaryKeyColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n // Create next available table\n const createNextTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n next_available_at TIMESTAMP WITH TIME ZONE,\n PRIMARY KEY (${primaryKeyColumns})\n )\n `;\n\n const { error: nextTableError } = await this.client.rpc(\"exec_sql\", {\n query: createNextTableSql,\n });\n if (nextTableError && nextTableError.code !== \"42P07\") {\n throw nextTableError;\n }\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.executionTableName).insert({\n ...prefixInsertValues,\n queue_name: queueName,\n });\n\n if (error) throw error;\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"queue_name\", queueName)\n .gt(\"executed_at\", windowStartTime);\n\n query = this.applyPrefixFilters(query);\n\n const { count, error } = await query;\n\n if (error) throw error;\n return count ?? 0;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"executed_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query\n .order(\"executed_at\", { ascending: true })\n .range(offset, offset);\n\n if (error) throw error;\n if (!data || data.length === 0) return undefined;\n return new Date(data[0].executed_at).toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n let query = this.client\n .from(this.nextAvailableTableName)\n .select(\"next_available_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return undefined; // Not found\n throw error;\n }\n\n if (!data?.next_available_at) return undefined;\n return new Date(data.next_available_at).toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.nextAvailableTableName).upsert(\n {\n ...prefixInsertValues,\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n },\n {\n onConflict:\n this.prefixes.length > 0\n ? `${this.getPrefixColumnNames().join(\",\")},queue_name`\n : \"queue_name\",\n }\n );\n\n if (error) throw error;\n }\n\n public async clear(queueName: string): Promise<void> {\n let execQuery = this.client.from(this.executionTableName).delete().eq(\"queue_name\", queueName);\n execQuery = this.applyPrefixFilters(execQuery);\n const { error: execError } = await execQuery;\n if (execError) throw execError;\n\n let nextQuery = this.client\n .from(this.nextAvailableTableName)\n .delete()\n .eq(\"queue_name\", queueName);\n nextQuery = this.applyPrefixFilters(nextQuery);\n const { error: nextError } = await nextQuery;\n if (nextError) throw nextError;\n }\n}\n",
|
|
46
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type { Pool } from \"@workglow/storage/postgres\";\nimport { PostgresTabularStorage } from \"../tabular/PostgresTabularStorage\";\nimport { StorageValidationError } from \"../tabular/StorageError\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\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 Vector - The vector type\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 Vector extends TypedArray = Float32Array,\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 VectorType: new (array: number[]) => TypedArray;\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 VectorType - The type of vector to use (defaults to Float32Array)\n */\n constructor(\n db: Pool,\n table: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array\n ) {\n super(db, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\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 getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n 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(row)}`,\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.VectorType(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(row)}`,\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.VectorType(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 ?? {}).join(\" \").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(row: any): 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",
|
|
46
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type { Pool } from \"@workglow/storage/postgres\";\nimport { PostgresTabularStorage } from \"../tabular/PostgresTabularStorage\";\nimport { StorageValidationError } from \"../tabular/StorageError\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\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 Vector - The vector type\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 Vector extends TypedArray = Float32Array,\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 VectorType: new (array: number[]) => TypedArray;\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 VectorType - The type of vector to use (defaults to Float32Array)\n */\n constructor(\n db: Pool,\n table: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array\n ) {\n super(db, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\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(row)}`,\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.VectorType(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(row)}`,\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.VectorType(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(row: any): 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",
|
|
47
47
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Sqlite } from \"@workglow/storage/sqlite\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { SqliteTabularStorage } from \"../tabular/SqliteTabularStorage\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(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/**\n * SQLite vector repository implementation using tabular storage underneath.\n * Stores vectors as JSON-encoded arrays with metadata.\n *\n * @template Vector - The vector type for the vector\n * @template Metadata - The metadata type for the vector\n * @template Schema - The schema for the vector\n * @template PrimaryKeyNames - The primary key names for the vector\n */\nexport class SqliteVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Vector extends TypedArray = Float32Array,\n Metadata extends Record<string, unknown> | undefined = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends SqliteTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private VectorType: new (array: number[]) => TypedArray;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n /**\n * Creates a new SQLite vector repository\n * @param dbOrPath - Either a Database instance or a path to the SQLite database file\n * @param table - The name of the table to use for storage (defaults to 'vectors')\n * @param dimensions - The number of dimensions of the vector\n * @param VectorType - The type of vector to use (defaults to Float32Array)\n */\n constructor(\n dbOrPath: string | Sqlite.Database,\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array\n ) {\n super(dbOrPath, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\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 getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /**\n * Deserialize vector from JSON string\n * Defaults to Float32Array for compatibility with typical embedding vectors\n */\n private deserializeVector(vectorJson: string): TypedArray {\n const array = JSON.parse(vectorJson);\n // Default to Float32Array for typical use case (embeddings)\n return new this.VectorType(array);\n }\n\n async similaritySearch(query: TypedArray, options: VectorSearchOptions<Metadata> = {}) {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const results: Array<Entity & { score: number }> = [];\n\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // SQLite stores vectors as JSON strings, need to deserialize\n const vectorRaw = entity[this.vectorPropertyName] as unknown as string;\n const vector = this.deserializeVector(vectorRaw);\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate similarity\n const score = cosineSimilarity(query, vector);\n\n // Apply threshold\n if (score < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score,\n } as Entity & { score: number });\n }\n\n // Sort by score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\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 // Fall back to regular vector search if no text query\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n const results: Array<Entity & { score: number }> = [];\n const allEntities = (await this.getAll()) || [];\n const queryLower = textQuery.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n\n for (const entity of allEntities) {\n // SQLite stores vectors as JSON strings, need to deserialize\n const vectorRaw = entity[this.vectorPropertyName] as unknown as string;\n const vector = this.deserializeVector(vectorRaw);\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate vector similarity\n const vectorScore = cosineSimilarity(query, vector);\n\n // Calculate text relevance (simple keyword matching)\n const metadataText = Object.values(metadata ?? {}).join(\" \").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 // Combine scores\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n // Apply threshold\n if (combinedScore < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score: combinedScore,\n } as Entity & { score: number });\n }\n\n // Sort by combined score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n}\n",
|
|
48
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Sqlite } from \"@workglow/storage/sqlite\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { SqliteTabularStorage } from \"../tabular/SqliteTabularStorage\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\n\n/**\n * Maps TypedArray constructor types to their sqlite-vector encoding function names\n * and corresponding distance metric types.\n */\nconst VECTOR_TYPE_MAP: Record<string, string> = {\n Float32Array: \"f32\",\n Float64Array: \"f32\", // sqlite-vector doesn't support f64, convert to f32\n Int8Array: \"i8\",\n Uint8Array: \"u8\",\n Int16Array: \"f16\", // approximate mapping\n};\n\n/**\n * Gets the sqlite-vector encoding function suffix for a given TypedArray type\n */\nfunction getVectorTypeSuffix(VectorType: { new (array: number[]): TypedArray }): string {\n return VECTOR_TYPE_MAP[VectorType.name] || \"f32\";\n}\n\n/**\n * Gets the sqlite-vector type string for vector_init options\n */\nfunction getVectorTypeOption(VectorType: { new (array: number[]): TypedArray }): string {\n const typeMap: Record<string, string> = {\n Float32Array: \"FLOAT32\",\n Float64Array: \"FLOAT32\",\n Int8Array: \"INT8\",\n Uint8Array: \"UINT8\",\n Int16Array: \"FLOAT16\",\n };\n return typeMap[VectorType.name] || \"FLOAT32\";\n}\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(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/**\n * Escape a SQL identifier (table/column name) by doubling any backtick characters,\n * then wrapping in backticks. This prevents SQL injection via identifier names.\n */\nfunction escapeIdentifier(name: string): string {\n return \"`\" + name.replace(/`/g, \"``\") + \"`\";\n}\n\n/**\n * SQLite vector storage implementation using the @sqliteai/sqlite-vector extension.\n * Provides native vector similarity search via SQLite virtual table functions\n * instead of in-memory brute-force search.\n *\n * Requirements:\n * - @sqliteai/sqlite-vector package installed\n * - Extension loaded via db.loadExtension(getExtensionPath())\n *\n * Vectors are stored as BLOBs using sqlite-vector encoding functions (vector_as_f32, etc.)\n * and searched using vector_full_scan for efficient KNN queries.\n *\n * @template Schema - The schema for the vector storage\n * @template PrimaryKeyNames - The primary key names\n * @template Vector - The vector type (default Float32Array)\n * @template Metadata - The metadata type\n */\nexport class SqliteAiVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Vector extends TypedArray = Float32Array,\n Metadata extends Record<string, unknown> | undefined = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends SqliteTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private VectorType: new (array: number[]) => TypedArray;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n private vectorTypeSuffix: string;\n private extensionLoaded: boolean = false;\n\n /**\n * Creates a new SQLite AI vector storage\n * @param dbOrPath - Either a Database instance or a path to the SQLite database file\n * @param table - The name of the table to use for storage\n * @param schema - The schema for the entity\n * @param primaryKeyNames - Array of property names forming the primary key\n * @param indexes - Array of columns to index\n * @param dimensions - The number of dimensions of the vector\n * @param VectorType - The type of vector to use (defaults to Float32Array)\n */\n constructor(\n dbOrPath: string | Sqlite.Database,\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array\n ) {\n super(dbOrPath, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\n this.vectorTypeSuffix = getVectorTypeSuffix(VectorType);\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 getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /**\n * Load the sqlite-vector extension and initialize vector indexing on the vector column.\n * Extension loading is best-effort: if unavailable, operations fall back to in-memory search.\n */\n async setupDatabase(): Promise<void> {\n // Always create the table first via the parent class\n await super.setupDatabase();\n\n // Try to load the sqlite-vector extension if not already loaded\n if (!this.extensionLoaded) {\n try {\n // Try to load the extension - the caller may have already loaded it\n const { getExtensionPath } = await import(\"@sqliteai/sqlite-vector\");\n this.database.loadExtension(getExtensionPath());\n this.extensionLoaded = true;\n } catch {\n // Extension might already be loaded by the caller; verify with vector_version()\n try {\n this.database.exec(\"SELECT vector_version()\");\n this.extensionLoaded = true;\n } catch {\n // Extension is unavailable; operations will fall back to in-memory search\n }\n }\n }\n\n // Initialize the vector column for sqlite-vector indexing (only if extension is available)\n if (this.extensionLoaded) {\n const vectorCol = String(this.vectorPropertyName);\n const vectorType = getVectorTypeOption(this.VectorType);\n try {\n this.database\n .prepare(\"SELECT vector_init(?, ?, ?)\")\n .run(\n this.table,\n vectorCol,\n `dimension=${this.vectorDimensions},type=${vectorType},distance=COSINE`\n );\n } catch {\n // vector_init may fail if already initialized, that's OK\n }\n }\n }\n\n /**\n * Encode a vector as a BLOB using sqlite-vector functions.\n * Returns a JSON string representation suitable for vector_as_f32() etc.\n */\n private encodeVectorJson(vector: TypedArray): string {\n return `[${Array.from(vector).join(\",\")}]`;\n }\n\n /**\n * Decode a vector BLOB from SQLite back to a TypedArray.\n * sqlite-vector stores vectors as BLOBs, but when we SELECT them\n * they come back as Buffer/Uint8Array. We also handle JSON string fallback.\n */\n private decodeVector(raw: unknown): TypedArray {\n if (raw instanceof Uint8Array || (typeof Buffer !== \"undefined\" && raw instanceof Buffer)) {\n // Normalize to a Uint8Array view so we respect byteOffset/byteLength for Buffer as well.\n const view =\n raw instanceof Uint8Array\n ? raw\n : new Uint8Array(\n (raw as Buffer).buffer,\n (raw as Buffer).byteOffset,\n (raw as Buffer).byteLength\n );\n\n if (this.VectorType === Float32Array || this.VectorType.name === \"Float32Array\") {\n return new Float32Array(view.buffer, view.byteOffset, this.vectorDimensions) as TypedArray;\n }\n // For other types, read as float32 and convert\n const f32 = new Float32Array(view.buffer, view.byteOffset, this.vectorDimensions);\n return new this.VectorType(Array.from(f32));\n }\n if (typeof raw === \"string\") {\n // JSON string fallback\n const array = JSON.parse(raw);\n return new this.VectorType(array);\n }\n if (Array.isArray(raw)) {\n return new this.VectorType(raw);\n }\n throw new Error(`Cannot decode vector from type: ${typeof raw}`);\n }\n\n /**\n * Override jsToSqlValue to encode vectors as BLOBs via sqlite-vector functions\n */\n protected jsToSqlValue(\n column: string,\n value: Entity[keyof Entity]\n ): ReturnType<SqliteTabularStorage<Schema, PrimaryKeyNames, Entity>[\"jsToSqlValue\"]> {\n if (column === String(this.vectorPropertyName) && value != null) {\n // For vector columns, encode as JSON string for sqlite-vector\n const vector = value as unknown as TypedArray;\n return this.encodeVectorJson(vector) as any;\n }\n return super.jsToSqlValue(column, value);\n }\n\n /**\n * Override sqlToJsValue to decode vector BLOBs back to TypedArrays\n */\n protected sqlToJsValue(column: string, value: any): Entity[keyof Entity] {\n if (column === String(this.vectorPropertyName) && value != null) {\n return this.decodeVector(value) as Entity[keyof Entity];\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Override mapTypeToSQL to use BLOB for vector columns instead of TEXT\n */\n protected mapTypeToSQL(typeDef: any): string {\n if (typeof typeDef !== \"boolean\" && typeDef.type === \"array\") {\n const format = typeDef.format as string | undefined;\n if (format === \"TypedArray\" || format?.startsWith(\"TypedArray:\")) {\n return \"BLOB\";\n }\n }\n return super.mapTypeToSQL(typeDef);\n }\n\n /**\n * Override put to use sqlite-vector encoding for vector data.\n * Builds a custom INSERT OR REPLACE that wraps the vector column\n * with vector_as_fXX() to encode as a native vector BLOB.\n * Falls back to base class put() if the extension is not available.\n */\n async put(entity: any): Promise<Entity> {\n if (!this.extensionLoaded) {\n return super.put(entity);\n }\n\n const db = this.database;\n const vectorCol = String(this.vectorPropertyName);\n\n // Handle auto-generated keys (UUID generation)\n let entityToInsert = entity;\n if ((this as any).hasAutoGeneratedKey() && (this as any).autoGeneratedKeyName) {\n const keyName = String((this as any).autoGeneratedKeyName);\n const clientProvidedValue = (entity as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n const clientProvidedKeys = (this as any).clientProvidedKeys;\n const autoGeneratedKeyStrategy = (this as any).autoGeneratedKeyStrategy;\n\n if (\n autoGeneratedKeyStrategy === \"uuid\" &&\n !hasClientValue &&\n clientProvidedKeys !== \"always\"\n ) {\n const generatedValue = (this as any).generateKeyValue(keyName, \"uuid\");\n entityToInsert = { ...entity, [keyName]: generatedValue };\n }\n }\n\n // Build column lists and values\n const allColumns: string[] = [];\n const placeholders: string[] = [];\n const params: any[] = [];\n\n // Primary key columns\n const pkColumns = this.primaryKeyColumns() as string[];\n for (const col of pkColumns) {\n const autoGeneratedKeyStrategy = (this as any).autoGeneratedKeyStrategy;\n const isAutoKey = (this as any).isAutoGeneratedKey(col);\n if (isAutoKey && autoGeneratedKeyStrategy === \"autoincrement\") {\n const clientProvidedKeys = (this as any).clientProvidedKeys;\n const clientValue = (entityToInsert as Record<string, unknown>)[col];\n if (clientProvidedKeys === \"if-missing\" && clientValue != null) {\n allColumns.push(col);\n placeholders.push(\"?\");\n params.push((this as any).jsToSqlValue(col, clientValue));\n }\n continue;\n }\n allColumns.push(col);\n placeholders.push(\"?\");\n params.push(this.jsToSqlValue(col, (entityToInsert as Record<string, unknown>)[col] as any));\n }\n\n // Value columns\n const valueColumns = this.valueColumns() as string[];\n for (const col of valueColumns) {\n allColumns.push(col);\n const value = (entityToInsert as Record<string, unknown>)[col];\n\n if (col === vectorCol && value != null) {\n // Use vector_as_fXX() for the vector column\n placeholders.push(`vector_as_${this.vectorTypeSuffix}(?)`);\n params.push(this.encodeVectorJson(value as TypedArray));\n } else {\n placeholders.push(\"?\");\n params.push(this.jsToSqlValue(col, value as any));\n }\n }\n\n const columnList = allColumns.map((c) => `\\`${c}\\``).join(\", \");\n const placeholderList = placeholders.join(\", \");\n\n const sql = `\n INSERT OR REPLACE INTO ${escapeIdentifier(this.table)} (${columnList})\n VALUES (${placeholderList})\n RETURNING *\n `;\n\n // Ensure all params are SQLite-compatible\n for (let i = 0; i < params.length; i++) {\n if (params[i] === undefined) {\n params[i] = null;\n } else if (params[i] !== null && typeof params[i] === \"object\") {\n const p = params[i];\n if (\n !(p instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(p instanceof Buffer))\n ) {\n params[i] = JSON.stringify(p);\n }\n }\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore - SQLite typing for variadic bindings\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const k in this.schema.properties) {\n updatedRecord[k] = this.sqlToJsValue(k, updatedRecord[k] as any);\n }\n\n (this as any).events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Perform similarity search using sqlite-vector's vector_full_scan.\n * Uses native COSINE distance computation in SQLite rather than in-memory JS.\n * Falls back to in-memory search if the extension is unavailable.\n */\n async similaritySearch(query: TypedArray, options: VectorSearchOptions<Metadata> = {}) {\n if (!this.extensionLoaded) {\n return this.searchFallback(query, options);\n }\n\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const db = this.database;\n const tableName = this.table;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n try {\n const queryJson = this.encodeVectorJson(query);\n const queryBlob = db\n .prepare(`SELECT vector_as_${this.vectorTypeSuffix}(?) as v`)\n .get(queryJson) as { v: Buffer };\n\n if (filter && Object.keys(filter).length > 0) {\n // When filtering, use streaming mode (no k parameter) so we can filter rows\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const results: Array<Entity & { score: number }> = [];\n for (const row of rows) {\n // Convert distance to similarity score (cosine distance to cosine similarity)\n const score = 1 - row.distance;\n\n if (score < scoreThreshold) {\n continue;\n }\n\n // Convert SQL values to JS\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n // Apply metadata filter (use empty object if no metadata column)\n const metadata = metadataCol ? (entity[metadataCol] as Metadata) : ({} as Metadata);\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n results.push({ ...entity, score } as Entity & { score: number });\n\n if (results.length >= topK) {\n break;\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, topK);\n }\n\n // No filter - use top-k mode for efficiency\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v, topK) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const results: Array<Entity & { score: number }> = [];\n for (const row of rows) {\n const score = 1 - row.distance;\n\n if (score < scoreThreshold) {\n continue;\n }\n\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n results.push({ ...entity, score } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n // Fall back to in-memory similarity calculation if sqlite-vector fails\n console.warn(\"sqlite-vector query failed, falling back to in-memory search:\", error);\n return this.searchFallback(query, options);\n }\n }\n\n /**\n * Hybrid search combining vector similarity with text relevance.\n * Uses sqlite-vector for the vector component and keyword matching for text.\n * Falls back to in-memory search if the extension is unavailable.\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 if (!this.extensionLoaded) {\n return this.hybridSearchFallback(query, options);\n }\n\n const db = this.database;\n const tableName = this.table;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n try {\n const queryJson = this.encodeVectorJson(query);\n const queryBlob = db\n .prepare(`SELECT vector_as_${this.vectorTypeSuffix}(?) as v`)\n .get(queryJson) as { v: Buffer };\n\n // Use streaming mode for hybrid search to allow text scoring on all results\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const queryLower = textQuery.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n const results: Array<Entity & { score: number }> = [];\n\n for (const row of rows) {\n const vectorScore = 1 - row.distance;\n\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n const metadata = metadataCol ? (entity[metadataCol] as Metadata) : ({} as Metadata);\n\n // Apply metadata filter\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate text relevance\n const metadataText = Object.values(metadata ?? {}).join(\" \").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 continue;\n }\n\n results.push({ ...entity, score: combinedScore } as Entity & { score: number });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, topK);\n } catch (error) {\n console.warn(\"sqlite-vector 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 && !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 return results.slice(0, topK);\n }\n\n /**\n * Fallback hybrid search using in-memory computation\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 && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n const vectorScore = cosineSimilarity(query, vector);\n const metadataText = Object.values(metadata ?? {}).join(\" \").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 return results.slice(0, topK);\n }\n}\n",
|
|
48
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { Sqlite } from \"@workglow/storage/sqlite\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { SqliteTabularStorage } from \"../tabular/SqliteTabularStorage\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\n\n/**\n * Maps TypedArray constructor types to their sqlite-vector encoding function names\n * and corresponding distance metric types.\n */\nconst VECTOR_TYPE_MAP: Record<string, string> = {\n Float32Array: \"f32\",\n Float64Array: \"f32\", // sqlite-vector doesn't support f64, convert to f32\n Int8Array: \"i8\",\n Uint8Array: \"u8\",\n Int16Array: \"f16\", // approximate mapping\n};\n\n/**\n * Gets the sqlite-vector encoding function suffix for a given TypedArray type\n */\nfunction getVectorTypeSuffix(VectorType: { new (array: number[]): TypedArray }): string {\n return VECTOR_TYPE_MAP[VectorType.name] || \"f32\";\n}\n\n/**\n * Gets the sqlite-vector type string for vector_init options\n */\nfunction getVectorTypeOption(VectorType: { new (array: number[]): TypedArray }): string {\n const typeMap: Record<string, string> = {\n Float32Array: \"FLOAT32\",\n Float64Array: \"FLOAT32\",\n Int8Array: \"INT8\",\n Uint8Array: \"UINT8\",\n Int16Array: \"FLOAT16\",\n };\n return typeMap[VectorType.name] || \"FLOAT32\";\n}\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(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/**\n * Escape a SQL identifier (table/column name) by doubling any backtick characters,\n * then wrapping in backticks. This prevents SQL injection via identifier names.\n */\nfunction escapeIdentifier(name: string): string {\n return \"`\" + name.replace(/`/g, \"``\") + \"`\";\n}\n\n/**\n * SQLite vector storage implementation using the @sqliteai/sqlite-vector extension.\n * Provides native vector similarity search via SQLite virtual table functions\n * instead of in-memory brute-force search.\n *\n * Requirements:\n * - @sqliteai/sqlite-vector package installed\n * - Extension loaded via db.loadExtension(getExtensionPath())\n *\n * Vectors are stored as BLOBs using sqlite-vector encoding functions (vector_as_f32, etc.)\n * and searched using vector_full_scan for efficient KNN queries.\n *\n * @template Schema - The schema for the vector storage\n * @template PrimaryKeyNames - The primary key names\n * @template Vector - The vector type (default Float32Array)\n * @template Metadata - The metadata type\n */\nexport class SqliteAiVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Vector extends TypedArray = Float32Array,\n Metadata extends Record<string, unknown> | undefined = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends SqliteTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private VectorType: new (array: number[]) => TypedArray;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n private vectorTypeSuffix: string;\n private extensionLoaded: boolean = false;\n\n /**\n * Creates a new SQLite AI vector storage\n * @param dbOrPath - Either a Database instance or a path to the SQLite database file\n * @param table - The name of the table to use for storage\n * @param schema - The schema for the entity\n * @param primaryKeyNames - Array of property names forming the primary key\n * @param indexes - Array of columns to index\n * @param dimensions - The number of dimensions of the vector\n * @param VectorType - The type of vector to use (defaults to Float32Array)\n */\n constructor(\n dbOrPath: string | Sqlite.Database,\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array\n ) {\n super(dbOrPath, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\n this.vectorTypeSuffix = getVectorTypeSuffix(VectorType);\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 getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /**\n * Load the sqlite-vector extension and initialize vector indexing on the vector column.\n * Extension loading is best-effort: if unavailable, operations fall back to in-memory search.\n */\n public override async setupDatabase(): Promise<void> {\n // Always create the table first via the parent class\n await super.setupDatabase();\n\n // Try to load the sqlite-vector extension if not already loaded\n if (!this.extensionLoaded) {\n try {\n // Try to load the extension - the caller may have already loaded it\n const { getExtensionPath } = await import(\"@sqliteai/sqlite-vector\");\n this.database.loadExtension(getExtensionPath());\n this.extensionLoaded = true;\n } catch {\n // Extension might already be loaded by the caller; verify with vector_version()\n try {\n this.database.exec(\"SELECT vector_version()\");\n this.extensionLoaded = true;\n } catch {\n // Extension is unavailable; operations will fall back to in-memory search\n }\n }\n }\n\n // Initialize the vector column for sqlite-vector indexing (only if extension is available)\n if (this.extensionLoaded) {\n const vectorCol = String(this.vectorPropertyName);\n const vectorType = getVectorTypeOption(this.VectorType);\n try {\n this.database\n .prepare(\"SELECT vector_init(?, ?, ?)\")\n .run(\n this.table,\n vectorCol,\n `dimension=${this.vectorDimensions},type=${vectorType},distance=COSINE`\n );\n } catch {\n // vector_init may fail if already initialized, that's OK\n }\n }\n }\n\n /**\n * Encode a vector as a BLOB using sqlite-vector functions.\n * Returns a JSON string representation suitable for vector_as_f32() etc.\n */\n private encodeVectorJson(vector: TypedArray): string {\n return `[${Array.from(vector).join(\",\")}]`;\n }\n\n /**\n * Decode a vector BLOB from SQLite back to a TypedArray.\n * sqlite-vector stores vectors as BLOBs, but when we SELECT them\n * they come back as Buffer/Uint8Array. We also handle JSON string fallback.\n */\n private decodeVector(raw: unknown): TypedArray {\n if (raw instanceof Uint8Array || (typeof Buffer !== \"undefined\" && raw instanceof Buffer)) {\n // Normalize to a Uint8Array view so we respect byteOffset/byteLength for Buffer as well.\n const view =\n raw instanceof Uint8Array\n ? raw\n : new Uint8Array(\n (raw as Buffer).buffer,\n (raw as Buffer).byteOffset,\n (raw as Buffer).byteLength\n );\n\n if (this.VectorType === Float32Array || this.VectorType.name === \"Float32Array\") {\n return new Float32Array(view.buffer, view.byteOffset, this.vectorDimensions) as TypedArray;\n }\n // For other types, read as float32 and convert\n const f32 = new Float32Array(view.buffer, view.byteOffset, this.vectorDimensions);\n return new this.VectorType(Array.from(f32));\n }\n if (typeof raw === \"string\") {\n // JSON string fallback\n const array = JSON.parse(raw);\n return new this.VectorType(array);\n }\n if (Array.isArray(raw)) {\n return new this.VectorType(raw);\n }\n throw new Error(`Cannot decode vector from type: ${typeof raw}`);\n }\n\n /**\n * Override jsToSqlValue to encode vectors as BLOBs via sqlite-vector functions\n */\n protected override jsToSqlValue(\n column: string,\n value: Entity[keyof Entity]\n ): ReturnType<SqliteTabularStorage<Schema, PrimaryKeyNames, Entity>[\"jsToSqlValue\"]> {\n if (column === String(this.vectorPropertyName) && value != null) {\n // For vector columns, encode as JSON string for sqlite-vector\n const vector = value as unknown as TypedArray;\n return this.encodeVectorJson(vector) as any;\n }\n return super.jsToSqlValue(column, value);\n }\n\n /**\n * Override sqlToJsValue to decode vector BLOBs back to TypedArrays\n */\n protected override sqlToJsValue(column: string, value: any): Entity[keyof Entity] {\n if (column === String(this.vectorPropertyName) && value != null) {\n return this.decodeVector(value) as Entity[keyof Entity];\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Override mapTypeToSQL to use BLOB for vector columns instead of TEXT\n */\n protected override mapTypeToSQL(typeDef: any): string {\n if (typeof typeDef !== \"boolean\" && typeDef.type === \"array\") {\n const format = typeDef.format as string | undefined;\n if (format === \"TypedArray\" || format?.startsWith(\"TypedArray:\")) {\n return \"BLOB\";\n }\n }\n return super.mapTypeToSQL(typeDef);\n }\n\n /**\n * Override put to use sqlite-vector encoding for vector data.\n * Builds a custom INSERT OR REPLACE that wraps the vector column\n * with vector_as_fXX() to encode as a native vector BLOB.\n * Falls back to base class put() if the extension is not available.\n */\n public override async put(entity: any): Promise<Entity> {\n if (!this.extensionLoaded) {\n return super.put(entity);\n }\n\n const db = this.database;\n const vectorCol = String(this.vectorPropertyName);\n\n // Handle auto-generated keys (UUID generation)\n let entityToInsert = entity;\n if ((this as any).hasAutoGeneratedKey() && (this as any).autoGeneratedKeyName) {\n const keyName = String((this as any).autoGeneratedKeyName);\n const clientProvidedValue = (entity as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n const clientProvidedKeys = (this as any).clientProvidedKeys;\n const autoGeneratedKeyStrategy = (this as any).autoGeneratedKeyStrategy;\n\n if (\n autoGeneratedKeyStrategy === \"uuid\" &&\n !hasClientValue &&\n clientProvidedKeys !== \"always\"\n ) {\n const generatedValue = (this as any).generateKeyValue(keyName, \"uuid\");\n entityToInsert = { ...entity, [keyName]: generatedValue };\n }\n }\n\n // Build column lists and values\n const allColumns: string[] = [];\n const placeholders: string[] = [];\n const params: any[] = [];\n\n // Primary key columns\n const pkColumns = this.primaryKeyColumns() as string[];\n for (const col of pkColumns) {\n const autoGeneratedKeyStrategy = (this as any).autoGeneratedKeyStrategy;\n const isAutoKey = (this as any).isAutoGeneratedKey(col);\n if (isAutoKey && autoGeneratedKeyStrategy === \"autoincrement\") {\n const clientProvidedKeys = (this as any).clientProvidedKeys;\n const clientValue = (entityToInsert as Record<string, unknown>)[col];\n if (clientProvidedKeys === \"if-missing\" && clientValue != null) {\n allColumns.push(col);\n placeholders.push(\"?\");\n params.push((this as any).jsToSqlValue(col, clientValue));\n }\n continue;\n }\n allColumns.push(col);\n placeholders.push(\"?\");\n params.push(this.jsToSqlValue(col, (entityToInsert as Record<string, unknown>)[col] as any));\n }\n\n // Value columns\n const valueColumns = this.valueColumns() as string[];\n for (const col of valueColumns) {\n allColumns.push(col);\n const value = (entityToInsert as Record<string, unknown>)[col];\n\n if (col === vectorCol && value != null) {\n // Use vector_as_fXX() for the vector column\n placeholders.push(`vector_as_${this.vectorTypeSuffix}(?)`);\n params.push(this.encodeVectorJson(value as TypedArray));\n } else {\n placeholders.push(\"?\");\n params.push(this.jsToSqlValue(col, value as any));\n }\n }\n\n const columnList = allColumns.map((c) => `\\`${c}\\``).join(\", \");\n const placeholderList = placeholders.join(\", \");\n\n const sql = `\n INSERT OR REPLACE INTO ${escapeIdentifier(this.table)} (${columnList})\n VALUES (${placeholderList})\n RETURNING *\n `;\n\n // Ensure all params are SQLite-compatible\n for (let i = 0; i < params.length; i++) {\n if (params[i] === undefined) {\n params[i] = null;\n } else if (params[i] !== null && typeof params[i] === \"object\") {\n const p = params[i];\n if (\n !(p instanceof Uint8Array) &&\n (typeof Buffer === \"undefined\" || !(p instanceof Buffer))\n ) {\n params[i] = JSON.stringify(p);\n }\n }\n }\n\n const stmt = db.prepare(sql);\n // @ts-ignore - SQLite typing for variadic bindings\n const updatedEntity = stmt.get(...params) as Entity;\n\n // Convert all columns according to schema\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const k in this.schema.properties) {\n updatedRecord[k] = this.sqlToJsValue(k, updatedRecord[k] as any);\n }\n\n (this as any).events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Perform similarity search using sqlite-vector's vector_full_scan.\n * Uses native COSINE distance computation in SQLite rather than in-memory JS.\n * Falls back to in-memory search if the extension is unavailable.\n */\n async similaritySearch(query: TypedArray, options: VectorSearchOptions<Metadata> = {}) {\n if (!this.extensionLoaded) {\n return this.searchFallback(query, options);\n }\n\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const db = this.database;\n const tableName = this.table;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n try {\n const queryJson = this.encodeVectorJson(query);\n const queryBlob = db\n .prepare(`SELECT vector_as_${this.vectorTypeSuffix}(?) as v`)\n .get(queryJson) as { v: Buffer };\n\n if (filter && Object.keys(filter).length > 0) {\n // When filtering, use streaming mode (no k parameter) so we can filter rows\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const results: Array<Entity & { score: number }> = [];\n for (const row of rows) {\n // Convert distance to similarity score (cosine distance to cosine similarity)\n const score = 1 - row.distance;\n\n if (score < scoreThreshold) {\n continue;\n }\n\n // Convert SQL values to JS\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n // Apply metadata filter (use empty object if no metadata column)\n const metadata = metadataCol ? (entity[metadataCol] as Metadata) : ({} as Metadata);\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n results.push({ ...entity, score } as Entity & { score: number });\n\n if (results.length >= topK) {\n break;\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, topK);\n }\n\n // No filter - use top-k mode for efficiency\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v, topK) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const results: Array<Entity & { score: number }> = [];\n for (const row of rows) {\n const score = 1 - row.distance;\n\n if (score < scoreThreshold) {\n continue;\n }\n\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n results.push({ ...entity, score } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n // Fall back to in-memory similarity calculation if sqlite-vector fails\n console.warn(\"sqlite-vector query failed, falling back to in-memory search:\", error);\n return this.searchFallback(query, options);\n }\n }\n\n /**\n * Hybrid search combining vector similarity with text relevance.\n * Uses sqlite-vector for the vector component and keyword matching for text.\n * Falls back to in-memory search if the extension is unavailable.\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 if (!this.extensionLoaded) {\n return this.hybridSearchFallback(query, options);\n }\n\n const db = this.database;\n const tableName = this.table;\n const vectorCol = String(this.vectorPropertyName);\n const metadataCol = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n\n try {\n const queryJson = this.encodeVectorJson(query);\n const queryBlob = db\n .prepare(`SELECT vector_as_${this.vectorTypeSuffix}(?) as v`)\n .get(queryJson) as { v: Buffer };\n\n // Use streaming mode for hybrid search to allow text scoring on all results\n const sql = `\n SELECT t.*, v.distance\n FROM ${escapeIdentifier(tableName)} AS t\n JOIN vector_full_scan(?, ?, ?) AS v\n ON t.rowid = v.rowid\n ORDER BY v.distance ASC\n `;\n const stmt = db.prepare(sql);\n const rows = stmt.all(tableName, vectorCol, queryBlob.v) as Array<\n Record<string, unknown> & { distance: number }\n >;\n\n const queryLower = textQuery.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n const results: Array<Entity & { score: number }> = [];\n\n for (const row of rows) {\n const vectorScore = 1 - row.distance;\n\n const entity = { ...row } as Record<string, unknown>;\n delete entity.distance;\n for (const k in this.schema.properties) {\n entity[k] = this.sqlToJsValue(k, entity[k] as any);\n }\n\n const metadata = metadataCol ? (entity[metadataCol] as Metadata) : ({} as Metadata);\n\n // Apply metadata filter\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate text relevance\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 continue;\n }\n\n results.push({ ...entity, score: combinedScore } as Entity & { score: number });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, topK);\n } catch (error) {\n console.warn(\"sqlite-vector 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 && !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 return results.slice(0, topK);\n }\n\n /**\n * Fallback hybrid search using in-memory computation\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 && !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 return results.slice(0, topK);\n }\n}\n",
|
|
49
49
|
"/**\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 { IndexedDbTabularStorage } from \"../tabular/IndexedDbTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, IKvStorage } from \"./IKvStorage\";\nimport { KvViaTabularStorage } from \"./KvViaTabularStorage\";\n\nexport const IDB_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.indexedDb\"\n);\n\n/**\n * A key-value repository implementation that uses IndexedDB for persistent storage in the browser.\n * Leverages a tabular repository abstraction for IndexedDB 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 IndexedDbKvStorage extends KvViaTabularStorage {\n public tabularRepository: IndexedDbTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public dbName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new IndexedDbTabularStorage(\n dbName,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
|
|
50
|
-
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\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 IndexedDbTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Promise that resolves to the IndexedDB database instance */\n private db: IDBDatabase | undefined;\n /** Promise to track ongoing database setup to prevent concurrent setup calls */\n private setupPromise: Promise<IDBDatabase> | null = null;\n /** Migration options for database schema changes */\n private migrationOptions: MigrationOptions;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\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 migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n /**\n * Internal method to get the database, setting it up if needed.\n * This ensures lazy initialization of the database.\n */\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n }\n\n /**\n * Internal method to perform the actual database setup\n */\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n // Create index definitions for both single and compound indexes\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n // Handle compound index\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create compound index name and keyPath\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // Determine if we should use autoIncrement\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n // Ensure that our table is created/upgraded only if the structure (indexes) has changed.\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n /**\n * Generates a key value for UUID keys\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected generateKeyValue(columnName: string, strategy: KeyGenerationStrategy): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by IndexedDB's autoIncrement option\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a row in the repository.\n * @param record - The entity to store (may be missing auto-generated keys).\n * @returns The stored entity\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = record as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // UUID generation - must be done client-side\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Autoincrement handled by IndexedDB\n // If clientProvidedKeys is \"always\", require the value\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n // If clientProvidedKeys is \"never\", omit the key to let IDB generate\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n // \"if-missing\": use client value if provided, omit if not\n }\n }\n\n // Merge key and value, ensuring all fields are at the root level for indexing\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n // For autoincrement keys, we need to update the record with the generated key\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n // Get the generated key from the request result\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n this.events.emit(\"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param records - Array of entities to store (may be missing auto-generated keys).\n * @returns Array of stored entities\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(records.map((record) => this.put(record)));\n }\n\n protected getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * Retrieves a value from the repository by its key.\n * @param key - The key object.\n * @returns The value object or undefined if not found.\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n this.events.emit(\"get\", key, undefined);\n resolve(undefined);\n return;\n }\n this.events.emit(\"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository.\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The key object to delete.\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"delete\", key as keyof Entity);\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Deletes all records from the repository.\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Returns the total number of rows in the repository.\n * @returns Count of stored items.\n */\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\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 if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n // Skip to offset using advance\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n // Collect records up to the limit\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n // No more records\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n /**\n * Checks if a record matches all criteria conditions.\n * @param record - The record to check\n * @param criteria - The search criteria\n * @returns true if all conditions match\n */\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\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 // Skip null values for comparison operators\n if (operator !== \"=\" && (recordValue === null || recordValue === undefined)) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n if (recordValue !== value) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\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 = await this.getDb();\n\n return new Promise(async (resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n // Set up transaction event handlers\n transaction.oncomplete = () => {\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n // Get all records and filter\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n // Filter records that match all criteria\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n // No records to delete\n return;\n }\n\n // Delete each record that matches the criteria\n for (const record of recordsToDelete) {\n // Extract the primary key from the record\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-ignore - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n // Delete the record using the primary key\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\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 = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n let results: Entity[] = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n });\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager.\n * This ensures all subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on table name\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n (a, b) => JSON.stringify(a) === JSON.stringify(b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDatabase() here to keep the method synchronous\n // The getAll() method in the hybrid manager will call setupDatabase() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys this repository and frees up resources.\n */\n destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n",
|
|
50
|
+
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\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 IndexedDbTabularStorage<\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 BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Promise that resolves to the IndexedDB database instance */\n private db: IDBDatabase | undefined;\n /** Promise to track ongoing database setup to prevent concurrent setup calls */\n private setupPromise: Promise<IDBDatabase> | null = null;\n /** Migration options for database schema changes */\n private migrationOptions: MigrationOptions;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\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 migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n /**\n * Internal method to get the database, setting it up if needed.\n * This ensures lazy initialization of the database.\n */\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n }\n\n /**\n * Internal method to perform the actual database setup\n */\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n // Create index definitions for both single and compound indexes\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n // Handle compound index\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create compound index name and keyPath\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // Determine if we should use autoIncrement\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n // Ensure that our table is created/upgraded only if the structure (indexes) has changed.\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n /**\n * Generates a key value for UUID keys\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by IndexedDB's autoIncrement option\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a row in the repository.\n * @param record - The entity to store (may be missing auto-generated keys).\n * @returns The stored entity\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = record as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // UUID generation - must be done client-side\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Autoincrement handled by IndexedDB\n // If clientProvidedKeys is \"always\", require the value\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n // If clientProvidedKeys is \"never\", omit the key to let IDB generate\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n // \"if-missing\": use client value if provided, omit if not\n }\n }\n\n // Merge key and value, ensuring all fields are at the root level for indexing\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n // For autoincrement keys, we need to update the record with the generated key\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n // Get the generated key from the request result\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n this.events.emit(\"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param records - Array of entities to store (may be missing auto-generated keys).\n * @returns Array of stored entities\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(records.map((record) => this.put(record)));\n }\n\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * Retrieves a value from the repository by its key.\n * @param key - The key object.\n * @returns The value object or undefined if not found.\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n this.events.emit(\"get\", key, undefined);\n resolve(undefined);\n return;\n }\n this.events.emit(\"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository.\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The key object to delete.\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"delete\", key as keyof Entity);\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Deletes all records from the repository.\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Returns the total number of rows in the repository.\n * @returns Count of stored items.\n */\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\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 if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n // Skip to offset using advance\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n // Collect records up to the limit\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n // No more records\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n /**\n * Checks if a record matches all criteria conditions.\n * @param record - The record to check\n * @param criteria - The search criteria\n * @returns true if all conditions match\n */\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\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 // Skip null values for comparison operators\n if (operator !== \"=\" && (recordValue === null || recordValue === undefined)) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n if (recordValue !== value) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\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 = await this.getDb();\n\n return new Promise(async (resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n // Set up transaction event handlers\n transaction.oncomplete = () => {\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n // Get all records and filter\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n // Filter records that match all criteria\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n // No records to delete\n return;\n }\n\n // Delete each record that matches the criteria\n for (const record of recordsToDelete) {\n // Extract the primary key from the record\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-ignore - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n // Delete the record using the primary key\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\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 = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n let results: Entity[] = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (options?.orderBy && options.orderBy.length > 0) {\n results.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n results = results.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n results = results.slice(0, options.limit);\n }\n\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n });\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager.\n * This ensures all subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on table name\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n (a, b) => JSON.stringify(a) === JSON.stringify(b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDatabase() here to keep the method synchronous\n // The getAll() method in the hybrid manager will call setupDatabase() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys this repository and frees up resources.\n */\n public override destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n",
|
|
51
51
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Production-ready IndexedDB table management with proper migration support.\n// Handles schema evolution without data loss by incrementally migrating the database\n// structure and transforming existing data as needed.\n\nexport interface ExpectedIndexDefinition {\n name: string;\n keyPath: string | string[];\n options?: IDBIndexParameters;\n}\n\nexport interface MigrationContext {\n db: IDBDatabase;\n transaction: IDBTransaction;\n oldVersion: number;\n newVersion: number;\n tableName: string;\n}\n\nexport interface DataTransformer {\n (oldData: any): any | Promise<any>;\n}\n\nexport interface MigrationOptions {\n /** Custom data transformer to apply during migration */\n dataTransformer?: DataTransformer;\n /** Whether to allow destructive operations (delete and recreate). Default: false */\n allowDestructiveMigration?: boolean;\n /** Callback for migration progress/logging */\n onMigrationProgress?: (message: string, progress?: number) => void;\n /** Callback for migration errors (non-fatal warnings) */\n onMigrationWarning?: (message: string, error?: Error) => void;\n}\n\ninterface SchemaSnapshot {\n version: number;\n primaryKey: string | string[];\n indexes: ExpectedIndexDefinition[];\n recordCount?: number;\n timestamp: number;\n}\n\nconst METADATA_STORE_NAME = \"__schema_metadata__\";\n\n/**\n * Stores metadata about the database schema for migration tracking\n */\nasync function saveSchemaMetadata(\n db: IDBDatabase,\n tableName: string,\n snapshot: SchemaSnapshot\n): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const transaction = db.transaction(METADATA_STORE_NAME, \"readwrite\");\n const store = transaction.objectStore(METADATA_STORE_NAME);\n const request = store.put({ ...snapshot, tableName }, tableName);\n\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n transaction.onerror = () => reject(transaction.error);\n } catch (err) {\n // Metadata store might not exist in old databases, that's OK\n resolve();\n }\n });\n}\n\n/**\n * Retrieves stored metadata about the database schema\n */\nasync function loadSchemaMetadata(\n db: IDBDatabase,\n tableName: string\n): Promise<SchemaSnapshot | null> {\n return new Promise((resolve) => {\n try {\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n resolve(null);\n return;\n }\n\n const transaction = db.transaction(METADATA_STORE_NAME, \"readonly\");\n const store = transaction.objectStore(METADATA_STORE_NAME);\n const request = store.get(tableName);\n\n request.onsuccess = () => resolve(request.result || null);\n request.onerror = () => resolve(null);\n transaction.onerror = () => resolve(null);\n } catch (err) {\n resolve(null);\n }\n });\n}\n\n/**\n * Opens an IndexedDB database with proper error handling\n */\nasync function openIndexedDbTable(\n tableName: string,\n version?: number,\n upgradeNeededCallback?: (event: IDBVersionChangeEvent) => void\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const openRequest = indexedDB.open(tableName, version);\n\n openRequest.onsuccess = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Handle unexpected close\n db.onversionchange = () => {\n db.close();\n };\n\n resolve(db);\n };\n\n openRequest.onupgradeneeded = (event) => {\n if (upgradeNeededCallback) {\n upgradeNeededCallback(event);\n }\n };\n\n openRequest.onerror = () => {\n const error = openRequest.error;\n // Check if it's a VersionError - this means the database exists at a higher version\n if (error && error.name === \"VersionError\") {\n reject(\n new Error(\n `Database ${tableName} exists at a higher version. Cannot open at version ${version || \"current\"}.`\n )\n );\n } else {\n reject(error);\n }\n };\n openRequest.onblocked = () => {\n reject(\n new Error(`Database ${tableName} is blocked. Close all other tabs using this database.`)\n );\n };\n });\n}\n\n/**\n * Deletes an IndexedDB database completely\n */\nasync function deleteIndexedDbTable(tableName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const deleteRequest = indexedDB.deleteDatabase(tableName);\n\n deleteRequest.onsuccess = () => resolve();\n deleteRequest.onerror = () => reject(deleteRequest.error);\n deleteRequest.onblocked = () => {\n reject(\n new Error(`Cannot delete database ${tableName}. Close all other tabs using this database.`)\n );\n };\n });\n}\n\n/**\n * Compares two schema definitions to determine what changes are needed\n */\ninterface SchemaDiff {\n indexesToAdd: ExpectedIndexDefinition[];\n indexesToRemove: string[];\n indexesToModify: ExpectedIndexDefinition[];\n primaryKeyChanged: boolean;\n needsObjectStoreRecreation: boolean;\n}\n\nfunction compareSchemas(\n store: IDBObjectStore,\n expectedPrimaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[]\n): SchemaDiff {\n const diff: SchemaDiff = {\n indexesToAdd: [],\n indexesToRemove: [],\n indexesToModify: [],\n primaryKeyChanged: false,\n needsObjectStoreRecreation: false,\n };\n\n // Check primary key\n const actualKeyPath = store.keyPath;\n const normalizedExpected = Array.isArray(expectedPrimaryKey)\n ? expectedPrimaryKey\n : expectedPrimaryKey;\n const normalizedActual = Array.isArray(actualKeyPath) ? actualKeyPath : actualKeyPath;\n\n if (JSON.stringify(normalizedExpected) !== JSON.stringify(normalizedActual)) {\n diff.primaryKeyChanged = true;\n diff.needsObjectStoreRecreation = true;\n return diff; // If primary key changed, we need full recreation\n }\n\n // Build a map of existing indexes\n const existingIndexes = new Map<string, IDBIndex>();\n for (let i = 0; i < store.indexNames.length; i++) {\n const indexName = store.indexNames[i];\n existingIndexes.set(indexName, store.index(indexName));\n }\n\n // Check for indexes to add or modify\n for (const expectedIdx of expectedIndexes) {\n const existingIdx = existingIndexes.get(expectedIdx.name);\n\n if (!existingIdx) {\n diff.indexesToAdd.push(expectedIdx);\n } else {\n // Compare index properties\n const expectedKeyPath = Array.isArray(expectedIdx.keyPath)\n ? expectedIdx.keyPath\n : [expectedIdx.keyPath];\n const actualKeyPath = Array.isArray(existingIdx.keyPath)\n ? existingIdx.keyPath\n : [existingIdx.keyPath];\n\n const keyPathChanged = JSON.stringify(expectedKeyPath) !== JSON.stringify(actualKeyPath);\n const uniqueChanged = existingIdx.unique !== (expectedIdx.options?.unique ?? false);\n const multiEntryChanged =\n existingIdx.multiEntry !== (expectedIdx.options?.multiEntry ?? false);\n\n if (keyPathChanged || uniqueChanged || multiEntryChanged) {\n diff.indexesToModify.push(expectedIdx);\n }\n\n existingIndexes.delete(expectedIdx.name);\n }\n }\n\n // Remaining indexes should be removed\n diff.indexesToRemove = Array.from(existingIndexes.keys());\n\n return diff;\n}\n\n/**\n * Reads all data from a store\n */\nasync function readAllData(store: IDBObjectStore): Promise<any[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Writes data back to a store\n */\nasync function writeAllData(store: IDBObjectStore, data: any[]): Promise<void> {\n return new Promise((resolve, reject) => {\n let completed = 0;\n const total = data.length;\n\n if (total === 0) {\n resolve();\n return;\n }\n\n const transaction = store.transaction;\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error);\n\n for (const record of data) {\n const request = store.put(record);\n request.onerror = () => reject(request.error);\n }\n });\n}\n\n/**\n * Performs a non-destructive migration by adding/removing indexes\n */\nasync function performIncrementalMigration(\n db: IDBDatabase,\n tableName: string,\n diff: SchemaDiff,\n options: MigrationOptions = {}\n): Promise<IDBDatabase> {\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n db.close();\n\n options.onMigrationProgress?.(\n `Migrating ${tableName} from version ${currentVersion} to ${newVersion}...`,\n 0\n );\n\n return openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n const transaction = (event.target as IDBOpenDBRequest).transaction!;\n const store = transaction.objectStore(tableName);\n\n // Remove outdated indexes\n for (const indexName of diff.indexesToRemove) {\n options.onMigrationProgress?.(`Removing index: ${indexName}`, 0.2);\n store.deleteIndex(indexName);\n }\n\n // Remove and recreate modified indexes\n for (const indexDef of diff.indexesToModify) {\n options.onMigrationProgress?.(`Updating index: ${indexDef.name}`, 0.4);\n if (store.indexNames.contains(indexDef.name)) {\n store.deleteIndex(indexDef.name);\n }\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n // Add new indexes\n for (const indexDef of diff.indexesToAdd) {\n options.onMigrationProgress?.(`Adding index: ${indexDef.name}`, 0.6);\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n options.onMigrationProgress?.(`Migration complete`, 1.0);\n });\n}\n\n/**\n * Performs a destructive migration by recreating the object store\n * This is needed when the primary key changes\n */\nasync function performDestructiveMigration(\n db: IDBDatabase,\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n if (!options.allowDestructiveMigration) {\n throw new Error(\n `Destructive migration required for ${tableName} but not allowed. ` +\n `Primary key has changed. Set allowDestructiveMigration=true to proceed with data loss, ` +\n `or provide a dataTransformer to migrate data.`\n );\n }\n\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n options.onMigrationProgress?.(\n `Performing destructive migration of ${tableName}. Reading existing data...`,\n 0\n );\n\n // Read all existing data\n let existingData: any[] = [];\n try {\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n existingData = await readAllData(store);\n options.onMigrationProgress?.(`Read ${existingData.length} records`, 0.3);\n } catch (err) {\n options.onMigrationWarning?.(\n `Failed to read existing data during migration: ${err}`,\n err as Error\n );\n }\n\n db.close();\n\n // Apply data transformer if provided\n if (options.dataTransformer && existingData.length > 0) {\n options.onMigrationProgress?.(`Transforming ${existingData.length} records...`, 0.4);\n try {\n const transformed = [];\n for (let i = 0; i < existingData.length; i++) {\n const record = existingData[i];\n const transformedRecord = await options.dataTransformer(record);\n if (transformedRecord !== undefined && transformedRecord !== null) {\n transformed.push(transformedRecord);\n }\n if (i % 100 === 0) {\n options.onMigrationProgress?.(\n `Transformed ${i}/${existingData.length} records`,\n 0.4 + (i / existingData.length) * 0.3\n );\n }\n }\n existingData = transformed;\n options.onMigrationProgress?.(`Transformation complete: ${existingData.length} records`, 0.7);\n } catch (err) {\n options.onMigrationWarning?.(\n `Data transformation failed: ${err}. Some data may be lost.`,\n err as Error\n );\n existingData = [];\n }\n }\n\n // Open with new version and recreate object store\n options.onMigrationProgress?.(`Recreating object store...`, 0.75);\n\n const newDb = await openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n const transaction = (event.target as IDBOpenDBRequest).transaction!;\n\n // Delete old object store if it exists\n if (db.objectStoreNames.contains(tableName)) {\n db.deleteObjectStore(tableName);\n }\n\n // Create new object store with new schema\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n\n // Restore data\n if (existingData.length > 0) {\n options.onMigrationProgress?.(`Restoring ${existingData.length} records...`, 0.8);\n\n for (const record of existingData) {\n try {\n store.put(record);\n } catch (err) {\n options.onMigrationWarning?.(`Failed to restore record: ${err}`, err as Error);\n }\n }\n }\n });\n\n options.onMigrationProgress?.(`Destructive migration complete`, 1.0);\n\n return newDb;\n}\n\n/**\n * Creates a new database with the specified schema\n */\nasync function createNewDatabase(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n\n // Delete existing database if it exists to avoid version conflicts\n try {\n await deleteIndexedDbTable(tableName);\n // Wait a bit for deletion to complete\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // Ignore errors - database might not exist\n }\n\n const version = 1;\n\n const db = await openIndexedDbTable(tableName, version, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create metadata store\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n // Create main object store\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n // Save schema metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n\n return db;\n}\n\n/**\n * Ensures that an IndexedDB table exists with the specified schema.\n * Performs migrations as needed without data loss when possible.\n */\nexport async function ensureIndexedDbTable(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[] = [],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n try {\n // Try to open existing database at current version (or create if doesn't exist)\n let db: IDBDatabase;\n let wasJustCreated = false;\n try {\n // Open without version - this will open at current version if exists, or create at version 1 if doesn't exist\n db = await openIndexedDbTable(tableName);\n\n // Check if database was just created (version 1 and no object stores)\n // This happens when indexedDB.open creates a new database without stores\n if (db.version === 1 && !db.objectStoreNames.contains(tableName)) {\n wasJustCreated = true;\n db.close();\n }\n } catch (err: any) {\n // If opening fails, database might not exist or there's a version conflict\n // Try to create it fresh\n options.onMigrationProgress?.(\n `Database ${tableName} does not exist or has version conflict, creating...`,\n 0\n );\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n // If database was just created, we need to create the stores\n // We'll upgrade from version 1 to version 1 (which triggers onupgradeneeded with oldVersion=0)\n // Actually, we need to explicitly create at version 1 with stores\n if (wasJustCreated) {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n // Delete the empty database and create it properly at version 1\n try {\n await deleteIndexedDbTable(tableName);\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // Ignore errors\n }\n\n // Create at version 1 with stores\n db = await openIndexedDbTable(tableName, 1, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create metadata store\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n // Create main object store\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n // Save schema metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n return db;\n }\n\n // Ensure metadata store exists\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n const currentVersion = db.version;\n db.close();\n\n db = await openIndexedDbTable(\n tableName,\n currentVersion + 1,\n (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n }\n );\n }\n\n // Load stored metadata\n const metadata = await loadSchemaMetadata(db, tableName);\n\n // Check if table structure matches expected\n if (!db.objectStoreNames.contains(tableName)) {\n // Object store doesn't exist, create it\n options.onMigrationProgress?.(`Object store ${tableName} does not exist, creating...`, 0);\n db.close();\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n // Compare schemas to determine what migration is needed\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n const diff = compareSchemas(store, primaryKey, expectedIndexes);\n\n await new Promise<void>((resolve) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => resolve();\n });\n\n // Determine migration strategy\n const needsMigration =\n diff.indexesToAdd.length > 0 ||\n diff.indexesToRemove.length > 0 ||\n diff.indexesToModify.length > 0 ||\n diff.needsObjectStoreRecreation;\n\n if (!needsMigration) {\n // Schema matches, no migration needed\n options.onMigrationProgress?.(`Schema for ${tableName} is up to date`, 1.0);\n\n // Update metadata anyway to keep timestamp current\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n }\n\n // Perform appropriate migration\n if (diff.needsObjectStoreRecreation) {\n options.onMigrationProgress?.(\n `Schema change requires object store recreation for ${tableName}`,\n 0\n );\n db = await performDestructiveMigration(\n db,\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n } else {\n options.onMigrationProgress?.(`Performing incremental migration for ${tableName}`, 0);\n db = await performIncrementalMigration(db, tableName, diff, options);\n }\n\n // Save updated metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n } catch (err) {\n options.onMigrationWarning?.(`Migration failed for ${tableName}: ${err}`, err as Error);\n throw err;\n }\n}\n\n/**\n * Utility function to delete a database (for testing or cleanup)\n */\nexport async function dropIndexedDbTable(tableName: string): Promise<void> {\n return deleteIndexedDbTable(tableName);\n}\n",
|
|
52
52
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB rate limiter storage including prefix support.\n */\nexport interface IndexedDbRateLimiterStorageOptions\n extends RateLimiterStorageOptions, MigrationOptions {}\n\n/**\n * Execution record stored in IndexedDB.\n */\ninterface ExecutionRecord {\n readonly id?: string;\n readonly queue_name: string;\n readonly executed_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * Next available record stored in IndexedDB.\n */\ninterface NextAvailableRecord {\n readonly queue_name: string;\n readonly next_available_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * IndexedDB implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class IndexedDbRateLimiterStorage implements IRateLimiterStorage {\n private executionDb: IDBDatabase | undefined;\n private nextAvailableDb: IDBDatabase | undefined;\n private readonly executionTableName: string;\n private readonly nextAvailableTableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n\n constructor(options: IndexedDbRateLimiterStorageOptions = {}) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a record matches the current prefix values.\n */\n private matchesPrefixes(record: Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (record[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction.\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getExecutionDb(): Promise<IDBDatabase> {\n if (this.executionDb) return this.executionDb;\n await this.setupDatabase();\n return this.executionDb!;\n }\n\n private async getNextAvailableDb(): Promise<IDBDatabase> {\n if (this.nextAvailableDb) return this.nextAvailableDb;\n await this.setupDatabase();\n return this.nextAvailableDb!;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const executionIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_executed_at\",\n keyPath: buildKeyPath([\"queue_name\", \"executed_at\"]),\n options: { unique: false },\n },\n ];\n\n this.executionDb = await ensureIndexedDbTable(\n this.executionTableName,\n \"id\",\n executionIndexes,\n this.migrationOptions\n );\n\n const nextAvailableIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_name\",\n keyPath: buildKeyPath([\"queue_name\"]),\n options: { unique: true },\n },\n ];\n\n this.nextAvailableDb = await ensureIndexedDbTable(\n this.nextAvailableTableName,\n buildKeyPath([\"queue_name\"]).join(\"_\"),\n nextAvailableIndexes,\n this.migrationOptions\n );\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readwrite\");\n const store = tx.objectStore(this.executionTableName);\n\n const record: ExecutionRecord = {\n id: crypto.randomUUID(),\n queue_name: queueName,\n executed_at: new Date().toISOString(),\n };\n\n // Add prefix values to the record\n for (const [key, value] of Object.entries(this.prefixValues)) {\n (record as Record<string, unknown>)[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const request = store.add(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n let count = 0;\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, windowStartTime],\n [...prefixKeyValues, queueName, \"\\uffff\"],\n true, // exclude lower bound (windowStartTime)\n false\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n count++;\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(count);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const executions: string[] = [];\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n executions.push(record.executed_at);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Sort by executed_at ascending\n executions.sort();\n resolve(executions[offset]);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readonly\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n return new Promise((resolve, reject) => {\n const request = store.get(key);\n request.onsuccess = () => {\n const record = request.result as NextAvailableRecord | undefined;\n if (record && this.matchesPrefixes(record)) {\n resolve(record.next_available_at);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readwrite\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n const record: NextAvailableRecord & { [key: string]: unknown } = {\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n };\n\n // Add prefix values to the record\n for (const [k, value] of Object.entries(this.prefixValues)) {\n record[k] = value;\n }\n\n // Set the key field\n (record as Record<string, unknown>)[\n this.getPrefixColumnNames().concat([\"queue_name\"]).join(\"_\")\n ] = key;\n\n return new Promise((resolve, reject) => {\n const request = store.put(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async clear(queueName: string): Promise<void> {\n // Clear executions\n const execDb = await this.getExecutionDb();\n const execTx = execDb.transaction(this.executionTableName, \"readwrite\");\n const execStore = execTx.objectStore(this.executionTableName);\n const execIndex = execStore.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n await new Promise<void>((resolve, reject) => {\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = execIndex.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n execTx.oncomplete = () => resolve();\n execTx.onerror = () => reject(execTx.error);\n request.onerror = () => reject(request.error);\n });\n\n // Clear next available\n const nextDb = await this.getNextAvailableDb();\n const nextTx = nextDb.transaction(this.nextAvailableTableName, \"readwrite\");\n const nextStore = nextTx.objectStore(this.nextAvailableTableName);\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n await new Promise<void>((resolve, reject) => {\n const request = nextStore.delete(key);\n nextTx.oncomplete = () => resolve();\n nextTx.onerror = () => reject(nextTx.error);\n request.onerror = () => reject(request.error);\n });\n }\n}\n",
|
|
53
53
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\nexport const INDEXED_DB_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB queue storage including prefix support\n */\nexport interface IndexedDbQueueStorageOptions extends QueueStorageOptions, MigrationOptions {\n /** Enable BroadcastChannel notifications (default: true) */\n readonly useBroadcastChannel?: boolean;\n /** Backup polling interval in ms (default: 5000, 0 to disable) */\n readonly backupPollingIntervalMs?: number;\n}\n\n/**\n * IndexedDB implementation of a job queue storage.\n * Provides storage and retrieval for job execution states using IndexedDB.\n */\nexport class IndexedDbQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n private db: IDBDatabase | undefined;\n private readonly tableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n\n constructor(\n public readonly queueName: string,\n options: IndexedDbQueueStorageOptions = {}\n ) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n this.hybridOptions = {\n useBroadcastChannel: options.useBroadcastChannel ?? true,\n backupPollingIntervalMs: options.backupPollingIntervalMs ?? 5000,\n };\n // Generate table name based on prefix configuration to avoid conflicts\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.tableName = `jobs_${prefixNames}`;\n } else {\n this.tableName = \"jobs\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a job matches the current prefix values\n */\n private matchesPrefixes(job: JobStorageFormat<Input, Output> & Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const expectedIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_status\",\n keyPath: buildKeyPath([\"queue\", \"status\"]),\n options: { unique: false },\n },\n {\n name: \"queue_status_run_after\",\n keyPath: buildKeyPath([\"queue\", \"status\", \"run_after\"]),\n options: { unique: false },\n },\n {\n name: \"queue_job_run_id\",\n keyPath: buildKeyPath([\"queue\", \"job_run_id\"]),\n options: { unique: false },\n },\n {\n name: \"queue_fingerprint_status\",\n keyPath: buildKeyPath([\"queue\", \"fingerprint\", \"status\"]),\n options: { unique: false },\n },\n ];\n\n this.db = await ensureIndexedDbTable(\n this.tableName,\n \"id\",\n expectedIndexes,\n this.migrationOptions\n );\n }\n\n /**\n * Adds a job to the queue.\n * @param job - The job to add to the queue.\n * @returns A promise that resolves to the job id.\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n const db = await this.getDb();\n const now = new Date().toISOString();\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();\n jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();\n jobWithPrefixes.queue = this.queueName;\n jobWithPrefixes.fingerprint = await makeFingerprint(jobWithPrefixes.input);\n jobWithPrefixes.status = JobStatus.PENDING;\n jobWithPrefixes.progress = 0;\n jobWithPrefixes.progress_message = \"\";\n jobWithPrefixes.progress_details = null;\n jobWithPrefixes.created_at = now;\n jobWithPrefixes.run_after = now;\n\n // Add prefix values to the job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const request = store.add(jobWithPrefixes);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve(jobWithPrefixes.id);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieves a job from the queue by its id.\n * @param id - The id of the job to retrieve.\n * @returns A promise that resolves to the job or undefined if the job is not found.\n */\n async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const request = store.get(id as string);\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Filter by queue name and prefix values to ensure job belongs to this queue\n if (job && job.queue === this.queueName && this.matchesPrefixes(job)) {\n resolve(job);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status of the jobs to retrieve.\n * @param num - The number of jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const ret = new Map<unknown, JobStorageFormat<Input, Output>>();\n // Create a key range for the compound index: from [prefixes..., queue, status, \"\"] to [prefixes..., queue, status, \"\\uffff\"]\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, status, \"\"],\n [...prefixKeyValues, this.queueName, status, \"\\uffff\"]\n );\n const cursorRequest = index.openCursor(keyRange);\n\n const handleCursor = (e: Event) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor || ret.size >= num) {\n resolve(Array.from(ret.values()));\n return;\n }\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify prefix match and use Map to ensure no duplicates by job ID\n if (this.matchesPrefixes(job)) {\n ret.set(cursor.value.id, cursor.value);\n }\n cursor.continue();\n };\n\n cursorRequest.onsuccess = handleCursor;\n cursorRequest.onerror = () => reject(cursorRequest.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves the next job from the queue using optimistic locking. In case multiple workers\n * claim the same job, the first worker to claim it will process it and the other workers will return undefined.\n * This ONLY happens if workers are running in multiple tabs.\n *\n * IndexedDB uses snapshot isolation, so concurrent transactions can both see the same\n * PENDING job. To prevent processing the same job multiple times, this method:\n * 1. Claims a job by setting it to PROCESSING with a unique claim token\n * 2. After the transaction completes, re-reads the job to verify the claim succeeded\n * 3. If another worker claimed it first (different claim token), returns undefined\n *\n * @param workerId - Worker ID to associate with the job (required)\n * @returns A promise that resolves to the next job or undefined if the queue is empty.\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const now = new Date().toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n\n // This ensures we can verify that we actually won the race to claim this job\n const claimToken = workerId;\n\n const jobToReturn = await new Promise<JobStorageFormat<Input, Output> | undefined>(\n (resolve, reject) => {\n const cursorRequest = index.openCursor(\n IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, \"\"],\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, now],\n false,\n true\n )\n );\n\n let claimedJob: JobStorageFormat<Input, Output> | undefined;\n let cursorStopped = false;\n\n cursorRequest.onsuccess = (e) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor) {\n // Cursor exhausted - resolve with whatever we found (or undefined)\n return;\n }\n\n // If we already found and updated a job, stop iterating\n if (cursorStopped) {\n return;\n }\n\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify the job belongs to this queue, matches prefixes, and is still in PENDING state\n if (\n job.queue !== this.queueName ||\n job.status !== JobStatus.PENDING ||\n !this.matchesPrefixes(job)\n ) {\n cursor.continue();\n return;\n }\n\n // Claim the job with our unique token\n job.status = JobStatus.PROCESSING;\n job.last_ran_at = now;\n job.worker_id = claimToken;\n\n try {\n const updateRequest = store.put(job);\n updateRequest.onsuccess = () => {\n claimedJob = job;\n cursorStopped = true;\n // Stop cursor iteration - we've claimed a job\n };\n updateRequest.onerror = (err) => {\n console.error(\"Failed to update job status:\", err);\n cursor.continue();\n };\n } catch (err) {\n console.error(\"Error updating job:\", err);\n cursor.continue();\n }\n };\n\n cursorRequest.onerror = () => reject(cursorRequest.error);\n\n // Wait for transaction to complete before resolving\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n if (claimedJob) {\n this.hybridManager?.notifyLocalChange();\n }\n resolve(claimedJob);\n };\n tx.onerror = () => reject(tx.error);\n }\n );\n\n // If we didn't find any job to claim, return undefined\n if (!jobToReturn) {\n return undefined;\n }\n\n // Verify we actually won the race by re-reading the job\n // This is the optimistic locking check - if another worker claimed it first,\n // their claim token will be there instead of ours\n const verifiedJob = await this.get(jobToReturn.id);\n\n if (!verifiedJob) {\n // Job was deleted - we lost the race\n return undefined;\n }\n\n if (verifiedJob.worker_id !== claimToken) {\n // Another worker claimed this job - we lost the race\n return undefined;\n }\n\n if (verifiedJob.status !== JobStatus.PROCESSING) {\n // Job status changed (e.g., another worker completed it already) - we lost the race\n return undefined;\n }\n\n // We successfully claimed the job\n return verifiedJob;\n }\n\n /**\n * Retrieves the number of jobs in the queue.\n * Returns the count of jobs in the queue.\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n const db = await this.getDb();\n const prefixKeyValues = this.getPrefixKeyValues();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n const request = index.count(keyRange);\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Marks a job as complete with its output or error.\n */\n public async complete(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const getReq = store.get(job.id as string);\n getReq.onsuccess = () => {\n const existing = getReq.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Verify job belongs to this queue and matches prefixes\n if (!existing || existing.queue !== this.queueName || !this.matchesPrefixes(existing)) {\n reject(\n new Error(`Job ${job.id} not found or does not belong to queue ${this.queueName}`)\n );\n return;\n }\n const currentAttempts = existing.run_attempts ?? 0;\n job.run_attempts = currentAttempts + 1;\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const putReq = store.put(jobWithPrefixes);\n putReq.onsuccess = () => {};\n putReq.onerror = () => reject(putReq.error);\n };\n getReq.onerror = () => reject(getReq.error);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Aborts a job in the queue.\n */\n public async abort(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n job.status = JobStatus.ABORTING;\n await this.complete(job);\n }\n\n /**\n * Gets jobs by their run ID.\n */\n public async getByRunId(job_run_id: string): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_job_run_id\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, job_run_id]);\n const request = index.getAll(keyRange);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n // Filter results to ensure they match prefixes\n const results = (request.result || []).filter(\n (job: JobStorageFormat<Input, Output> & Record<string, unknown>) =>\n this.matchesPrefixes(job)\n );\n resolve(results);\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n // Use a cursor to iterate through all jobs for this queue with prefix\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue and matches prefixes before deleting\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n const deleteRequest = cursor.delete();\n deleteRequest.onsuccess = () => {\n cursor.continue();\n };\n deleteRequest.onerror = () => {\n // Continue even if delete fails\n cursor.continue();\n };\n } else {\n cursor.continue();\n }\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets the output for a given input.\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n const fingerprint = await makeFingerprint(input);\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_fingerprint_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const request = index.get([\n ...prefixKeyValues,\n this.queueName,\n fingerprint,\n JobStatus.COMPLETED,\n ]);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n if (job && this.matchesPrefixes(job)) {\n resolve(job.output ?? null);\n } else {\n resolve(null);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Saves progress updates for a job.\n */\n public async saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n const job = await this.get(id);\n if (!job) throw new Error(`Job ${id} not found`);\n\n job.progress = progress;\n job.progress_message = message;\n job.progress_details = details;\n\n await this.put(job);\n }\n\n /**\n * Persists a job to the store without modifying run_attempts or other completion logic.\n */\n private async put(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const putReq = store.put(jobWithPrefixes);\n putReq.onerror = () => reject(putReq.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes a job by its ID.\n */\n public async delete(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const request = store.delete(id as string);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n\n return new Promise((resolve, reject) => {\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue, matches prefixes, and matches criteria\n if (\n job.queue === this.queueName &&\n this.matchesPrefixes(job) &&\n job.status === status &&\n job.completed_at &&\n job.completed_at <= cutoffDate\n ) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue that match the current prefix values.\n * Used internally for normal polling-based subscriptions (efficient - filters at DB level).\n *\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobs(): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n // Use a key range that covers all statuses for this queue with prefixes\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n jobs.push(job);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue with a custom prefix filter.\n * Used for subscriptions with custom prefix filters (filters at DB level where possible).\n *\n * @param prefixFilter - The prefix values to filter by (empty object = all jobs)\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobsWithFilter(\n prefixFilter: Readonly<Record<string, string | number>>\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n const request = store.openCursor();\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Filter by queue name\n if (job.queue !== this.queueName) {\n cursor.continue();\n return;\n }\n // If empty filter, include all jobs for this queue\n if (Object.keys(prefixFilter).length === 0) {\n jobs.push(job);\n } else {\n // Check each filter value\n let matches = true;\n for (const [key, value] of Object.entries(prefixFilter)) {\n if (job[key] !== value) {\n matches = false;\n break;\n }\n }\n if (matches) {\n jobs.push(job);\n }\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Checks if a prefix filter is custom (different from instance's prefixes).\n */\n private isCustomPrefixFilter(prefixFilter?: Readonly<Record<string, string | number>>): boolean {\n // No filter specified - use instance prefixes (not custom)\n if (prefixFilter === undefined) {\n return false;\n }\n // Empty filter - receive all (custom)\n if (Object.keys(prefixFilter).length === 0) {\n return true;\n }\n // Check if filter matches instance prefixes exactly\n const instanceKeys = Object.keys(this.prefixValues);\n const filterKeys = Object.keys(prefixFilter);\n if (instanceKeys.length !== filterKeys.length) {\n return true; // Different number of keys = custom\n }\n for (const key of instanceKeys) {\n if (this.prefixValues[key] !== prefixFilter[key]) {\n return true; // Different value = custom\n }\n }\n return false; // Matches instance prefixes exactly\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager for normal subscriptions.\n * This ensures all normal subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on queue name and table name\n const channelName = `indexeddb-queue-${this.tableName}-${this.queueName}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n >(\n channelName,\n async () => {\n // Fetch jobs with instance's prefix filter (efficient DB-level filtering)\n const jobs = await this.getAllJobs();\n return new Map(jobs.map((j) => [j.id, j]));\n },\n (a, b) => JSON.stringify(a) === JSON.stringify(b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Creates a dedicated polling subscription for custom prefix filters.\n * This runs separately from the normal polling manager.\n */\n private subscribeWithCustomPrefixFilter(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter: Readonly<Record<string, string | number>>,\n intervalMs: number\n ): () => void {\n let lastKnownJobs = new Map<unknown, JobStorageFormat<Input, Output>>();\n let cancelled = false;\n\n const poll = async () => {\n if (cancelled) return;\n try {\n const currentJobs = await this.getAllJobsWithFilter(prefixFilter);\n if (cancelled) return;\n const currentMap = new Map(currentJobs.map((j) => [j.id, j]));\n\n // Detect changes\n for (const [id, job] of currentMap) {\n const old = lastKnownJobs.get(id);\n if (!old) {\n callback({ type: \"INSERT\", new: job });\n } else if (JSON.stringify(old) !== JSON.stringify(job)) {\n callback({ type: \"UPDATE\", old, new: job });\n }\n }\n\n for (const [id, job] of lastKnownJobs) {\n if (!currentMap.has(id)) {\n callback({ type: \"DELETE\", old: job });\n }\n }\n\n lastKnownJobs = currentMap;\n } catch {\n // Ignore polling errors\n }\n };\n\n const intervalId = setInterval(poll, intervalMs);\n poll(); // Initial poll\n\n return () => {\n cancelled = true;\n clearInterval(intervalId);\n };\n }\n\n /**\n * Subscribes to changes in the queue.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * Normal subscriptions (no custom prefix filter) share a single polling loop for efficiency.\n * Custom prefix filter subscriptions get their own dedicated polling loop with DB-level filtering.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including polling interval and prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n\n // Check if this is a custom prefix filter subscription\n if (this.isCustomPrefixFilter(options?.prefixFilter)) {\n // Custom prefix filter - use dedicated polling with DB-level filtering\n return this.subscribeWithCustomPrefixFilter(callback, options!.prefixFilter!, intervalMs);\n }\n\n // Normal subscription - use shared hybrid manager (efficient)\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Cleanup method to destroy the hybrid manager\n */\n destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n }\n}\n",
|
|
54
54
|
"/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { IndexedDbTabularStorage } from \"../tabular/IndexedDbTabularStorage\";\nimport type { ClientProvidedKeysOption } from \"../tabular/BaseTabularStorage\";\nimport type { AnyVectorStorage } from \"./IVectorStorage\";\nimport type { MigrationOptions } from \"../util/IndexedDbTable\";\nimport {\n getMetadataProperty,\n getVectorProperty,\n type HybridSearchOptions,\n type IVectorStorage,\n type VectorSearchOptions,\n} from \"./IVectorStorage\";\n\nexport const IDB_VECTOR_REPOSITORY = createServiceToken<AnyVectorStorage>(\n \"storage.vectorRepository.indexedDb\"\n);\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(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/**\n * Simple full-text search scoring (keyword matching)\n */\nfunction textRelevance(text: string, query: string): number {\n const textLower = text.toLowerCase();\n const queryLower = query.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n if (queryWords.length === 0) {\n return 0;\n }\n let matches = 0;\n for (const word of queryWords) {\n if (textLower.includes(word)) {\n matches++;\n }\n }\n return matches / queryWords.length;\n}\n\n/**\n * IndexedDB vector storage implementation.\n * Extends IndexedDbTabularStorage for storage.\n * Suitable for browser applications that need persistent vector storage.\n * No vector serialization needed since IndexedDB supports TypedArrays\n * natively via structured clone.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - The primary key names\n * @template Metadata - The metadata type for the vector\n * @template Vector - The vector type\n * @template Entity - The entity type\n */\nexport class IndexedDbVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Vector extends TypedArray = Float32Array,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends IndexedDbTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private VectorType: new (array: number[]) => TypedArray;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n /**\n * Creates a new IndexedDB vector storage\n * @param table - The name of the IndexedDB store (defaults to 'vectors')\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 VectorType - The type of vector to use (defaults to Float32Array)\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof Entity | readonly (keyof Entity)[])[] = [],\n dimensions: number,\n VectorType: new (array: number[]) => TypedArray = Float32Array,\n migrationOptions: MigrationOptions = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, migrationOptions, clientProvidedKeys);\n\n this.vectorDimensions = dimensions;\n this.VectorType = VectorType;\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 /**\n * Get the vector dimensions\n * @returns The vector dimensions\n */\n getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Record<string, unknown>> = {}\n ) {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const results: Array<Entity & { score: number }> = [];\n\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // IndexedDB stores TypedArrays natively via structured clone (no deserialization needed)\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate similarity\n const score = cosineSimilarity(query, vector);\n\n // Apply threshold\n if (score < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score,\n } as Entity & { score: number });\n }\n\n // Sort by score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n async hybridSearch(query: TypedArray, options: HybridSearchOptions<Record<string, unknown>>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n if (!textQuery || textQuery.trim().length === 0) {\n // Fall back to regular vector search if no text query\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n const results: Array<Entity & { score: number }> = [];\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // IndexedDB stores TypedArrays natively via structured clone (no deserialization needed)\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate vector similarity\n const vectorScore = cosineSimilarity(query, vector);\n\n // Calculate text relevance (simple keyword matching)\n const metadataText = Object.values(metadata).join(\" \").toLowerCase();\n const textScore = textRelevance(metadataText, textQuery);\n\n // Combine scores\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n // Apply threshold\n if (combinedScore < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score: combinedScore,\n } as Entity & { score: number });\n }\n\n // Sort by combined score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n}\n"
|
|
55
55
|
],
|
|
56
|
-
"mappings": "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",
|
|
56
|
+
"mappings": "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",
|
|
57
57
|
"debugId": "120AE6AECCC1B17664756E2164756E21",
|
|
58
58
|
"names": []
|
|
59
59
|
}
|