@payloadcms-vectorize/pg 0.6.0-beta.2 → 0.6.0-beta.3

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.
@@ -3,6 +3,13 @@ import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from '
3
3
  import { join, resolve } from 'path';
4
4
  import toSnakeCase from 'to-snake-case';
5
5
  import { getVectorizedPayload } from 'payloadcms-vectorize';
6
+ function listMigrationFiles(migrationsDir) {
7
+ return readdirSync(migrationsDir).filter((f)=>(f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js').map((f)=>({
8
+ name: f,
9
+ path: join(migrationsDir, f),
10
+ mtime: statSync(join(migrationsDir, f)).mtime
11
+ })).sort((a, b)=>b.mtime.getTime() - a.mtime.getTime());
12
+ }
6
13
  /**
7
14
  * Get prior dims state from existing migrations
8
15
  */ function getPriorDimsFromMigrations(migrationsDir, poolNames) {
@@ -15,12 +22,7 @@ import { getVectorizedPayload } from 'payloadcms-vectorize';
15
22
  return state;
16
23
  }
17
24
  // Find all migration files and read them in reverse order (newest first)
18
- // Exclude index.ts/index.js as those are not migration files
19
- const migrationFiles = readdirSync(migrationsDir).filter((f)=>(f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js').map((f)=>({
20
- name: f,
21
- path: join(migrationsDir, f),
22
- mtime: statSync(join(migrationsDir, f)).mtime
23
- })).sort((a, b)=>b.mtime.getTime() - a.mtime.getTime());
25
+ const migrationFiles = listMigrationFiles(migrationsDir);
24
26
  // Skip the most recent migration when determining prior dims, since it may contain
25
27
  // the pending dims change that we're trying to detect
26
28
  const filesToCheck = migrationFiles.slice(1);
@@ -189,11 +191,7 @@ import { getVectorizedPayload } from 'payloadcms-vectorize';
189
191
  if (!existsSync(migrationsDir)) {
190
192
  throw new Error(`[payloadcms-vectorize] Migrations directory not found: ${migrationsDir}\n` + `Please run 'payload migrate:create' first to create a migration for the dims change.`);
191
193
  }
192
- const migrationFiles = readdirSync(migrationsDir).filter((f)=>(f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js').map((f)=>({
193
- name: f,
194
- path: join(migrationsDir, f),
195
- mtime: statSync(join(migrationsDir, f)).mtime
196
- })).sort((a, b)=>b.mtime.getTime() - a.mtime.getTime());
194
+ const migrationFiles = listMigrationFiles(migrationsDir);
197
195
  if (migrationFiles.length === 0) {
198
196
  throw new Error(`[payloadcms-vectorize] No migration files found in ${migrationsDir}\n` + `Please run 'payload migrate:create' first to create a migration for the dims change.`);
199
197
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/bin-vectorize-migrate.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\nimport { getPayload } from 'payload'\nimport { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from 'fs'\nimport { join, resolve } from 'path'\nimport toSnakeCase from 'to-snake-case'\n\nimport { getVectorizedPayload } from 'payloadcms-vectorize'\nimport { KnowledgePoolsConfig } from './types.js'\n\n/**\n * Get prior dims state from existing migrations\n */\nfunction getPriorDimsFromMigrations(\n migrationsDir: string,\n poolNames: string[],\n): Map<string, number | null> {\n const state = new Map<string, number | null>()\n\n // Initialize with null (unknown state)\n for (const poolName of poolNames) {\n state.set(poolName, null)\n }\n\n if (!existsSync(migrationsDir)) {\n return state\n }\n\n // Find all migration files and read them in reverse order (newest first)\n // Exclude index.ts/index.js as those are not migration files\n const migrationFiles = readdirSync(migrationsDir)\n .filter((f) => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js')\n .map((f) => ({\n name: f,\n path: join(migrationsDir, f),\n mtime: statSync(join(migrationsDir, f)).mtime,\n }))\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime())\n\n // Skip the most recent migration when determining prior dims, since it may contain\n // the pending dims change that we're trying to detect\n const filesToCheck = migrationFiles.slice(1)\n\n // Read migration files to find vector dims\n for (const file of filesToCheck) {\n try {\n const content = readFileSync(file.path, 'utf-8')\n\n // Extract only the UP function content to avoid matching values in DOWN function\n const upFunctionMatch = content.match(\n /export\\s+async\\s+function\\s+up\\s*\\([^)]*\\)[^{]*\\{([\\s\\S]*?)(?=\\}\\s*(?:export\\s+async\\s+function\\s+down|$))/i,\n )\n const upContent = upFunctionMatch ? upFunctionMatch[1] : content\n\n // Look for dims in vector column definition (pool-specific patterns)\n for (const poolName of poolNames) {\n const tableName = toSnakeCase(poolName)\n\n const pattern1 = new RegExp(\n `ALTER\\\\s+TABLE[^;]*?\"${tableName}\"[^;]*?vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n const pattern2 = new RegExp(\n `CREATE\\\\s+TABLE[^;]*?\"${tableName}\"[^;]*?embedding[^;]*?vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n const pattern3 = new RegExp(\n `\"${tableName}\"\\\\s*\\\\([^)]*embedding[^)]*vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n\n const match1 = upContent.match(pattern1)\n const match2 = upContent.match(pattern2)\n const match3 = upContent.match(pattern3)\n\n const dimsMatch = match1 || match2 || match3\n\n if (dimsMatch && !state.get(poolName)) {\n const dims = parseInt(dimsMatch[1], 10)\n state.set(poolName, dims)\n }\n }\n } catch (err) {\n // Skip files that can't be read\n continue\n }\n }\n\n return state\n}\n\n/**\n * Generate SQL code for destructive dims change (truncate table)\n */\nfunction generateDimsChangeTruncateCode(\n tableName: string,\n schemaName: string,\n oldDims: number,\n newDims: number,\n): string {\n return ` // payloadcms-vectorize: WARNING - Changing dims from ${oldDims} to ${newDims} is DESTRUCTIVE\n // All existing embeddings will be deleted. You must re-embed all documents after this migration.\n // Truncate table (destructive - all embeddings are lost)\n // Use CASCADE to handle foreign key constraints\n await db.execute(sql.raw(\\`TRUNCATE TABLE \"${schemaName}\".\"${tableName}\" CASCADE\\`));`\n}\n\n/**\n * Generate SQL code for down migration (restore old dims column type)\n */\nfunction generateDimsChangeDownCode(\n tableName: string,\n schemaName: string,\n oldDims: number,\n): string {\n return ` // payloadcms-vectorize: Revert column type to old dimensions\n // WARNING: Data was truncated during up migration and cannot be restored.\n // You will need to re-embed all documents after rolling back.\n await db.execute(sql.raw(\\`ALTER TABLE \"${schemaName}\".\"${tableName}\" ALTER COLUMN embedding TYPE vector(${oldDims})\\`));`\n}\n\n/**\n * Patch a migration file with truncate SQL for dims changes\n */\nfunction patchMigrationFileForDimsChange(\n migrationPath: string,\n tableName: string,\n schemaName: string,\n oldDims: number,\n newDims: number,\n): void {\n let content = readFileSync(migrationPath, 'utf-8')\n\n // Ensure sql import exists for injected sql.raw usage\n const sqlImportRegex = /import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]@payloadcms\\/db-postgres['\"]/\n const importMatch = content.match(sqlImportRegex)\n if (importMatch) {\n const imports = importMatch[1]\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n if (!imports.includes('sql')) {\n imports.push('sql')\n const updatedImport = `import { ${imports.join(', ')} } from '@payloadcms/db-postgres'`\n content = content.replace(importMatch[0], updatedImport)\n }\n } else {\n content = `import { sql } from '@payloadcms/db-postgres'\\n${content}`\n }\n\n // Generate SQL code\n const truncateCode = generateDimsChangeTruncateCode(tableName, schemaName, oldDims, newDims)\n const downCode = generateDimsChangeDownCode(tableName, schemaName, oldDims)\n\n // Find the up function and insert code before the closing brace\n const upFunctionMatch = content.match(\n /export\\s+async\\s+function\\s+up\\s*\\([^)]*\\)\\s*:\\s*Promise<void>\\s*\\{/i,\n )\n if (!upFunctionMatch) {\n throw new Error(`Could not find 'up' function in migration file: ${migrationPath}`)\n }\n\n const upFunctionStart = upFunctionMatch.index! + upFunctionMatch[0].length\n const downFunctionMatch = content.match(/export\\s+async\\s+function\\s+down\\s*\\([^)]*\\)/i)\n const searchEnd = downFunctionMatch ? downFunctionMatch.index! : content.length\n\n // Find the last closing brace before down function or end\n const upFunctionBody = content.substring(upFunctionStart, searchEnd)\n const lastBraceIndex = upFunctionBody.lastIndexOf('}')\n if (lastBraceIndex === -1) {\n throw new Error(\n `Could not find closing brace for 'up' function in migration file: ${migrationPath}`,\n )\n }\n\n // Insert our code before the closing brace\n const beforeBrace = content.substring(0, upFunctionStart + lastBraceIndex)\n const afterBrace = content.substring(upFunctionStart + lastBraceIndex)\n\n const codeToInsert = '\\n' + truncateCode + '\\n'\n let newContent = beforeBrace + codeToInsert + afterBrace\n\n // Handle down function\n if (downFunctionMatch) {\n const downFunctionStart = downFunctionMatch.index! + downFunctionMatch[0].length\n const downBraceMatch = newContent.substring(downFunctionStart).match(/\\{/)\n if (downBraceMatch) {\n const downBodyStart = downFunctionStart + downBraceMatch.index! + 1\n const downBody = newContent.substring(downBodyStart)\n const downLastBraceIndex = downBody.lastIndexOf('}')\n if (downLastBraceIndex !== -1) {\n const beforeDownBrace = newContent.substring(0, downBodyStart + downLastBraceIndex)\n const afterDownBrace = newContent.substring(downBodyStart + downLastBraceIndex)\n const downCodeToInsert = '\\n' + downCode + '\\n'\n newContent = beforeDownBrace + downCodeToInsert + afterDownBrace\n }\n }\n }\n\n writeFileSync(migrationPath, newContent, 'utf-8')\n}\n\n/**\n * Bin script entry point for patching vector migrations with truncate for dims changes\n *\n * NOTE: As of v0.5.3, the IVFFLAT index is created automatically via afterSchemaInitHook\n * using Drizzle's extraConfig. This script is only needed when changing dims, which\n * requires truncating the embeddings table (destructive operation).\n */\nexport const script = async (config: SanitizedConfig): Promise<void> => {\n // Get Payload instance to access static configs via VectorizedPayload\n const getPayloadOptions = {\n config,\n // In test environment, use unique key\n ...(process.env.TEST_ENV ? { key: `vectorize-migrate-${Date.now()}` } : {}),\n }\n\n const payload = await getPayload(getPayloadOptions)\n\n // Get static configs from VectorizedPayload\n const vectorizedPayload = getVectorizedPayload(payload)\n if (!vectorizedPayload) {\n throw new Error(\n '[payloadcms-vectorize] Vectorize plugin not found. Ensure payloadcmsVectorize is configured in your Payload config.',\n )\n }\n\n const staticConfigs = (\n vectorizedPayload.getDbAdapterCustom() as { _staticConfigs: KnowledgePoolsConfig }\n )._staticConfigs\n if (!staticConfigs || Object.keys(staticConfigs).length === 0) {\n throw new Error('[payloadcms-vectorize] No static configs found')\n }\n\n const poolNames = Object.keys(staticConfigs)\n const schemaName = (payload.db as any).schemaName || 'public'\n\n // Get migrations directory\n const dbMigrationDir = (payload.db as any).migrationDir\n const migrationsDir = dbMigrationDir || resolve(process.cwd(), 'src/migrations')\n\n // Get prior dims state from migrations\n const priorDims = getPriorDimsFromMigrations(migrationsDir, poolNames)\n\n // Check if any dims have changed\n const dimsChanges: Array<{\n poolName: string\n tableName: string\n oldDims: number\n newDims: number\n }> = []\n\n for (const poolName of poolNames) {\n const currentConfig = staticConfigs[poolName]\n const priorDimsValue = priorDims.get(poolName)\n const currentDims = currentConfig.dims\n\n // Only flag as change if we have a prior value AND it's different\n if (priorDimsValue !== null && priorDimsValue !== undefined && priorDimsValue !== currentDims) {\n dimsChanges.push({\n poolName,\n tableName: toSnakeCase(poolName),\n oldDims: priorDimsValue as number,\n newDims: currentDims,\n })\n }\n }\n\n // If no dims changes detected, show deprecation message\n if (dimsChanges.length === 0) {\n console.log(\n '\\n[payloadcms-vectorize] No dims changes detected. ' +\n 'This script is only needed when changing dims (which requires truncating the embeddings table). ',\n )\n return\n }\n\n // Dims changed - we need to patch the most recent migration with TRUNCATE\n console.log('\\n[payloadcms-vectorize] Detected dims changes:')\n for (const change of dimsChanges) {\n console.log(` - ${change.poolName}: ${change.oldDims} → ${change.newDims}`)\n }\n console.log('')\n\n // Find the most recent migration file\n if (!existsSync(migrationsDir)) {\n throw new Error(\n `[payloadcms-vectorize] Migrations directory not found: ${migrationsDir}\\n` +\n `Please run 'payload migrate:create' first to create a migration for the dims change.`,\n )\n }\n\n const migrationFiles = readdirSync(migrationsDir)\n .filter((f) => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js')\n .map((f) => ({\n name: f,\n path: join(migrationsDir, f),\n mtime: statSync(join(migrationsDir, f)).mtime,\n }))\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime())\n\n if (migrationFiles.length === 0) {\n throw new Error(\n `[payloadcms-vectorize] No migration files found in ${migrationsDir}\\n` +\n `Please run 'payload migrate:create' first to create a migration for the dims change.`,\n )\n }\n\n const latestMigration = migrationFiles[0]\n\n // Check if migration already has truncate code\n const migrationContent = readFileSync(latestMigration.path, 'utf-8')\n if (\n migrationContent.includes('TRUNCATE TABLE') &&\n migrationContent.includes('payloadcms-vectorize')\n ) {\n console.log(\n '[payloadcms-vectorize] Migration already patched with TRUNCATE. No changes needed.',\n )\n return\n }\n\n // Patch the migration for each dims change\n for (const change of dimsChanges) {\n patchMigrationFileForDimsChange(\n latestMigration.path,\n change.tableName,\n schemaName,\n change.oldDims,\n change.newDims,\n )\n }\n\n console.log(`[payloadcms-vectorize] Migration patched successfully: ${latestMigration.name}`)\n console.log('')\n console.log('⚠️ WARNING: This migration will TRUNCATE your embeddings table(s).')\n console.log(' All existing embeddings will be deleted.')\n console.log(' After running the migration, you must re-embed all documents.')\n console.log('')\n\n // Only exit if not in test environment\n if (process.env.NODE_ENV !== 'test' && !process.env.VITEST) {\n process.exit(0)\n }\n}\n"],"names":["getPayload","readFileSync","writeFileSync","readdirSync","statSync","existsSync","join","resolve","toSnakeCase","getVectorizedPayload","getPriorDimsFromMigrations","migrationsDir","poolNames","state","Map","poolName","set","migrationFiles","filter","f","endsWith","map","name","path","mtime","sort","a","b","getTime","filesToCheck","slice","file","content","upFunctionMatch","match","upContent","tableName","pattern1","RegExp","pattern2","pattern3","match1","match2","match3","dimsMatch","get","dims","parseInt","err","generateDimsChangeTruncateCode","schemaName","oldDims","newDims","generateDimsChangeDownCode","patchMigrationFileForDimsChange","migrationPath","sqlImportRegex","importMatch","imports","split","part","trim","Boolean","includes","push","updatedImport","replace","truncateCode","downCode","Error","upFunctionStart","index","length","downFunctionMatch","searchEnd","upFunctionBody","substring","lastBraceIndex","lastIndexOf","beforeBrace","afterBrace","codeToInsert","newContent","downFunctionStart","downBraceMatch","downBodyStart","downBody","downLastBraceIndex","beforeDownBrace","afterDownBrace","downCodeToInsert","script","config","getPayloadOptions","process","env","TEST_ENV","key","Date","now","payload","vectorizedPayload","staticConfigs","getDbAdapterCustom","_staticConfigs","Object","keys","db","dbMigrationDir","migrationDir","cwd","priorDims","dimsChanges","currentConfig","priorDimsValue","currentDims","undefined","console","log","change","latestMigration","migrationContent","NODE_ENV","VITEST","exit"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/bin-vectorize-migrate.ts"],"sourcesContent":["import type { SanitizedConfig } from 'payload'\nimport { getPayload } from 'payload'\nimport { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from 'fs'\nimport { join, resolve } from 'path'\nimport toSnakeCase from 'to-snake-case'\n\nimport { getVectorizedPayload } from 'payloadcms-vectorize'\nimport { KnowledgePoolsConfig } from './types.js'\n\nfunction listMigrationFiles(migrationsDir: string) {\n return readdirSync(migrationsDir)\n .filter((f) => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js')\n .map((f) => ({\n name: f,\n path: join(migrationsDir, f),\n mtime: statSync(join(migrationsDir, f)).mtime,\n }))\n .sort((a, b) => b.mtime.getTime() - a.mtime.getTime())\n}\n\n/**\n * Get prior dims state from existing migrations\n */\nfunction getPriorDimsFromMigrations(\n migrationsDir: string,\n poolNames: string[],\n): Map<string, number | null> {\n const state = new Map<string, number | null>()\n\n // Initialize with null (unknown state)\n for (const poolName of poolNames) {\n state.set(poolName, null)\n }\n\n if (!existsSync(migrationsDir)) {\n return state\n }\n\n // Find all migration files and read them in reverse order (newest first)\n const migrationFiles = listMigrationFiles(migrationsDir)\n\n // Skip the most recent migration when determining prior dims, since it may contain\n // the pending dims change that we're trying to detect\n const filesToCheck = migrationFiles.slice(1)\n\n // Read migration files to find vector dims\n for (const file of filesToCheck) {\n try {\n const content = readFileSync(file.path, 'utf-8')\n\n // Extract only the UP function content to avoid matching values in DOWN function\n const upFunctionMatch = content.match(\n /export\\s+async\\s+function\\s+up\\s*\\([^)]*\\)[^{]*\\{([\\s\\S]*?)(?=\\}\\s*(?:export\\s+async\\s+function\\s+down|$))/i,\n )\n const upContent = upFunctionMatch ? upFunctionMatch[1] : content\n\n // Look for dims in vector column definition (pool-specific patterns)\n for (const poolName of poolNames) {\n const tableName = toSnakeCase(poolName)\n\n const pattern1 = new RegExp(\n `ALTER\\\\s+TABLE[^;]*?\"${tableName}\"[^;]*?vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n const pattern2 = new RegExp(\n `CREATE\\\\s+TABLE[^;]*?\"${tableName}\"[^;]*?embedding[^;]*?vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n const pattern3 = new RegExp(\n `\"${tableName}\"\\\\s*\\\\([^)]*embedding[^)]*vector\\\\((\\\\d+)\\\\)`,\n 'is',\n )\n\n const match1 = upContent.match(pattern1)\n const match2 = upContent.match(pattern2)\n const match3 = upContent.match(pattern3)\n\n const dimsMatch = match1 || match2 || match3\n\n if (dimsMatch && !state.get(poolName)) {\n const dims = parseInt(dimsMatch[1], 10)\n state.set(poolName, dims)\n }\n }\n } catch (err) {\n // Skip files that can't be read\n continue\n }\n }\n\n return state\n}\n\n/**\n * Generate SQL code for destructive dims change (truncate table)\n */\nfunction generateDimsChangeTruncateCode(\n tableName: string,\n schemaName: string,\n oldDims: number,\n newDims: number,\n): string {\n return ` // payloadcms-vectorize: WARNING - Changing dims from ${oldDims} to ${newDims} is DESTRUCTIVE\n // All existing embeddings will be deleted. You must re-embed all documents after this migration.\n // Truncate table (destructive - all embeddings are lost)\n // Use CASCADE to handle foreign key constraints\n await db.execute(sql.raw(\\`TRUNCATE TABLE \"${schemaName}\".\"${tableName}\" CASCADE\\`));`\n}\n\n/**\n * Generate SQL code for down migration (restore old dims column type)\n */\nfunction generateDimsChangeDownCode(\n tableName: string,\n schemaName: string,\n oldDims: number,\n): string {\n return ` // payloadcms-vectorize: Revert column type to old dimensions\n // WARNING: Data was truncated during up migration and cannot be restored.\n // You will need to re-embed all documents after rolling back.\n await db.execute(sql.raw(\\`ALTER TABLE \"${schemaName}\".\"${tableName}\" ALTER COLUMN embedding TYPE vector(${oldDims})\\`));`\n}\n\n/**\n * Patch a migration file with truncate SQL for dims changes\n */\nfunction patchMigrationFileForDimsChange(\n migrationPath: string,\n tableName: string,\n schemaName: string,\n oldDims: number,\n newDims: number,\n): void {\n let content = readFileSync(migrationPath, 'utf-8')\n\n // Ensure sql import exists for injected sql.raw usage\n const sqlImportRegex = /import\\s+\\{([^}]+)\\}\\s+from\\s+['\"]@payloadcms\\/db-postgres['\"]/\n const importMatch = content.match(sqlImportRegex)\n if (importMatch) {\n const imports = importMatch[1]\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n if (!imports.includes('sql')) {\n imports.push('sql')\n const updatedImport = `import { ${imports.join(', ')} } from '@payloadcms/db-postgres'`\n content = content.replace(importMatch[0], updatedImport)\n }\n } else {\n content = `import { sql } from '@payloadcms/db-postgres'\\n${content}`\n }\n\n // Generate SQL code\n const truncateCode = generateDimsChangeTruncateCode(tableName, schemaName, oldDims, newDims)\n const downCode = generateDimsChangeDownCode(tableName, schemaName, oldDims)\n\n // Find the up function and insert code before the closing brace\n const upFunctionMatch = content.match(\n /export\\s+async\\s+function\\s+up\\s*\\([^)]*\\)\\s*:\\s*Promise<void>\\s*\\{/i,\n )\n if (!upFunctionMatch) {\n throw new Error(`Could not find 'up' function in migration file: ${migrationPath}`)\n }\n\n const upFunctionStart = upFunctionMatch.index! + upFunctionMatch[0].length\n const downFunctionMatch = content.match(/export\\s+async\\s+function\\s+down\\s*\\([^)]*\\)/i)\n const searchEnd = downFunctionMatch ? downFunctionMatch.index! : content.length\n\n // Find the last closing brace before down function or end\n const upFunctionBody = content.substring(upFunctionStart, searchEnd)\n const lastBraceIndex = upFunctionBody.lastIndexOf('}')\n if (lastBraceIndex === -1) {\n throw new Error(\n `Could not find closing brace for 'up' function in migration file: ${migrationPath}`,\n )\n }\n\n // Insert our code before the closing brace\n const beforeBrace = content.substring(0, upFunctionStart + lastBraceIndex)\n const afterBrace = content.substring(upFunctionStart + lastBraceIndex)\n\n const codeToInsert = '\\n' + truncateCode + '\\n'\n let newContent = beforeBrace + codeToInsert + afterBrace\n\n // Handle down function\n if (downFunctionMatch) {\n const downFunctionStart = downFunctionMatch.index! + downFunctionMatch[0].length\n const downBraceMatch = newContent.substring(downFunctionStart).match(/\\{/)\n if (downBraceMatch) {\n const downBodyStart = downFunctionStart + downBraceMatch.index! + 1\n const downBody = newContent.substring(downBodyStart)\n const downLastBraceIndex = downBody.lastIndexOf('}')\n if (downLastBraceIndex !== -1) {\n const beforeDownBrace = newContent.substring(0, downBodyStart + downLastBraceIndex)\n const afterDownBrace = newContent.substring(downBodyStart + downLastBraceIndex)\n const downCodeToInsert = '\\n' + downCode + '\\n'\n newContent = beforeDownBrace + downCodeToInsert + afterDownBrace\n }\n }\n }\n\n writeFileSync(migrationPath, newContent, 'utf-8')\n}\n\n/**\n * Bin script entry point for patching vector migrations with truncate for dims changes\n *\n * NOTE: As of v0.5.3, the IVFFLAT index is created automatically via afterSchemaInitHook\n * using Drizzle's extraConfig. This script is only needed when changing dims, which\n * requires truncating the embeddings table (destructive operation).\n */\nexport const script = async (config: SanitizedConfig): Promise<void> => {\n // Get Payload instance to access static configs via VectorizedPayload\n const getPayloadOptions = {\n config,\n // In test environment, use unique key\n ...(process.env.TEST_ENV ? { key: `vectorize-migrate-${Date.now()}` } : {}),\n }\n\n const payload = await getPayload(getPayloadOptions)\n\n // Get static configs from VectorizedPayload\n const vectorizedPayload = getVectorizedPayload(payload)\n if (!vectorizedPayload) {\n throw new Error(\n '[payloadcms-vectorize] Vectorize plugin not found. Ensure payloadcmsVectorize is configured in your Payload config.',\n )\n }\n\n const staticConfigs = (\n vectorizedPayload.getDbAdapterCustom() as { _staticConfigs: KnowledgePoolsConfig }\n )._staticConfigs\n if (!staticConfigs || Object.keys(staticConfigs).length === 0) {\n throw new Error('[payloadcms-vectorize] No static configs found')\n }\n\n const poolNames = Object.keys(staticConfigs)\n const schemaName = (payload.db as any).schemaName || 'public'\n\n // Get migrations directory\n const dbMigrationDir = (payload.db as any).migrationDir\n const migrationsDir = dbMigrationDir || resolve(process.cwd(), 'src/migrations')\n\n // Get prior dims state from migrations\n const priorDims = getPriorDimsFromMigrations(migrationsDir, poolNames)\n\n // Check if any dims have changed\n const dimsChanges: Array<{\n poolName: string\n tableName: string\n oldDims: number\n newDims: number\n }> = []\n\n for (const poolName of poolNames) {\n const currentConfig = staticConfigs[poolName]\n const priorDimsValue = priorDims.get(poolName)\n const currentDims = currentConfig.dims\n\n // Only flag as change if we have a prior value AND it's different\n if (priorDimsValue !== null && priorDimsValue !== undefined && priorDimsValue !== currentDims) {\n dimsChanges.push({\n poolName,\n tableName: toSnakeCase(poolName),\n oldDims: priorDimsValue as number,\n newDims: currentDims,\n })\n }\n }\n\n // If no dims changes detected, show deprecation message\n if (dimsChanges.length === 0) {\n console.log(\n '\\n[payloadcms-vectorize] No dims changes detected. ' +\n 'This script is only needed when changing dims (which requires truncating the embeddings table). ',\n )\n return\n }\n\n // Dims changed - we need to patch the most recent migration with TRUNCATE\n console.log('\\n[payloadcms-vectorize] Detected dims changes:')\n for (const change of dimsChanges) {\n console.log(` - ${change.poolName}: ${change.oldDims} → ${change.newDims}`)\n }\n console.log('')\n\n // Find the most recent migration file\n if (!existsSync(migrationsDir)) {\n throw new Error(\n `[payloadcms-vectorize] Migrations directory not found: ${migrationsDir}\\n` +\n `Please run 'payload migrate:create' first to create a migration for the dims change.`,\n )\n }\n\n const migrationFiles = listMigrationFiles(migrationsDir)\n\n if (migrationFiles.length === 0) {\n throw new Error(\n `[payloadcms-vectorize] No migration files found in ${migrationsDir}\\n` +\n `Please run 'payload migrate:create' first to create a migration for the dims change.`,\n )\n }\n\n const latestMigration = migrationFiles[0]\n\n // Check if migration already has truncate code\n const migrationContent = readFileSync(latestMigration.path, 'utf-8')\n if (\n migrationContent.includes('TRUNCATE TABLE') &&\n migrationContent.includes('payloadcms-vectorize')\n ) {\n console.log(\n '[payloadcms-vectorize] Migration already patched with TRUNCATE. No changes needed.',\n )\n return\n }\n\n // Patch the migration for each dims change\n for (const change of dimsChanges) {\n patchMigrationFileForDimsChange(\n latestMigration.path,\n change.tableName,\n schemaName,\n change.oldDims,\n change.newDims,\n )\n }\n\n console.log(`[payloadcms-vectorize] Migration patched successfully: ${latestMigration.name}`)\n console.log('')\n console.log('⚠️ WARNING: This migration will TRUNCATE your embeddings table(s).')\n console.log(' All existing embeddings will be deleted.')\n console.log(' After running the migration, you must re-embed all documents.')\n console.log('')\n\n // Only exit if not in test environment\n if (process.env.NODE_ENV !== 'test' && !process.env.VITEST) {\n process.exit(0)\n }\n}\n"],"names":["getPayload","readFileSync","writeFileSync","readdirSync","statSync","existsSync","join","resolve","toSnakeCase","getVectorizedPayload","listMigrationFiles","migrationsDir","filter","f","endsWith","map","name","path","mtime","sort","a","b","getTime","getPriorDimsFromMigrations","poolNames","state","Map","poolName","set","migrationFiles","filesToCheck","slice","file","content","upFunctionMatch","match","upContent","tableName","pattern1","RegExp","pattern2","pattern3","match1","match2","match3","dimsMatch","get","dims","parseInt","err","generateDimsChangeTruncateCode","schemaName","oldDims","newDims","generateDimsChangeDownCode","patchMigrationFileForDimsChange","migrationPath","sqlImportRegex","importMatch","imports","split","part","trim","Boolean","includes","push","updatedImport","replace","truncateCode","downCode","Error","upFunctionStart","index","length","downFunctionMatch","searchEnd","upFunctionBody","substring","lastBraceIndex","lastIndexOf","beforeBrace","afterBrace","codeToInsert","newContent","downFunctionStart","downBraceMatch","downBodyStart","downBody","downLastBraceIndex","beforeDownBrace","afterDownBrace","downCodeToInsert","script","config","getPayloadOptions","process","env","TEST_ENV","key","Date","now","payload","vectorizedPayload","staticConfigs","getDbAdapterCustom","_staticConfigs","Object","keys","db","dbMigrationDir","migrationDir","cwd","priorDims","dimsChanges","currentConfig","priorDimsValue","currentDims","undefined","console","log","change","latestMigration","migrationContent","NODE_ENV","VITEST","exit"],"mappings":"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"}
package/dist/embed.js CHANGED
@@ -1,29 +1,28 @@
1
1
  import { isPostgresPayload } from './types.js';
2
2
  import toSnakeCase from 'to-snake-case';
3
- export default (async (payload, poolName, id, embedding)=>{
4
- const isPostgres = isPostgresPayload(payload);
5
- if (!isPostgres) {
3
+ export default (async (payload, poolName, _sourceCollection, _sourceDocId, id, embedding)=>{
4
+ if (!isPostgresPayload(payload)) {
6
5
  throw new Error('[@payloadcms-vectorize/pg] Only works with Postgres');
7
6
  }
7
+ // After the type guard, payload is narrowed to PostgresPayload
8
8
  const runSQL = async (sql, params)=>{
9
- if (postgresPayload.db.pool?.query) return postgresPayload.db.pool.query(sql, params);
10
- if (postgresPayload.db.drizzle?.execute) return postgresPayload.db.drizzle.execute(sql, params);
9
+ if (payload.db.pool?.query) return payload.db.pool.query(sql, params);
10
+ if (payload.db.drizzle?.execute) return payload.db.drizzle.execute(sql);
11
11
  throw new Error('[@payloadcms-vectorize/pg] Failed to persist vector column');
12
12
  };
13
- const literal = `[${Array.from(embedding).join(',')}]`;
14
- const postgresPayload = payload;
15
- const schemaName = postgresPayload.db.schemaName || 'public';
13
+ const pgVectorLiteral = `[${Array.from(embedding).join(',')}]`;
14
+ const schemaName = payload.db.schemaName || 'public';
16
15
  // Drizzle converts camelCase collection slugs to snake_case table names
17
- const sql = `UPDATE "${schemaName}"."${toSnakeCase(poolName)}" SET embedding = $1 WHERE id = $2`;
16
+ const sqlStatement = `UPDATE "${schemaName}"."${toSnakeCase(poolName)}" SET embedding = $1 WHERE id = $2`;
18
17
  try {
19
- await runSQL(sql, [
20
- literal,
18
+ await runSQL(sqlStatement, [
19
+ pgVectorLiteral,
21
20
  id
22
21
  ]);
23
22
  } catch (e) {
24
- const errorMessage = e.message || e.toString();
23
+ const errorMessage = e instanceof Error ? e.message : String(e);
25
24
  payload.logger.error(`[@payloadcms-vectorize/pg] Failed to persist vector column: ${errorMessage}`);
26
- throw new Error(`[@payloadcms-vectorize/pg] Failed to persist vector column: ${e}`);
25
+ throw new Error(`[@payloadcms-vectorize/pg] Failed to persist vector column: ${errorMessage}`);
27
26
  }
28
27
  });
29
28
 
package/dist/embed.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/embed.ts"],"sourcesContent":["import { Payload } from 'payload'\nimport { isPostgresPayload, PostgresPayload } from './types.js'\nimport toSnakeCase from 'to-snake-case'\n\nexport default async (\n payload: Payload,\n poolName: string,\n id: string,\n embedding: number[] | Float32Array,\n) => {\n const isPostgres = isPostgresPayload(payload)\n if (!isPostgres) {\n throw new Error('[@payloadcms-vectorize/pg] Only works with Postgres')\n }\n const runSQL = async (sql: string, params?: any[]) => {\n if (postgresPayload.db.pool?.query) return postgresPayload.db.pool.query(sql, params)\n if (postgresPayload.db.drizzle?.execute) return postgresPayload.db.drizzle.execute(sql, params)\n throw new Error('[@payloadcms-vectorize/pg] Failed to persist vector column')\n }\n const literal = `[${Array.from(embedding).join(',')}]`\n const postgresPayload = payload as PostgresPayload\n const schemaName = postgresPayload.db.schemaName || 'public'\n // Drizzle converts camelCase collection slugs to snake_case table names\n const sql =\n `UPDATE \"${schemaName}\".\"${toSnakeCase(poolName)}\" SET embedding = $1 WHERE id = $2` as string\n try {\n await runSQL(sql, [literal, id])\n } catch (e) {\n const errorMessage = (e as Error).message || (e as any).toString()\n payload.logger.error(\n `[@payloadcms-vectorize/pg] Failed to persist vector column: ${errorMessage}`,\n )\n throw new Error(`[@payloadcms-vectorize/pg] Failed to persist vector column: ${e}`)\n }\n}\n"],"names":["isPostgresPayload","toSnakeCase","payload","poolName","id","embedding","isPostgres","Error","runSQL","sql","params","postgresPayload","db","pool","query","drizzle","execute","literal","Array","from","join","schemaName","e","errorMessage","message","toString","logger","error"],"mappings":"AACA,SAASA,iBAAiB,QAAyB,aAAY;AAC/D,OAAOC,iBAAiB,gBAAe;AAEvC,eAAe,CAAA,OACbC,SACAC,UACAC,IACAC;IAEA,MAAMC,aAAaN,kBAAkBE;IACrC,IAAI,CAACI,YAAY;QACf,MAAM,IAAIC,MAAM;IAClB;IACA,MAAMC,SAAS,OAAOC,KAAaC;QACjC,IAAIC,gBAAgBC,EAAE,CAACC,IAAI,EAAEC,OAAO,OAAOH,gBAAgBC,EAAE,CAACC,IAAI,CAACC,KAAK,CAACL,KAAKC;QAC9E,IAAIC,gBAAgBC,EAAE,CAACG,OAAO,EAAEC,SAAS,OAAOL,gBAAgBC,EAAE,CAACG,OAAO,CAACC,OAAO,CAACP,KAAKC;QACxF,MAAM,IAAIH,MAAM;IAClB;IACA,MAAMU,UAAU,CAAC,CAAC,EAAEC,MAAMC,IAAI,CAACd,WAAWe,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,MAAMT,kBAAkBT;IACxB,MAAMmB,aAAaV,gBAAgBC,EAAE,CAACS,UAAU,IAAI;IACpD,wEAAwE;IACxE,MAAMZ,MACJ,CAAC,QAAQ,EAAEY,WAAW,GAAG,EAAEpB,YAAYE,UAAU,kCAAkC,CAAC;IACtF,IAAI;QACF,MAAMK,OAAOC,KAAK;YAACQ;YAASb;SAAG;IACjC,EAAE,OAAOkB,GAAG;QACV,MAAMC,eAAe,AAACD,EAAYE,OAAO,IAAI,AAACF,EAAUG,QAAQ;QAChEvB,QAAQwB,MAAM,CAACC,KAAK,CAClB,CAAC,4DAA4D,EAAEJ,cAAc;QAE/E,MAAM,IAAIhB,MAAM,CAAC,4DAA4D,EAAEe,GAAG;IACpF;AACF,CAAA,EAAC"}
1
+ {"version":3,"sources":["../src/embed.ts"],"sourcesContent":["import { Payload } from 'payload'\nimport { isPostgresPayload } from './types.js'\nimport toSnakeCase from 'to-snake-case'\n\nexport default async (\n payload: Payload,\n poolName: string,\n _sourceCollection: string,\n _sourceDocId: string,\n id: string,\n embedding: number[] | Float32Array,\n) => {\n if (!isPostgresPayload(payload)) {\n throw new Error('[@payloadcms-vectorize/pg] Only works with Postgres')\n }\n // After the type guard, payload is narrowed to PostgresPayload\n const runSQL = async (sql: string, params?: unknown[]) => {\n if (payload.db.pool?.query) return payload.db.pool.query(sql, params)\n if (payload.db.drizzle?.execute) return payload.db.drizzle.execute(sql)\n throw new Error('[@payloadcms-vectorize/pg] Failed to persist vector column')\n }\n const pgVectorLiteral = `[${Array.from(embedding).join(',')}]`\n const schemaName = payload.db.schemaName || 'public'\n // Drizzle converts camelCase collection slugs to snake_case table names\n const sqlStatement = `UPDATE \"${schemaName}\".\"${toSnakeCase(poolName)}\" SET embedding = $1 WHERE id = $2`\n try {\n await runSQL(sqlStatement, [pgVectorLiteral, id])\n } catch (e) {\n const errorMessage = e instanceof Error ? e.message : String(e)\n payload.logger.error(\n `[@payloadcms-vectorize/pg] Failed to persist vector column: ${errorMessage}`,\n )\n throw new Error(`[@payloadcms-vectorize/pg] Failed to persist vector column: ${errorMessage}`)\n }\n}\n"],"names":["isPostgresPayload","toSnakeCase","payload","poolName","_sourceCollection","_sourceDocId","id","embedding","Error","runSQL","sql","params","db","pool","query","drizzle","execute","pgVectorLiteral","Array","from","join","schemaName","sqlStatement","e","errorMessage","message","String","logger","error"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,aAAY;AAC9C,OAAOC,iBAAiB,gBAAe;AAEvC,eAAe,CAAA,OACbC,SACAC,UACAC,mBACAC,cACAC,IACAC;IAEA,IAAI,CAACP,kBAAkBE,UAAU;QAC/B,MAAM,IAAIM,MAAM;IAClB;IACA,+DAA+D;IAC/D,MAAMC,SAAS,OAAOC,KAAaC;QACjC,IAAIT,QAAQU,EAAE,CAACC,IAAI,EAAEC,OAAO,OAAOZ,QAAQU,EAAE,CAACC,IAAI,CAACC,KAAK,CAACJ,KAAKC;QAC9D,IAAIT,QAAQU,EAAE,CAACG,OAAO,EAAEC,SAAS,OAAOd,QAAQU,EAAE,CAACG,OAAO,CAACC,OAAO,CAACN;QACnE,MAAM,IAAIF,MAAM;IAClB;IACA,MAAMS,kBAAkB,CAAC,CAAC,EAAEC,MAAMC,IAAI,CAACZ,WAAWa,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAMC,aAAanB,QAAQU,EAAE,CAACS,UAAU,IAAI;IAC5C,wEAAwE;IACxE,MAAMC,eAAe,CAAC,QAAQ,EAAED,WAAW,GAAG,EAAEpB,YAAYE,UAAU,kCAAkC,CAAC;IACzG,IAAI;QACF,MAAMM,OAAOa,cAAc;YAACL;YAAiBX;SAAG;IAClD,EAAE,OAAOiB,GAAG;QACV,MAAMC,eAAeD,aAAaf,QAAQe,EAAEE,OAAO,GAAGC,OAAOH;QAC7DrB,QAAQyB,MAAM,CAACC,KAAK,CAClB,CAAC,4DAA4D,EAAEJ,cAAc;QAE/E,MAAM,IAAIhB,MAAM,CAAC,4DAA4D,EAAEgB,cAAc;IAC/F;AACF,CAAA,EAAC"}
package/dist/search.js CHANGED
@@ -82,9 +82,10 @@ export default (async (payload, queryEmbedding, poolName, limit = 10, where)=>{
82
82
  return mapRowsToResults(result, collectionConfig);
83
83
  });
84
84
  /**
85
- * Convert Payload WHERE clause to Drizzle conditions
86
- * Simplified version inspired by Payload's buildQuery
87
- */ function convertWhereToDrizzle(where, table, fields) {
85
+ * Convert Payload WHERE clause to Drizzle conditions.
86
+ * Returns a drizzle SQL condition, null (empty/no-op), or undefined (invalid).
87
+ */ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88
+ function convertWhereToDrizzle(where, table, fields) {
88
89
  if (!where || typeof where !== 'object') {
89
90
  return undefined;
90
91
  }
@@ -103,13 +104,12 @@ export default (async (payload, queryEmbedding, poolName, limit = 10, where)=>{
103
104
  return or(...conditions);
104
105
  }
105
106
  // Handle field conditions - collect all field conditions and combine with AND
107
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
108
  const fieldConditions = [];
107
109
  for (const [fieldName, condition] of Object.entries(where)){
108
110
  if (fieldName === 'and' || fieldName === 'or') continue;
109
- // Get the column from the table
110
- // Drizzle tables have columns as direct properties
111
- // Try camelCase first, then snake_case as fallback
112
- // Use 'in' operator to check existence, then access the property
111
+ // Get the column from the table (try camelCase first, then snake_case)
112
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
113
  let column = undefined;
114
114
  if (fieldName in table) {
115
115
  column = table[fieldName];
@@ -201,11 +201,9 @@ export default (async (payload, queryEmbedding, poolName, limit = 10, where)=>{
201
201
  function mapRowsToResults(rows, collectionConfig) {
202
202
  // Collect names of fields that are typed as number on the collection
203
203
  const numberFields = new Set();
204
- if (collectionConfig?.fields) {
205
- for (const field of collectionConfig.fields){
206
- if (typeof field === 'object' && 'name' in field && field.type === 'number') {
207
- numberFields.add(field.name);
208
- }
204
+ for (const field of collectionConfig.fields){
205
+ if (typeof field === 'object' && 'name' in field && field.type === 'number') {
206
+ numberFields.add(field.name);
209
207
  }
210
208
  }
211
209
  return rows.map((row)=>{
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/search.ts"],"sourcesContent":["import {\n sql,\n cosineDistance,\n inArray,\n eq,\n and,\n or,\n not,\n like,\n gt,\n gte,\n lt,\n lte,\n ne,\n isNull,\n isNotNull,\n} from '@payloadcms/db-postgres/drizzle'\nimport { BasePayload, Where } from 'payload'\nimport { KnowledgePoolName, VectorSearchResult } from 'payloadcms-vectorize'\nimport toSnakeCase from 'to-snake-case'\nimport { getEmbeddingsTable } from './drizzle.js'\n\nexport default async (\n payload: BasePayload,\n queryEmbedding: number[],\n poolName: KnowledgePoolName,\n limit: number = 10,\n where?: Where,\n): Promise<Array<VectorSearchResult>> => {\n const isPostgres = payload.db?.pool?.query || payload.db?.drizzle\n\n if (!isPostgres) {\n throw new Error('Only works with Postgres')\n }\n\n // In PayloadCMS, payload.db IS the adapter, and drizzle is at payload.db.drizzle\n const adapter = payload.db\n if (!adapter) {\n throw new Error('Drizzle adapter not found')\n }\n\n // Get drizzle instance\n const drizzle = adapter.drizzle\n if (!drizzle) {\n throw new Error('Drizzle instance not found in adapter')\n }\n\n // Get collection config and table name\n const collectionConfig = payload.collections[poolName]?.config\n if (!collectionConfig) {\n throw new Error(`Collection ${poolName} not found`)\n }\n\n const table = getEmbeddingsTable(poolName)\n if (!table) {\n throw new Error(\n `[payloadcms-vectorize] Embeddings table for knowledge pool \"${poolName}\" not registered. Ensure the plugin's afterSchemaInit hook ran and the pool exists.`,\n )\n }\n\n // Use Drizzle's query builder with cosineDistance function\n // cosineDistance returns distance, so we calculate score as 1 - distance\n // The table from fullSchema should have columns as direct properties\n const embeddingColumn = table.embedding\n if (!embeddingColumn) {\n throw new Error(\n `Embedding column not found in table for pool \"${poolName}\". Available properties: ${Object.keys(table).join(', ')}`,\n )\n }\n\n // Convert WHERE clause to Drizzle conditions\n let drizzleWhere: any = undefined\n if (where) {\n drizzleWhere = convertWhereToDrizzle(where, table, collectionConfig.flattenedFields)\n if (drizzleWhere === null) {\n // WHERE clause resulted in an empty condition (e.g., empty 'and' or 'or' array)\n // This semantically means \"match nothing\", so return empty results\n throw new Error(\n `[payloadcms-vectorize] WHERE clause resulted in no valid conditions. This typically occurs when using empty 'and' or 'or' arrays, or when all field conditions reference non-existent columns.`,\n )\n }\n if (drizzleWhere === undefined) {\n // WHERE clause could not be converted (invalid structure or unsupported operators)\n throw new Error(\n `[payloadcms-vectorize] WHERE clause could not be converted to Drizzle conditions. Please check that all field names exist and operators are supported.`,\n )\n }\n }\n\n // Build query using Drizzle's query builder\n // Column names in the table are camelCase (docId, chunkText, etc.)\n // but their database names are snake_case (doc_id, chunk_text, etc.)\n // The table from fullSchema should have columns as direct properties\n // Calculate score: 1 - cosineDistance (distance)\n // Need to cast 1 to numeric to avoid \"integer - vector\" error\n const distanceExpr = cosineDistance(embeddingColumn, queryEmbedding)\n\n // Build select object with score\n const selectObj: Record<string, any> = {\n id: table.id, // ensure we select id explicitly\n score: sql<number>`1 - (${distanceExpr})`,\n }\n\n // Add reserved + extension fields from collection config\n for (const field of collectionConfig.fields ?? []) {\n if (typeof field === 'object' && 'name' in field) {\n const name = field.name as string\n if (name in table) {\n selectObj[name] = table[name]\n } else if (toSnakeCase(name) in table) {\n selectObj[name] = table[toSnakeCase(name)]\n }\n }\n }\n\n let query: any = drizzle.select(selectObj).from(table)\n\n // Add WHERE clause if provided\n if (drizzleWhere) {\n query = query.where(drizzleWhere)\n }\n\n // Order by cosine distance (ascending = most similar first) and limit\n // Reuse the same distance expression for ordering\n query = query.orderBy(distanceExpr).limit(limit)\n\n // Execute the query\n const result = await query\n\n return mapRowsToResults(result, collectionConfig)\n}\n\n/**\n * Convert Payload WHERE clause to Drizzle conditions\n * Simplified version inspired by Payload's buildQuery\n */\nfunction convertWhereToDrizzle(where: Where, table: any, fields: any[]): any {\n if (!where || typeof where !== 'object') {\n return undefined\n }\n\n // Handle 'and' operator\n if ('and' in where && Array.isArray(where.and)) {\n const conditions = where.and\n .map((condition) => convertWhereToDrizzle(condition, table, fields))\n .filter((c) => c !== undefined && c !== null)\n if (conditions.length === 0) return null\n if (conditions.length === 1) return conditions[0]\n return and(...conditions)\n }\n\n // Handle 'or' operator\n if ('or' in where && Array.isArray(where.or)) {\n const conditions = where.or\n .map((condition) => convertWhereToDrizzle(condition, table, fields))\n .filter((c) => c !== undefined && c !== null)\n if (conditions.length === 0) return null\n if (conditions.length === 1) return conditions[0]\n return or(...conditions)\n }\n\n // Handle field conditions - collect all field conditions and combine with AND\n const fieldConditions: any[] = []\n for (const [fieldName, condition] of Object.entries(where)) {\n if (fieldName === 'and' || fieldName === 'or') continue\n\n // Get the column from the table\n // Drizzle tables have columns as direct properties\n // Try camelCase first, then snake_case as fallback\n // Use 'in' operator to check existence, then access the property\n let column: any = undefined\n if (fieldName in table) {\n column = table[fieldName]\n } else if (toSnakeCase(fieldName) in table) {\n column = table[toSnakeCase(fieldName)]\n } else if (table.columns) {\n // Fallback to table.columns if it exists\n if (fieldName in table.columns) {\n column = table.columns[fieldName]\n } else if (toSnakeCase(fieldName) in table.columns) {\n column = table.columns[toSnakeCase(fieldName)]\n }\n }\n\n if (!column) {\n // Field not found, skip (could be a nested field we don't support)\n continue\n }\n\n if (typeof condition !== 'object' || condition === null || Array.isArray(condition)) {\n continue\n }\n\n const cond = condition as Record<string, any>\n\n // Handle equals\n if ('equals' in cond) {\n fieldConditions.push(eq(column, cond.equals))\n continue\n }\n\n // Handle not_equals / notEquals\n if ('not_equals' in cond || 'notEquals' in cond) {\n fieldConditions.push(ne(column, cond.not_equals ?? cond.notEquals))\n continue\n }\n\n // Handle in\n if ('in' in cond && Array.isArray(cond.in)) {\n fieldConditions.push(inArray(column, cond.in))\n continue\n }\n\n // Handle not_in / notIn\n if ('not_in' in cond || 'notIn' in cond) {\n const values = cond.not_in ?? cond.notIn\n if (Array.isArray(values)) {\n fieldConditions.push(not(inArray(column, values)))\n }\n continue\n }\n\n // Handle like\n if ('like' in cond && typeof cond.like === 'string') {\n fieldConditions.push(like(column, cond.like))\n continue\n }\n\n // Handle contains\n if ('contains' in cond && typeof cond.contains === 'string') {\n fieldConditions.push(like(column, `%${cond.contains}%`))\n continue\n }\n\n // Handle greater_than / greaterThan\n if ('greater_than' in cond || 'greaterThan' in cond) {\n fieldConditions.push(gt(column, cond.greater_than ?? cond.greaterThan))\n continue\n }\n\n // Handle greater_than_equal / greaterThanEqual\n if ('greater_than_equal' in cond || 'greaterThanEqual' in cond) {\n fieldConditions.push(gte(column, cond.greater_than_equal ?? cond.greaterThanEqual))\n continue\n }\n\n // Handle less_than / lessThan\n if ('less_than' in cond || 'lessThan' in cond) {\n fieldConditions.push(lt(column, cond.less_than ?? cond.lessThan))\n continue\n }\n\n // Handle less_than_equal / lessThanEqual\n if ('less_than_equal' in cond || 'lessThanEqual' in cond) {\n fieldConditions.push(lte(column, cond.less_than_equal ?? cond.lessThanEqual))\n continue\n }\n\n // Handle exists (null check)\n if ('exists' in cond && typeof cond.exists === 'boolean') {\n fieldConditions.push(cond.exists ? isNotNull(column) : isNull(column))\n continue\n }\n }\n\n // Combine all field conditions with AND\n if (fieldConditions.length === 0) {\n return undefined\n }\n if (fieldConditions.length === 1) {\n return fieldConditions[0]\n }\n return and(...fieldConditions)\n}\n\nfunction mapRowsToResults(rows: any[], collectionConfig: any): Array<VectorSearchResult> {\n // Collect names of fields that are typed as number on the collection\n const numberFields = new Set<string>()\n if (collectionConfig?.fields) {\n for (const field of collectionConfig.fields) {\n if (typeof field === 'object' && 'name' in field && field.type === 'number') {\n numberFields.add(field.name as string)\n }\n }\n }\n\n return rows.map((row: any) => {\n // Drizzle returns columns with the names we selected (camelCase)\n // Handle both camelCase and snake_case for robustness\n const rawDocId = row.docId ?? row.doc_id\n const rawChunkIndex = row.chunkIndex ?? row.chunk_index\n const rawScore = row.score\n\n const result: any = {\n ...row,\n id: String(row.id),\n docId: String(rawDocId),\n score: typeof rawScore === 'number' ? rawScore : parseFloat(String(rawScore)),\n chunkIndex:\n typeof rawChunkIndex === 'number' ? rawChunkIndex : parseInt(String(rawChunkIndex), 10),\n }\n\n // Ensure any number fields from the schema are numbers in the result\n for (const fieldName of numberFields) {\n const value = result[fieldName]\n if (value != null && typeof value !== 'number') {\n const parsed = parseFloat(String(value))\n if (!Number.isNaN(parsed)) {\n result[fieldName] = parsed\n }\n }\n }\n\n return result\n })\n}\n"],"names":["sql","cosineDistance","inArray","eq","and","or","not","like","gt","gte","lt","lte","ne","isNull","isNotNull","toSnakeCase","getEmbeddingsTable","payload","queryEmbedding","poolName","limit","where","isPostgres","db","pool","query","drizzle","Error","adapter","collectionConfig","collections","config","table","embeddingColumn","embedding","Object","keys","join","drizzleWhere","undefined","convertWhereToDrizzle","flattenedFields","distanceExpr","selectObj","id","score","field","fields","name","select","from","orderBy","result","mapRowsToResults","Array","isArray","conditions","map","condition","filter","c","length","fieldConditions","fieldName","entries","column","columns","cond","push","equals","not_equals","notEquals","in","values","not_in","notIn","contains","greater_than","greaterThan","greater_than_equal","greaterThanEqual","less_than","lessThan","less_than_equal","lessThanEqual","exists","rows","numberFields","Set","type","add","row","rawDocId","docId","doc_id","rawChunkIndex","chunkIndex","chunk_index","rawScore","String","parseFloat","parseInt","value","parsed","Number","isNaN"],"mappings":"AAAA,SACEA,GAAG,EACHC,cAAc,EACdC,OAAO,EACPC,EAAE,EACFC,GAAG,EACHC,EAAE,EACFC,GAAG,EACHC,IAAI,EACJC,EAAE,EACFC,GAAG,EACHC,EAAE,EACFC,GAAG,EACHC,EAAE,EACFC,MAAM,EACNC,SAAS,QACJ,kCAAiC;AAGxC,OAAOC,iBAAiB,gBAAe;AACvC,SAASC,kBAAkB,QAAQ,eAAc;AAEjD,eAAe,CAAA,OACbC,SACAC,gBACAC,UACAC,QAAgB,EAAE,EAClBC;IAEA,MAAMC,aAAaL,QAAQM,EAAE,EAAEC,MAAMC,SAASR,QAAQM,EAAE,EAAEG;IAE1D,IAAI,CAACJ,YAAY;QACf,MAAM,IAAIK,MAAM;IAClB;IAEA,iFAAiF;IACjF,MAAMC,UAAUX,QAAQM,EAAE;IAC1B,IAAI,CAACK,SAAS;QACZ,MAAM,IAAID,MAAM;IAClB;IAEA,uBAAuB;IACvB,MAAMD,UAAUE,QAAQF,OAAO;IAC/B,IAAI,CAACA,SAAS;QACZ,MAAM,IAAIC,MAAM;IAClB;IAEA,uCAAuC;IACvC,MAAME,mBAAmBZ,QAAQa,WAAW,CAACX,SAAS,EAAEY;IACxD,IAAI,CAACF,kBAAkB;QACrB,MAAM,IAAIF,MAAM,CAAC,WAAW,EAAER,SAAS,UAAU,CAAC;IACpD;IAEA,MAAMa,QAAQhB,mBAAmBG;IACjC,IAAI,CAACa,OAAO;QACV,MAAM,IAAIL,MACR,CAAC,4DAA4D,EAAER,SAAS,mFAAmF,CAAC;IAEhK;IAEA,2DAA2D;IAC3D,yEAAyE;IACzE,qEAAqE;IACrE,MAAMc,kBAAkBD,MAAME,SAAS;IACvC,IAAI,CAACD,iBAAiB;QACpB,MAAM,IAAIN,MACR,CAAC,8CAA8C,EAAER,SAAS,yBAAyB,EAAEgB,OAAOC,IAAI,CAACJ,OAAOK,IAAI,CAAC,OAAO;IAExH;IAEA,6CAA6C;IAC7C,IAAIC,eAAoBC;IACxB,IAAIlB,OAAO;QACTiB,eAAeE,sBAAsBnB,OAAOW,OAAOH,iBAAiBY,eAAe;QACnF,IAAIH,iBAAiB,MAAM;YACzB,gFAAgF;YAChF,mEAAmE;YACnE,MAAM,IAAIX,MACR,CAAC,8LAA8L,CAAC;QAEpM;QACA,IAAIW,iBAAiBC,WAAW;YAC9B,mFAAmF;YACnF,MAAM,IAAIZ,MACR,CAAC,sJAAsJ,CAAC;QAE5J;IACF;IAEA,4CAA4C;IAC5C,mEAAmE;IACnE,qEAAqE;IACrE,qEAAqE;IACrE,iDAAiD;IACjD,8DAA8D;IAC9D,MAAMe,eAAezC,eAAegC,iBAAiBf;IAErD,iCAAiC;IACjC,MAAMyB,YAAiC;QACrCC,IAAIZ,MAAMY,EAAE;QACZC,OAAO7C,GAAW,CAAC,KAAK,EAAE0C,aAAa,CAAC,CAAC;IAC3C;IAEA,yDAAyD;IACzD,KAAK,MAAMI,SAASjB,iBAAiBkB,MAAM,IAAI,EAAE,CAAE;QACjD,IAAI,OAAOD,UAAU,YAAY,UAAUA,OAAO;YAChD,MAAME,OAAOF,MAAME,IAAI;YACvB,IAAIA,QAAQhB,OAAO;gBACjBW,SAAS,CAACK,KAAK,GAAGhB,KAAK,CAACgB,KAAK;YAC/B,OAAO,IAAIjC,YAAYiC,SAAShB,OAAO;gBACrCW,SAAS,CAACK,KAAK,GAAGhB,KAAK,CAACjB,YAAYiC,MAAM;YAC5C;QACF;IACF;IAEA,IAAIvB,QAAaC,QAAQuB,MAAM,CAACN,WAAWO,IAAI,CAAClB;IAEhD,+BAA+B;IAC/B,IAAIM,cAAc;QAChBb,QAAQA,MAAMJ,KAAK,CAACiB;IACtB;IAEA,sEAAsE;IACtE,kDAAkD;IAClDb,QAAQA,MAAM0B,OAAO,CAACT,cAActB,KAAK,CAACA;IAE1C,oBAAoB;IACpB,MAAMgC,SAAS,MAAM3B;IAErB,OAAO4B,iBAAiBD,QAAQvB;AAClC,CAAA,EAAC;AAED;;;CAGC,GACD,SAASW,sBAAsBnB,KAAY,EAAEW,KAAU,EAAEe,MAAa;IACpE,IAAI,CAAC1B,SAAS,OAAOA,UAAU,UAAU;QACvC,OAAOkB;IACT;IAEA,wBAAwB;IACxB,IAAI,SAASlB,SAASiC,MAAMC,OAAO,CAAClC,MAAMjB,GAAG,GAAG;QAC9C,MAAMoD,aAAanC,MAAMjB,GAAG,CACzBqD,GAAG,CAAC,CAACC,YAAclB,sBAAsBkB,WAAW1B,OAAOe,SAC3DY,MAAM,CAAC,CAACC,IAAMA,MAAMrB,aAAaqB,MAAM;QAC1C,IAAIJ,WAAWK,MAAM,KAAK,GAAG,OAAO;QACpC,IAAIL,WAAWK,MAAM,KAAK,GAAG,OAAOL,UAAU,CAAC,EAAE;QACjD,OAAOpD,OAAOoD;IAChB;IAEA,uBAAuB;IACvB,IAAI,QAAQnC,SAASiC,MAAMC,OAAO,CAAClC,MAAMhB,EAAE,GAAG;QAC5C,MAAMmD,aAAanC,MAAMhB,EAAE,CACxBoD,GAAG,CAAC,CAACC,YAAclB,sBAAsBkB,WAAW1B,OAAOe,SAC3DY,MAAM,CAAC,CAACC,IAAMA,MAAMrB,aAAaqB,MAAM;QAC1C,IAAIJ,WAAWK,MAAM,KAAK,GAAG,OAAO;QACpC,IAAIL,WAAWK,MAAM,KAAK,GAAG,OAAOL,UAAU,CAAC,EAAE;QACjD,OAAOnD,MAAMmD;IACf;IAEA,8EAA8E;IAC9E,MAAMM,kBAAyB,EAAE;IACjC,KAAK,MAAM,CAACC,WAAWL,UAAU,IAAIvB,OAAO6B,OAAO,CAAC3C,OAAQ;QAC1D,IAAI0C,cAAc,SAASA,cAAc,MAAM;QAE/C,gCAAgC;QAChC,mDAAmD;QACnD,mDAAmD;QACnD,iEAAiE;QACjE,IAAIE,SAAc1B;QAClB,IAAIwB,aAAa/B,OAAO;YACtBiC,SAASjC,KAAK,CAAC+B,UAAU;QAC3B,OAAO,IAAIhD,YAAYgD,cAAc/B,OAAO;YAC1CiC,SAASjC,KAAK,CAACjB,YAAYgD,WAAW;QACxC,OAAO,IAAI/B,MAAMkC,OAAO,EAAE;YACxB,yCAAyC;YACzC,IAAIH,aAAa/B,MAAMkC,OAAO,EAAE;gBAC9BD,SAASjC,MAAMkC,OAAO,CAACH,UAAU;YACnC,OAAO,IAAIhD,YAAYgD,cAAc/B,MAAMkC,OAAO,EAAE;gBAClDD,SAASjC,MAAMkC,OAAO,CAACnD,YAAYgD,WAAW;YAChD;QACF;QAEA,IAAI,CAACE,QAAQ;YAEX;QACF;QAEA,IAAI,OAAOP,cAAc,YAAYA,cAAc,QAAQJ,MAAMC,OAAO,CAACG,YAAY;YACnF;QACF;QAEA,MAAMS,OAAOT;QAEb,gBAAgB;QAChB,IAAI,YAAYS,MAAM;YACpBL,gBAAgBM,IAAI,CAACjE,GAAG8D,QAAQE,KAAKE,MAAM;YAC3C;QACF;QAEA,gCAAgC;QAChC,IAAI,gBAAgBF,QAAQ,eAAeA,MAAM;YAC/CL,gBAAgBM,IAAI,CAACxD,GAAGqD,QAAQE,KAAKG,UAAU,IAAIH,KAAKI,SAAS;YACjE;QACF;QAEA,YAAY;QACZ,IAAI,QAAQJ,QAAQb,MAAMC,OAAO,CAACY,KAAKK,EAAE,GAAG;YAC1CV,gBAAgBM,IAAI,CAAClE,QAAQ+D,QAAQE,KAAKK,EAAE;YAC5C;QACF;QAEA,wBAAwB;QACxB,IAAI,YAAYL,QAAQ,WAAWA,MAAM;YACvC,MAAMM,SAASN,KAAKO,MAAM,IAAIP,KAAKQ,KAAK;YACxC,IAAIrB,MAAMC,OAAO,CAACkB,SAAS;gBACzBX,gBAAgBM,IAAI,CAAC9D,IAAIJ,QAAQ+D,QAAQQ;YAC3C;YACA;QACF;QAEA,cAAc;QACd,IAAI,UAAUN,QAAQ,OAAOA,KAAK5D,IAAI,KAAK,UAAU;YACnDuD,gBAAgBM,IAAI,CAAC7D,KAAK0D,QAAQE,KAAK5D,IAAI;YAC3C;QACF;QAEA,kBAAkB;QAClB,IAAI,cAAc4D,QAAQ,OAAOA,KAAKS,QAAQ,KAAK,UAAU;YAC3Dd,gBAAgBM,IAAI,CAAC7D,KAAK0D,QAAQ,CAAC,CAAC,EAAEE,KAAKS,QAAQ,CAAC,CAAC,CAAC;YACtD;QACF;QAEA,oCAAoC;QACpC,IAAI,kBAAkBT,QAAQ,iBAAiBA,MAAM;YACnDL,gBAAgBM,IAAI,CAAC5D,GAAGyD,QAAQE,KAAKU,YAAY,IAAIV,KAAKW,WAAW;YACrE;QACF;QAEA,+CAA+C;QAC/C,IAAI,wBAAwBX,QAAQ,sBAAsBA,MAAM;YAC9DL,gBAAgBM,IAAI,CAAC3D,IAAIwD,QAAQE,KAAKY,kBAAkB,IAAIZ,KAAKa,gBAAgB;YACjF;QACF;QAEA,8BAA8B;QAC9B,IAAI,eAAeb,QAAQ,cAAcA,MAAM;YAC7CL,gBAAgBM,IAAI,CAAC1D,GAAGuD,QAAQE,KAAKc,SAAS,IAAId,KAAKe,QAAQ;YAC/D;QACF;QAEA,yCAAyC;QACzC,IAAI,qBAAqBf,QAAQ,mBAAmBA,MAAM;YACxDL,gBAAgBM,IAAI,CAACzD,IAAIsD,QAAQE,KAAKgB,eAAe,IAAIhB,KAAKiB,aAAa;YAC3E;QACF;QAEA,6BAA6B;QAC7B,IAAI,YAAYjB,QAAQ,OAAOA,KAAKkB,MAAM,KAAK,WAAW;YACxDvB,gBAAgBM,IAAI,CAACD,KAAKkB,MAAM,GAAGvE,UAAUmD,UAAUpD,OAAOoD;YAC9D;QACF;IACF;IAEA,wCAAwC;IACxC,IAAIH,gBAAgBD,MAAM,KAAK,GAAG;QAChC,OAAOtB;IACT;IACA,IAAIuB,gBAAgBD,MAAM,KAAK,GAAG;QAChC,OAAOC,eAAe,CAAC,EAAE;IAC3B;IACA,OAAO1D,OAAO0D;AAChB;AAEA,SAAST,iBAAiBiC,IAAW,EAAEzD,gBAAqB;IAC1D,qEAAqE;IACrE,MAAM0D,eAAe,IAAIC;IACzB,IAAI3D,kBAAkBkB,QAAQ;QAC5B,KAAK,MAAMD,SAASjB,iBAAiBkB,MAAM,CAAE;YAC3C,IAAI,OAAOD,UAAU,YAAY,UAAUA,SAASA,MAAM2C,IAAI,KAAK,UAAU;gBAC3EF,aAAaG,GAAG,CAAC5C,MAAME,IAAI;YAC7B;QACF;IACF;IAEA,OAAOsC,KAAK7B,GAAG,CAAC,CAACkC;QACf,iEAAiE;QACjE,sDAAsD;QACtD,MAAMC,WAAWD,IAAIE,KAAK,IAAIF,IAAIG,MAAM;QACxC,MAAMC,gBAAgBJ,IAAIK,UAAU,IAAIL,IAAIM,WAAW;QACvD,MAAMC,WAAWP,IAAI9C,KAAK;QAE1B,MAAMO,SAAc;YAClB,GAAGuC,GAAG;YACN/C,IAAIuD,OAAOR,IAAI/C,EAAE;YACjBiD,OAAOM,OAAOP;YACd/C,OAAO,OAAOqD,aAAa,WAAWA,WAAWE,WAAWD,OAAOD;YACnEF,YACE,OAAOD,kBAAkB,WAAWA,gBAAgBM,SAASF,OAAOJ,gBAAgB;QACxF;QAEA,qEAAqE;QACrE,KAAK,MAAMhC,aAAawB,aAAc;YACpC,MAAMe,QAAQlD,MAAM,CAACW,UAAU;YAC/B,IAAIuC,SAAS,QAAQ,OAAOA,UAAU,UAAU;gBAC9C,MAAMC,SAASH,WAAWD,OAAOG;gBACjC,IAAI,CAACE,OAAOC,KAAK,CAACF,SAAS;oBACzBnD,MAAM,CAACW,UAAU,GAAGwC;gBACtB;YACF;QACF;QAEA,OAAOnD;IACT;AACF"}
1
+ {"version":3,"sources":["../src/search.ts"],"sourcesContent":["import {\n sql,\n cosineDistance,\n inArray,\n eq,\n and,\n or,\n not,\n like,\n gt,\n gte,\n lt,\n lte,\n ne,\n isNull,\n isNotNull,\n} from '@payloadcms/db-postgres/drizzle'\nimport { BasePayload, Where, SanitizedCollectionConfig, FlattenedField } from 'payload'\nimport { KnowledgePoolName, VectorSearchResult } from 'payloadcms-vectorize'\nimport toSnakeCase from 'to-snake-case'\nimport { getEmbeddingsTable } from './drizzle.js'\n\nexport default async (\n payload: BasePayload,\n queryEmbedding: number[],\n poolName: KnowledgePoolName,\n limit: number = 10,\n where?: Where,\n): Promise<Array<VectorSearchResult>> => {\n const isPostgres = payload.db?.pool?.query || payload.db?.drizzle\n\n if (!isPostgres) {\n throw new Error('Only works with Postgres')\n }\n\n // In PayloadCMS, payload.db IS the adapter, and drizzle is at payload.db.drizzle\n const adapter = payload.db\n if (!adapter) {\n throw new Error('Drizzle adapter not found')\n }\n\n // Get drizzle instance\n const drizzle = adapter.drizzle\n if (!drizzle) {\n throw new Error('Drizzle instance not found in adapter')\n }\n\n // Get collection config and table name\n const collectionConfig = payload.collections[poolName]?.config\n if (!collectionConfig) {\n throw new Error(`Collection ${poolName} not found`)\n }\n\n const table = getEmbeddingsTable(poolName)\n if (!table) {\n throw new Error(\n `[payloadcms-vectorize] Embeddings table for knowledge pool \"${poolName}\" not registered. Ensure the plugin's afterSchemaInit hook ran and the pool exists.`,\n )\n }\n\n // Use Drizzle's query builder with cosineDistance function\n // cosineDistance returns distance, so we calculate score as 1 - distance\n // The table from fullSchema should have columns as direct properties\n const embeddingColumn = table.embedding\n if (!embeddingColumn) {\n throw new Error(\n `Embedding column not found in table for pool \"${poolName}\". Available properties: ${Object.keys(table).join(', ')}`,\n )\n }\n\n // Convert WHERE clause to Drizzle conditions\n let drizzleWhere: any = undefined\n if (where) {\n drizzleWhere = convertWhereToDrizzle(where, table, collectionConfig.flattenedFields)\n if (drizzleWhere === null) {\n // WHERE clause resulted in an empty condition (e.g., empty 'and' or 'or' array)\n // This semantically means \"match nothing\", so return empty results\n throw new Error(\n `[payloadcms-vectorize] WHERE clause resulted in no valid conditions. This typically occurs when using empty 'and' or 'or' arrays, or when all field conditions reference non-existent columns.`,\n )\n }\n if (drizzleWhere === undefined) {\n // WHERE clause could not be converted (invalid structure or unsupported operators)\n throw new Error(\n `[payloadcms-vectorize] WHERE clause could not be converted to Drizzle conditions. Please check that all field names exist and operators are supported.`,\n )\n }\n }\n\n // Build query using Drizzle's query builder\n // Column names in the table are camelCase (docId, chunkText, etc.)\n // but their database names are snake_case (doc_id, chunk_text, etc.)\n // The table from fullSchema should have columns as direct properties\n // Calculate score: 1 - cosineDistance (distance)\n // Need to cast 1 to numeric to avoid \"integer - vector\" error\n const distanceExpr = cosineDistance(embeddingColumn, queryEmbedding)\n\n // Build select object with score\n const selectObj: Record<string, any> = {\n id: table.id, // ensure we select id explicitly\n score: sql<number>`1 - (${distanceExpr})`,\n }\n\n // Add reserved + extension fields from collection config\n for (const field of collectionConfig.fields ?? []) {\n if (typeof field === 'object' && 'name' in field) {\n const name = field.name as string\n if (name in table) {\n selectObj[name] = table[name]\n } else if (toSnakeCase(name) in table) {\n selectObj[name] = table[toSnakeCase(name)]\n }\n }\n }\n\n let query: any = drizzle.select(selectObj).from(table)\n\n // Add WHERE clause if provided\n if (drizzleWhere) {\n query = query.where(drizzleWhere)\n }\n\n // Order by cosine distance (ascending = most similar first) and limit\n // Reuse the same distance expression for ordering\n query = query.orderBy(distanceExpr).limit(limit)\n\n // Execute the query\n const result = await query\n\n return mapRowsToResults(result, collectionConfig)\n}\n\n/**\n * Drizzle table — dynamically registered, so typed loosely.\n * We use `any` here because Drizzle column types (SQLWrapper, Column) are\n * not directly expressible for tables that are registered at runtime.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype DrizzleTable = Record<string, any>\n\n/**\n * Convert Payload WHERE clause to Drizzle conditions.\n * Returns a drizzle SQL condition, null (empty/no-op), or undefined (invalid).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction convertWhereToDrizzle(where: Where, table: DrizzleTable, fields: FlattenedField[]): any {\n if (!where || typeof where !== 'object') {\n return undefined\n }\n\n // Handle 'and' operator\n if ('and' in where && Array.isArray(where.and)) {\n const conditions = where.and\n .map((condition) => convertWhereToDrizzle(condition, table, fields))\n .filter((c) => c !== undefined && c !== null)\n if (conditions.length === 0) return null\n if (conditions.length === 1) return conditions[0]\n return and(...conditions)\n }\n\n // Handle 'or' operator\n if ('or' in where && Array.isArray(where.or)) {\n const conditions = where.or\n .map((condition) => convertWhereToDrizzle(condition, table, fields))\n .filter((c) => c !== undefined && c !== null)\n if (conditions.length === 0) return null\n if (conditions.length === 1) return conditions[0]\n return or(...conditions)\n }\n\n // Handle field conditions - collect all field conditions and combine with AND\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const fieldConditions: any[] = []\n for (const [fieldName, condition] of Object.entries(where)) {\n if (fieldName === 'and' || fieldName === 'or') continue\n\n // Get the column from the table (try camelCase first, then snake_case)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let column: any = undefined\n if (fieldName in table) {\n column = table[fieldName]\n } else if (toSnakeCase(fieldName) in table) {\n column = table[toSnakeCase(fieldName)]\n } else if (table.columns) {\n // Fallback to table.columns if it exists\n if (fieldName in table.columns) {\n column = table.columns[fieldName]\n } else if (toSnakeCase(fieldName) in table.columns) {\n column = table.columns[toSnakeCase(fieldName)]\n }\n }\n\n if (!column) {\n // Field not found, skip (could be a nested field we don't support)\n continue\n }\n\n if (typeof condition !== 'object' || condition === null || Array.isArray(condition)) {\n continue\n }\n\n const cond = condition as Record<string, unknown>\n\n // Handle equals\n if ('equals' in cond) {\n fieldConditions.push(eq(column, cond.equals))\n continue\n }\n\n // Handle not_equals / notEquals\n if ('not_equals' in cond || 'notEquals' in cond) {\n fieldConditions.push(ne(column, cond.not_equals ?? cond.notEquals))\n continue\n }\n\n // Handle in\n if ('in' in cond && Array.isArray(cond.in)) {\n fieldConditions.push(inArray(column, cond.in))\n continue\n }\n\n // Handle not_in / notIn\n if ('not_in' in cond || 'notIn' in cond) {\n const values = cond.not_in ?? cond.notIn\n if (Array.isArray(values)) {\n fieldConditions.push(not(inArray(column, values)))\n }\n continue\n }\n\n // Handle like\n if ('like' in cond && typeof cond.like === 'string') {\n fieldConditions.push(like(column, cond.like))\n continue\n }\n\n // Handle contains\n if ('contains' in cond && typeof cond.contains === 'string') {\n fieldConditions.push(like(column, `%${cond.contains}%`))\n continue\n }\n\n // Handle greater_than / greaterThan\n if ('greater_than' in cond || 'greaterThan' in cond) {\n fieldConditions.push(gt(column, cond.greater_than ?? cond.greaterThan))\n continue\n }\n\n // Handle greater_than_equal / greaterThanEqual\n if ('greater_than_equal' in cond || 'greaterThanEqual' in cond) {\n fieldConditions.push(gte(column, cond.greater_than_equal ?? cond.greaterThanEqual))\n continue\n }\n\n // Handle less_than / lessThan\n if ('less_than' in cond || 'lessThan' in cond) {\n fieldConditions.push(lt(column, cond.less_than ?? cond.lessThan))\n continue\n }\n\n // Handle less_than_equal / lessThanEqual\n if ('less_than_equal' in cond || 'lessThanEqual' in cond) {\n fieldConditions.push(lte(column, cond.less_than_equal ?? cond.lessThanEqual))\n continue\n }\n\n // Handle exists (null check)\n if ('exists' in cond && typeof cond.exists === 'boolean') {\n fieldConditions.push(cond.exists ? isNotNull(column) : isNull(column))\n continue\n }\n }\n\n // Combine all field conditions with AND\n if (fieldConditions.length === 0) {\n return undefined\n }\n if (fieldConditions.length === 1) {\n return fieldConditions[0]\n }\n return and(...fieldConditions)\n}\n\nfunction mapRowsToResults(\n rows: Record<string, unknown>[],\n collectionConfig: SanitizedCollectionConfig,\n): Array<VectorSearchResult> {\n // Collect names of fields that are typed as number on the collection\n const numberFields = new Set<string>()\n for (const field of collectionConfig.fields) {\n if (typeof field === 'object' && 'name' in field && field.type === 'number') {\n numberFields.add(field.name)\n }\n }\n\n return rows.map((row) => {\n // Drizzle returns columns with the names we selected (camelCase)\n // Handle both camelCase and snake_case for robustness\n const rawDocId = row.docId ?? row.doc_id\n const rawChunkIndex = row.chunkIndex ?? row.chunk_index\n const rawScore = row.score\n\n const result = {\n ...row,\n id: String(row.id),\n docId: String(rawDocId),\n score: typeof rawScore === 'number' ? rawScore : parseFloat(String(rawScore)),\n chunkIndex:\n typeof rawChunkIndex === 'number' ? rawChunkIndex : parseInt(String(rawChunkIndex), 10),\n } as VectorSearchResult\n\n // Ensure any number fields from the schema are numbers in the result\n for (const fieldName of numberFields) {\n const value = result[fieldName]\n if (value != null && typeof value !== 'number') {\n const parsed = parseFloat(String(value))\n if (!Number.isNaN(parsed)) {\n result[fieldName] = parsed\n }\n }\n }\n\n return result\n })\n}\n"],"names":["sql","cosineDistance","inArray","eq","and","or","not","like","gt","gte","lt","lte","ne","isNull","isNotNull","toSnakeCase","getEmbeddingsTable","payload","queryEmbedding","poolName","limit","where","isPostgres","db","pool","query","drizzle","Error","adapter","collectionConfig","collections","config","table","embeddingColumn","embedding","Object","keys","join","drizzleWhere","undefined","convertWhereToDrizzle","flattenedFields","distanceExpr","selectObj","id","score","field","fields","name","select","from","orderBy","result","mapRowsToResults","Array","isArray","conditions","map","condition","filter","c","length","fieldConditions","fieldName","entries","column","columns","cond","push","equals","not_equals","notEquals","in","values","not_in","notIn","contains","greater_than","greaterThan","greater_than_equal","greaterThanEqual","less_than","lessThan","less_than_equal","lessThanEqual","exists","rows","numberFields","Set","type","add","row","rawDocId","docId","doc_id","rawChunkIndex","chunkIndex","chunk_index","rawScore","String","parseFloat","parseInt","value","parsed","Number","isNaN"],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1,6 +1,8 @@
1
- /** Configuration for a knowledge pool */ // Type guard to check if Payload is using Postgres adapter
2
- export function isPostgresPayload(payload) {
3
- return typeof payload?.db?.pool?.query === 'function' || typeof payload?.db?.drizzle?.execute === 'function';
1
+ /** Configuration for a knowledge pool */ /** Type guard to check if Payload is using Postgres adapter */ export function isPostgresPayload(payload) {
2
+ const db = payload.db;
3
+ const pool = db?.pool;
4
+ const drizzle = db?.drizzle;
5
+ return typeof pool?.query === 'function' || typeof drizzle?.execute === 'function';
4
6
  }
5
7
 
6
8
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Configuration for a knowledge pool */\n\nimport { KnowledgePoolName } from 'payloadcms-vectorize'\n\n/** Note current limitation: needs a migration in order to change */\nexport type KnowledgePoolsConfig = Record<\n KnowledgePoolName,\n {\n /** Vector dimensions for pgvector column */\n dims: number\n /** IVFFLAT lists parameter used when creating the index */\n ivfflatLists: number\n }\n>\n\n// Type guard to check if Payload is using Postgres adapter\nexport function isPostgresPayload(payload: any): payload is any & {\n db: {\n pool?: { query: (sql: string, params?: any[]) => Promise<any> }\n drizzle?: { execute: (sql: string) => Promise<any> }\n }\n} {\n return (\n typeof payload?.db?.pool?.query === 'function' ||\n typeof payload?.db?.drizzle?.execute === 'function'\n )\n}\n\n// Type for Payload with Postgres database\nexport type PostgresPayload = any & {\n db: {\n pool?: { query: (sql: string, params?: any[]) => Promise<any> }\n drizzle?: { execute: (sql: string) => Promise<any> }\n }\n}\n"],"names":["isPostgresPayload","payload","db","pool","query","drizzle","execute"],"mappings":"AAAA,uCAAuC,GAevC,2DAA2D;AAC3D,OAAO,SAASA,kBAAkBC,OAAY;IAM5C,OACE,OAAOA,SAASC,IAAIC,MAAMC,UAAU,cACpC,OAAOH,SAASC,IAAIG,SAASC,YAAY;AAE7C"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/** Configuration for a knowledge pool */\n\nimport { KnowledgePoolName } from 'payloadcms-vectorize'\nimport type { Payload } from 'payload'\n\n/** Note current limitation: needs a migration in order to change */\nexport type KnowledgePoolsConfig = Record<\n KnowledgePoolName,\n {\n /** Vector dimensions for pgvector column */\n dims: number\n /** IVFFLAT lists parameter used when creating the index */\n ivfflatLists: number\n }\n>\n\n/** Shape of the Postgres-specific db properties we need */\nexport interface PostgresDb {\n pool?: { query: (sql: string, params?: unknown[]) => Promise<unknown> }\n drizzle?: Record<string, unknown> & { execute?: (sql: string) => Promise<unknown> }\n schemaName?: string\n}\n\n/** Payload instance with a Postgres database adapter */\nexport type PostgresPayload = Payload & {\n db: PostgresDb\n}\n\n/** Type guard to check if Payload is using Postgres adapter */\nexport function isPostgresPayload(payload: Payload): payload is PostgresPayload {\n const db = payload.db as unknown as Record<string, unknown>\n const pool = db?.pool as Record<string, unknown> | undefined\n const drizzle = db?.drizzle as Record<string, unknown> | undefined\n return typeof pool?.query === 'function' || typeof drizzle?.execute === 'function'\n}\n"],"names":["isPostgresPayload","payload","db","pool","drizzle","query","execute"],"mappings":"AAAA,uCAAuC,GA4BvC,6DAA6D,GAC7D,OAAO,SAASA,kBAAkBC,OAAgB;IAChD,MAAMC,KAAKD,QAAQC,EAAE;IACrB,MAAMC,OAAOD,IAAIC;IACjB,MAAMC,UAAUF,IAAIE;IACpB,OAAO,OAAOD,MAAME,UAAU,cAAc,OAAOD,SAASE,YAAY;AAC1E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms-vectorize/pg",
3
- "version": "0.6.0-beta.2",
3
+ "version": "0.6.0-beta.3",
4
4
  "description": "PostgreSQL adapter for payloadcms-vectorize",
5
5
  "license": "MIT",
6
6
  "type": "module",