@workglow/postgres 0.2.33 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +51 -0
  2. package/dist/job-queue/browser.d.ts.map +1 -1
  3. package/dist/job-queue/browser.js +11 -1
  4. package/dist/job-queue/browser.js.map +3 -3
  5. package/dist/job-queue/bun.d.ts.map +1 -1
  6. package/dist/job-queue/common.d.ts.map +1 -1
  7. package/dist/job-queue/node.d.ts.map +1 -1
  8. package/dist/job-queue/node.js +11 -1
  9. package/dist/job-queue/node.js.map +3 -3
  10. package/dist/migrations/PostgresMigrationRunner.d.ts +7 -3
  11. package/dist/migrations/PostgresMigrationRunner.d.ts.map +1 -1
  12. package/dist/migrations/common.d.ts.map +1 -1
  13. package/dist/storage/PostgresTabularStorage.d.ts +14 -2
  14. package/dist/storage/PostgresTabularStorage.d.ts.map +1 -1
  15. package/dist/storage/PostgresVectorStorage.d.ts +1 -5
  16. package/dist/storage/PostgresVectorStorage.d.ts.map +1 -1
  17. package/dist/storage/browser.d.ts.map +1 -1
  18. package/dist/storage/browser.js +50 -106
  19. package/dist/storage/browser.js.map +4 -4
  20. package/dist/storage/bun.d.ts.map +1 -1
  21. package/dist/storage/common.d.ts.map +1 -1
  22. package/dist/storage/node.d.ts.map +1 -1
  23. package/dist/storage/node.js +60 -106
  24. package/dist/storage/node.js.map +5 -5
  25. package/dist/text/PostgresFtsTextIndex.d.ts +108 -0
  26. package/dist/text/PostgresFtsTextIndex.d.ts.map +1 -0
  27. package/dist/text/browser.d.ts +7 -0
  28. package/dist/text/browser.d.ts.map +1 -0
  29. package/dist/text/browser.js +185 -0
  30. package/dist/text/browser.js.map +10 -0
  31. package/dist/text/bun.d.ts +7 -0
  32. package/dist/text/bun.d.ts.map +1 -0
  33. package/dist/text/common.d.ts +7 -0
  34. package/dist/text/common.d.ts.map +1 -0
  35. package/dist/text/node.d.ts +7 -0
  36. package/dist/text/node.d.ts.map +1 -0
  37. package/dist/text/node.js +185 -0
  38. package/dist/text/node.js.map +10 -0
  39. package/package.json +25 -9
@@ -639,6 +639,52 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
639
639
  this.events.emit("get", key, val);
640
640
  return val;
641
641
  }
642
+ async getBulk(keys) {
643
+ if (keys.length === 0)
644
+ return [];
645
+ const pkColCount = this.primaryKeyColumns().length;
646
+ const chunkSize = Math.max(1, Math.floor(30000 / pkColCount));
647
+ let rows;
648
+ if (keys.length <= chunkSize) {
649
+ rows = await this.mutex(() => this._getBulkInternal(keys));
650
+ } else {
651
+ rows = [];
652
+ for (let i = 0;i < keys.length; i += chunkSize) {
653
+ const chunk = keys.slice(i, i + chunkSize);
654
+ const chunkRows = await this.mutex(() => this._getBulkInternal(chunk));
655
+ rows.push(...chunkRows);
656
+ }
657
+ }
658
+ this.events.emit("getBulk", keys, rows);
659
+ return rows;
660
+ }
661
+ async _getBulkInternal(keys) {
662
+ const db = this.db;
663
+ const pkCols = this.primaryKeyColumns();
664
+ const params = [];
665
+ const tuples = [];
666
+ let p = 1;
667
+ for (const key of keys) {
668
+ const ordered = this.getPrimaryKeyAsOrderedArray(key);
669
+ params.push(...ordered);
670
+ const slots = [];
671
+ for (let i = 0;i < pkCols.length; i++) {
672
+ slots.push(`$${p++}`);
673
+ }
674
+ tuples.push(`(${slots.join(", ")})`);
675
+ }
676
+ const lhs = pkCols.length === 1 ? `"${pkCols[0]}"` : `(${pkCols.map((c) => `"${c}"`).join(", ")})`;
677
+ const rhs = pkCols.length === 1 ? params.map((_, i) => `$${i + 1}`).join(", ") : tuples.join(", ");
678
+ const sql = `SELECT * FROM "${this.table}" WHERE ${lhs} IN (${rhs})`;
679
+ const result = await db.query(sql, params);
680
+ for (const row of result.rows) {
681
+ const record = row;
682
+ for (const key in this.schema.properties) {
683
+ record[key] = this.sqlToJsValue(key, record[key]);
684
+ }
685
+ }
686
+ return result.rows;
687
+ }
642
688
  async delete(value) {
643
689
  return this.mutex(() => this._deleteInternal(value));
644
690
  }
@@ -711,10 +757,10 @@ class PostgresTabularStorage extends BaseSqlTabularStorage {
711
757
  const result = await db.query(`SELECT COUNT(*) FROM "${this.table}" WHERE ${whereClause}`, params);
712
758
  return parseInt(result.rows[0].count, 10);
713
759
  }
714
- async getBulk(offset, limit) {
715
- return this.mutex(() => this._getBulkInternal(offset, limit));
760
+ async getOffsetPage(offset, limit) {
761
+ return this.mutex(() => this._getOffsetPageInternal(offset, limit));
716
762
  }
717
- async _getBulkInternal(offset, limit) {
763
+ async _getOffsetPageInternal(offset, limit) {
718
764
  const db = this.db;
719
765
  const orderByClause = this.primaryKeyColumns().map((col) => `"${String(col)}"`).join(", ");
720
766
  const result = await db.query(`SELECT * FROM "${this.table}" ORDER BY ${orderByClause} LIMIT $1 OFFSET $2`, [limit, offset]);
@@ -1063,74 +1109,6 @@ class PostgresVectorStorage extends PostgresTabularStorage {
1063
1109
  return this.searchFallback(query, options);
1064
1110
  }
1065
1111
  }
1066
- async hybridSearch(query, options) {
1067
- const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
1068
- if (!textQuery || textQuery.trim().length === 0) {
1069
- return this.similaritySearch(query, { topK, filter, scoreThreshold });
1070
- }
1071
- try {
1072
- const queryVector = `[${Array.from(query).join(",")}]`;
1073
- const tsQueryText = textQuery;
1074
- const vectorColRaw = String(this.vectorPropertyName);
1075
- const vectorCol = PostgresDialect2.quoteId(vectorColRaw);
1076
- const metadataColRaw = this.metadataPropertyName ? String(this.metadataPropertyName) : null;
1077
- const metadataCol = metadataColRaw ? PostgresDialect2.quoteId(metadataColRaw) : null;
1078
- const vectorScoreExpr = this.buildScoreExpr(vectorCol, "$1");
1079
- const combinedScoreExpr = `(
1080
- $2 * ${vectorScoreExpr} +
1081
- $3 * ts_rank(to_tsvector('english', ${metadataCol || "''"}::text), plainto_tsquery('english', $4))
1082
- )`;
1083
- let sql = `
1084
- SELECT
1085
- *,
1086
- ${combinedScoreExpr} as score
1087
- FROM "${this.table}"
1088
- `;
1089
- const params = [queryVector, vectorWeight, 1 - vectorWeight, tsQueryText];
1090
- let paramIndex = 5;
1091
- let hasWhere = false;
1092
- if (filter && Object.keys(filter).length > 0 && metadataCol) {
1093
- const conditions = [];
1094
- for (const [key, value] of Object.entries(filter)) {
1095
- if (!SAFE_IDENTIFIER_RE.test(key)) {
1096
- throw new StorageValidationError(`Invalid metadata filter key: "${key}". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`);
1097
- }
1098
- conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);
1099
- params.push(String(value));
1100
- paramIndex++;
1101
- }
1102
- if (conditions.length > 0) {
1103
- sql += ` WHERE ${conditions.join(" AND ")}`;
1104
- hasWhere = true;
1105
- }
1106
- }
1107
- sql += hasWhere ? " AND" : " WHERE";
1108
- sql += ` ${combinedScoreExpr} >= $${paramIndex}`;
1109
- params.push(scoreThreshold);
1110
- paramIndex++;
1111
- sql += ` ORDER BY score DESC LIMIT $${paramIndex}`;
1112
- params.push(topK);
1113
- const result = await this.db.query(sql, params);
1114
- const results = [];
1115
- for (const row of result.rows) {
1116
- const vectorResult = await this.db.query(`SELECT ${vectorCol}::text FROM "${this.table}" WHERE ${this.getPrimaryKeyWhereClause()}`, this.getPrimaryKeyValues(row));
1117
- const vectorStr = vectorResult.rows[0]?.[vectorColRaw] || "[]";
1118
- const vectorArray = JSON.parse(vectorStr);
1119
- results.push({
1120
- ...row,
1121
- [this.vectorPropertyName]: new this.vectorCtor(vectorArray),
1122
- score: parseFloat(row.score)
1123
- });
1124
- }
1125
- return results;
1126
- } catch (error) {
1127
- if (error instanceof StorageValidationError) {
1128
- throw error;
1129
- }
1130
- console.error("pgvector hybrid query failed, falling back to in-memory search:", error);
1131
- return this.hybridSearchFallback(query, options);
1132
- }
1133
- }
1134
1112
  assertFallbackSupportsDistance() {
1135
1113
  if (this.distance !== "cosine") {
1136
1114
  throw new Error(`PostgresVectorStorage: pgvector is unavailable and the in-memory ` + `fallback only supports cosine distance (configured: "${this.distance}"). ` + `Install pgvector or switch the storage to cosine distance.`);
@@ -1156,40 +1134,6 @@ class PostgresVectorStorage extends PostgresTabularStorage {
1156
1134
  const topResults = results.slice(0, topK);
1157
1135
  return topResults;
1158
1136
  }
1159
- async hybridSearchFallback(query, options) {
1160
- this.assertFallbackSupportsDistance();
1161
- const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;
1162
- const allRows = await this.getAll() || [];
1163
- const results = [];
1164
- const queryLower = textQuery.toLowerCase();
1165
- const queryWords = queryLower.split(/\s+/).filter((w) => w.length > 0);
1166
- for (const row of allRows) {
1167
- const vector = row[this.vectorPropertyName];
1168
- const metadata = this.metadataPropertyName ? row[this.metadataPropertyName] : {};
1169
- if (filter && !this.matchesFilter(metadata, filter)) {
1170
- continue;
1171
- }
1172
- const vectorScore = cosineSimilarity(query, vector);
1173
- const metadataText = Object.values(metadata ?? {}).join(" ").toLowerCase();
1174
- let textScore = 0;
1175
- if (queryWords.length > 0) {
1176
- let matches = 0;
1177
- for (const word of queryWords) {
1178
- if (metadataText.includes(word)) {
1179
- matches++;
1180
- }
1181
- }
1182
- textScore = matches / queryWords.length;
1183
- }
1184
- const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;
1185
- if (combinedScore >= scoreThreshold) {
1186
- results.push({ ...row, score: combinedScore });
1187
- }
1188
- }
1189
- results.sort((a, b) => b.score - a.score);
1190
- const topResults = results.slice(0, topK);
1191
- return topResults;
1192
- }
1193
1137
  getPrimaryKeyWhereClause() {
1194
1138
  const conditions = this.primaryKeyNames.map((key, idx) => `${String(key)} = $${idx + 1}`);
1195
1139
  return conditions.join(" AND ");
@@ -1211,6 +1155,7 @@ import {
1211
1155
  MIGRATIONS_TABLE as MIGRATIONS_TABLE2,
1212
1156
  sortMigrations
1213
1157
  } from "@workglow/storage";
1158
+ var runLocks = new WeakMap;
1214
1159
 
1215
1160
  class PostgresMigrationRunner {
1216
1161
  db;
@@ -1243,6 +1188,15 @@ class PostgresMigrationRunner {
1243
1188
  } };
1244
1189
  }
1245
1190
  async run(migrations, options = {}) {
1191
+ const key = this.db;
1192
+ const prev = runLocks.get(key) ?? Promise.resolve();
1193
+ const result = prev.then(() => this.runInternal(migrations, options));
1194
+ runLocks.set(key, result.catch(() => {
1195
+ return;
1196
+ }));
1197
+ return result;
1198
+ }
1199
+ async runInternal(migrations, options) {
1246
1200
  await this.ensureBookkeepingTable();
1247
1201
  const sorted = sortMigrations(migrations);
1248
1202
  const applied = [];
@@ -1328,4 +1282,4 @@ export {
1328
1282
  POSTGRES_KV_REPOSITORY
1329
1283
  };
1330
1284
 
1331
- //# debugId=1C3E72F1BE3B8A0064756E2164756E21
1285
+ //# debugId=31CB72E3014C272564756E2164756E21