@oracle/langchain-oracledb 0.2.0 → 1.1.0
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/README.md +62 -1
- package/dist/cache.cjs +535 -0
- package/dist/cache.cjs.map +1 -0
- package/dist/cache.d.cts +168 -0
- package/dist/cache.d.ts +168 -0
- package/dist/cache.js +527 -0
- package/dist/cache.js.map +1 -0
- package/dist/chatMessageHistories.cjs +345 -0
- package/dist/chatMessageHistories.cjs.map +1 -0
- package/dist/chatMessageHistories.d.cts +107 -0
- package/dist/chatMessageHistories.d.ts +107 -0
- package/dist/chatMessageHistories.js +338 -0
- package/dist/chatMessageHistories.js.map +1 -0
- package/dist/document_loaders.cjs +4 -3
- package/dist/document_loaders.cjs.map +1 -1
- package/dist/document_loaders.js +4 -3
- package/dist/document_loaders.js.map +1 -1
- package/dist/errors.cjs +123 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +57 -0
- package/dist/errors.d.ts +57 -0
- package/dist/errors.js +113 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +11 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/utils.cjs +49 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +5 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +44 -0
- package/dist/utils.js.map +1 -0
- package/dist/vectorstores.cjs +156 -108
- package/dist/vectorstores.cjs.map +1 -1
- package/dist/vectorstores.d.cts +11 -3
- package/dist/vectorstores.d.ts +11 -3
- package/dist/vectorstores.js +137 -91
- package/dist/vectorstores.js.map +1 -1
- package/package.json +27 -26
package/dist/vectorstores.cjs
CHANGED
|
@@ -3,12 +3,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.OracleVS = exports.dropTablePurge = exports.createIndex = exports.createTable = exports.DistanceStrategy = exports.VectorElementFormat = exports.VectorType = exports.generateWhereClause = void 0;
|
|
6
|
+
exports.OracleVS = exports.dropTablePurge = exports.createIndex = exports.createTable = exports.DistanceStrategy = exports.VectorElementFormat = exports.VectorType = exports.generateWhereClause = exports.isLangChainOracleError = exports.OracleVSErrorCode = exports.OracleVSError = exports.ErrorCode = exports.LangChainOracleError = void 0;
|
|
7
7
|
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
8
|
const oracledb_1 = __importDefault(require("oracledb"));
|
|
9
9
|
const vectorstores_1 = require("@langchain/core/vectorstores");
|
|
10
10
|
const documents_1 = require("@langchain/core/documents");
|
|
11
11
|
const math_1 = require("@langchain/core/utils/math");
|
|
12
|
+
const errors_js_1 = require("./errors.cjs");
|
|
13
|
+
Object.defineProperty(exports, "LangChainOracleError", { enumerable: true, get: function () { return errors_js_1.LangChainOracleError; } });
|
|
14
|
+
Object.defineProperty(exports, "OracleVSError", { enumerable: true, get: function () { return errors_js_1.LangChainOracleError; } });
|
|
15
|
+
Object.defineProperty(exports, "ErrorCode", { enumerable: true, get: function () { return errors_js_1.ErrorCode; } });
|
|
16
|
+
Object.defineProperty(exports, "OracleVSErrorCode", { enumerable: true, get: function () { return errors_js_1.ErrorCode; } });
|
|
17
|
+
Object.defineProperty(exports, "isLangChainOracleError", { enumerable: true, get: function () { return errors_js_1.isLangChainOracleError; } });
|
|
18
|
+
const utils_js_1 = require("./utils.cjs");
|
|
19
|
+
function validateMetadataKey(column) {
|
|
20
|
+
const pattern = /^[a-zA-Z0-9_.[\],\s*]*$/;
|
|
21
|
+
if (!column || !pattern.test(column)) {
|
|
22
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.FILTER_INVALID_METADATA_KEY, column);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
12
25
|
function generateWhereClause(dbFilter, bindValues) {
|
|
13
26
|
// Handle $and
|
|
14
27
|
if ("$and" in dbFilter && Array.isArray(dbFilter.$and)) {
|
|
@@ -44,6 +57,7 @@ function generateWhereClause(dbFilter, bindValues) {
|
|
|
44
57
|
}
|
|
45
58
|
exports.generateWhereClause = generateWhereClause;
|
|
46
59
|
function generateOperatorCondition(column, operator, value, bindValues) {
|
|
60
|
+
validateMetadataKey(column);
|
|
47
61
|
switch (operator) {
|
|
48
62
|
case "$eq":
|
|
49
63
|
return jsonCompare(column, "=", value, bindValues);
|
|
@@ -58,20 +72,23 @@ function generateOperatorCondition(column, operator, value, bindValues) {
|
|
|
58
72
|
case "$gte":
|
|
59
73
|
return jsonCompare(column, ">=", value, bindValues);
|
|
60
74
|
case "$in": {
|
|
61
|
-
if (!Array.isArray(value))
|
|
62
|
-
|
|
75
|
+
if (!Array.isArray(value)) {
|
|
76
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.FILTER_INVALID_VALUE, "$in requires array");
|
|
77
|
+
}
|
|
63
78
|
const inClauses = value.map((v) => jsonCompare(column, "=", v, bindValues));
|
|
64
79
|
return `(${inClauses.join(" OR ")})`;
|
|
65
80
|
}
|
|
66
81
|
case "$nin": {
|
|
67
|
-
if (!Array.isArray(value))
|
|
68
|
-
|
|
82
|
+
if (!Array.isArray(value)) {
|
|
83
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.FILTER_INVALID_VALUE, "$nin requires array");
|
|
84
|
+
}
|
|
69
85
|
const ninClauses = value.map((v) => jsonCompare(column, "!=", v, bindValues));
|
|
70
86
|
return `(${ninClauses.join(" AND ")})`;
|
|
71
87
|
}
|
|
72
88
|
case "$between": {
|
|
73
|
-
if (!Array.isArray(value) || value.length !== 2)
|
|
74
|
-
|
|
89
|
+
if (!Array.isArray(value) || value.length !== 2) {
|
|
90
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.FILTER_INVALID_VALUE, "$between requires [low, high]");
|
|
91
|
+
}
|
|
75
92
|
const [low, high] = value;
|
|
76
93
|
bindValues.push(low, high);
|
|
77
94
|
const posLow = bindValues.length - 1;
|
|
@@ -86,7 +103,7 @@ function generateOperatorCondition(column, operator, value, bindValues) {
|
|
|
86
103
|
return `NOT JSON_EXISTS(metadata, '$.${column}')`;
|
|
87
104
|
}
|
|
88
105
|
default:
|
|
89
|
-
|
|
106
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.FILTER_UNSUPPORTED_OPERATOR, operator);
|
|
90
107
|
}
|
|
91
108
|
}
|
|
92
109
|
// Helper: build JSON_EXISTS clause for comparison
|
|
@@ -116,42 +133,11 @@ exports.DistanceStrategy = {
|
|
|
116
133
|
HAMMING: "HAMMING",
|
|
117
134
|
EUCLIDEAN_SQUARED: "EUCLIDEAN_SQUARED",
|
|
118
135
|
};
|
|
119
|
-
function handleError(error) {
|
|
120
|
-
// Type guard to check if the error is an object and has 'name' and 'message' properties
|
|
121
|
-
if (typeof error === "object" &&
|
|
122
|
-
error !== null &&
|
|
123
|
-
"name" in error &&
|
|
124
|
-
"message" in error) {
|
|
125
|
-
const err = error; // Type assertion based on guarded checks
|
|
126
|
-
// Handle specific error types based on the name property
|
|
127
|
-
switch (err.name) {
|
|
128
|
-
case "RuntimeError":
|
|
129
|
-
throw new Error("Database operation failed due to a runtime error.");
|
|
130
|
-
case "ValidationError":
|
|
131
|
-
throw new Error("Operation failed due to a validation error.");
|
|
132
|
-
default:
|
|
133
|
-
throw new Error(`An unexpected error occurred during the operation. ${error}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
throw new Error(`An unknown and unexpected error occurred. ${error}`);
|
|
137
|
-
}
|
|
138
136
|
function isPool(client) {
|
|
139
137
|
return "getConnection" in client;
|
|
140
138
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
const validateRegex = /^(?:"[^"]+"|[^".]+)(?:\.(?:"[^"]+"|[^".]+))*$/;
|
|
144
|
-
if (!validateRegex.test(name)) {
|
|
145
|
-
throw new Error(`Identifier name ${identifier} is not valid.`);
|
|
146
|
-
}
|
|
147
|
-
// extracts parts of the identifier with quoted and unquoted.
|
|
148
|
-
const matchRegex = /"([^"]+)"|([^".]+)/g;
|
|
149
|
-
const groups = [];
|
|
150
|
-
for (const match of name.matchAll(matchRegex)) {
|
|
151
|
-
groups.push(match[1] || match[2]);
|
|
152
|
-
}
|
|
153
|
-
const quotedParts = groups.map((g) => `"${g}"`);
|
|
154
|
-
return quotedParts.join(".");
|
|
139
|
+
function isClientProvider(client) {
|
|
140
|
+
return typeof client === "function";
|
|
155
141
|
}
|
|
156
142
|
const isFloat32Array = (value) =>
|
|
157
143
|
// eslint-disable-next-line no-instanceof/no-instanceof
|
|
@@ -186,25 +172,26 @@ function normalizeVectorFormat(value, vectorType) {
|
|
|
186
172
|
const format = validFormats.includes(normalizedValue)
|
|
187
173
|
? normalizedValue
|
|
188
174
|
: exports.VectorElementFormat.FLOAT32;
|
|
189
|
-
if (vectorType === exports.VectorType.SPARSE &&
|
|
190
|
-
|
|
175
|
+
if (vectorType === exports.VectorType.SPARSE &&
|
|
176
|
+
format === exports.VectorElementFormat.BINARY) {
|
|
177
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_CONFIGURATION, "BINARY format is not supported for SPARSE vectors.");
|
|
191
178
|
}
|
|
192
179
|
return format;
|
|
193
180
|
}
|
|
194
181
|
function buildVectorColumnDefinition(embeddingDim, customization) {
|
|
195
182
|
if (embeddingDim === undefined || embeddingDim === null) {
|
|
196
|
-
|
|
183
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_CONFIGURATION, "Embedding dimension is required to create the vector column.");
|
|
197
184
|
}
|
|
198
185
|
if (!Number.isInteger(embeddingDim) || embeddingDim <= 0) {
|
|
199
|
-
|
|
186
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_CONFIGURATION, "Embedding dimension must be a positive integer.");
|
|
200
187
|
}
|
|
201
188
|
const vectorType = normalizeVectorTypeValue(customization?.vectorType);
|
|
202
189
|
if (vectorType === exports.VectorType.SPARSE && customization?.format === undefined) {
|
|
203
|
-
|
|
190
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_CONFIGURATION, "Sparse vector type requires a vector format to be specified.");
|
|
204
191
|
}
|
|
205
192
|
const format = normalizeVectorFormat(customization?.format, vectorType);
|
|
206
193
|
if (format === exports.VectorElementFormat.BINARY && embeddingDim % 8 !== 0) {
|
|
207
|
-
|
|
194
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_CONFIGURATION, "BINARY vector format requires dimensions to be a multiple of 8.");
|
|
208
195
|
}
|
|
209
196
|
const dimensionSegment = String(embeddingDim);
|
|
210
197
|
const formatSegment = format ?? exports.VectorElementFormat.FLOAT32;
|
|
@@ -220,7 +207,7 @@ function escapePlSqlLiteral(sql) {
|
|
|
220
207
|
return sql.replace(/'/g, "''");
|
|
221
208
|
}
|
|
222
209
|
async function createTable(connection, tableName, embeddingDim, customization) {
|
|
223
|
-
const tableIdentifier = quoteIdentifier(tableName);
|
|
210
|
+
const tableIdentifier = (0, utils_js_1.quoteIdentifier)(tableName);
|
|
224
211
|
const colsDict = {
|
|
225
212
|
id: "RAW(16) DEFAULT SYS_GUID() PRIMARY KEY",
|
|
226
213
|
external_id: `VARCHAR2(36) UNIQUE`,
|
|
@@ -252,7 +239,7 @@ async function createTable(connection, tableName, embeddingDim, customization) {
|
|
|
252
239
|
const columnKey = columnName.trim().toLowerCase();
|
|
253
240
|
if (!(columnKey in colsDict))
|
|
254
241
|
continue;
|
|
255
|
-
const normalizedColumnIdentifier = `${tableIdentifier}.${quoteIdentifier(columnKey.toUpperCase())}`;
|
|
242
|
+
const normalizedColumnIdentifier = `${tableIdentifier}.${(0, utils_js_1.quoteIdentifier)(columnKey.toUpperCase())}`;
|
|
256
243
|
const escapedNote = escapeCommentText(trimmedNote);
|
|
257
244
|
statements.push(`EXECUTE IMMEDIATE 'COMMENT ON COLUMN ${normalizedColumnIdentifier} IS ''${escapedNote}''';`);
|
|
258
245
|
}
|
|
@@ -261,7 +248,7 @@ async function createTable(connection, tableName, embeddingDim, customization) {
|
|
|
261
248
|
await connection.execute(block);
|
|
262
249
|
}
|
|
263
250
|
catch (error) {
|
|
264
|
-
handleError(error);
|
|
251
|
+
(0, errors_js_1.handleError)(error);
|
|
265
252
|
}
|
|
266
253
|
}
|
|
267
254
|
exports.createTable = createTable;
|
|
@@ -296,7 +283,7 @@ function convertDenseVectorForFormat(values, format) {
|
|
|
296
283
|
for (let i = 0; i < values.length; i += 1) {
|
|
297
284
|
const rounded = Math.round(values[i]);
|
|
298
285
|
if (rounded < -128 || rounded > 127) {
|
|
299
|
-
|
|
286
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_VALUE, "INT8 vector values must be within [-128, 127].");
|
|
300
287
|
}
|
|
301
288
|
clamped[i] = rounded;
|
|
302
289
|
}
|
|
@@ -336,10 +323,10 @@ async function createHNSWIndex(connection, oraclevs, params = {}) {
|
|
|
336
323
|
const { idxName = _getIndexName("HNSW"), idxType = "HNSW", neighbors = 32, efConstruction = 200, accuracy = 90, parallel = 8, ...extra } = params;
|
|
337
324
|
const invalidKeys = Object.keys(extra);
|
|
338
325
|
if (invalidKeys.length > 0) {
|
|
339
|
-
|
|
326
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_INDEX_PARAMETERS, invalidKeys);
|
|
340
327
|
}
|
|
341
328
|
const ddl = `
|
|
342
|
-
CREATE VECTOR INDEX IF NOT EXISTS ${quoteIdentifier(idxName)}
|
|
329
|
+
CREATE VECTOR INDEX IF NOT EXISTS ${(0, utils_js_1.quoteIdentifier)(idxName)}
|
|
343
330
|
ON ${oraclevs.tableName}(embedding)
|
|
344
331
|
ORGANIZATION INMEMORY NEIGHBOR GRAPH
|
|
345
332
|
WITH TARGET ACCURACY ${accuracy}
|
|
@@ -352,7 +339,7 @@ async function createHNSWIndex(connection, oraclevs, params = {}) {
|
|
|
352
339
|
await connection.execute(ddl);
|
|
353
340
|
}
|
|
354
341
|
catch (error) {
|
|
355
|
-
handleError(error);
|
|
342
|
+
(0, errors_js_1.handleError)(error);
|
|
356
343
|
}
|
|
357
344
|
}
|
|
358
345
|
async function createIVFIndex(connection, oraclevs, params = {}) {
|
|
@@ -360,10 +347,10 @@ async function createIVFIndex(connection, oraclevs, params = {}) {
|
|
|
360
347
|
const { idxName = _getIndexName("IVF"), idxType = "IVF", neighborPart = 32, accuracy = 90, parallel = 8, ...extra } = params;
|
|
361
348
|
const invalidKeys = Object.keys(extra);
|
|
362
349
|
if (invalidKeys.length > 0) {
|
|
363
|
-
|
|
350
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_INDEX_PARAMETERS, invalidKeys);
|
|
364
351
|
}
|
|
365
352
|
const ddl = `
|
|
366
|
-
CREATE VECTOR INDEX IF NOT EXISTS ${quoteIdentifier(idxName)}
|
|
353
|
+
CREATE VECTOR INDEX IF NOT EXISTS ${(0, utils_js_1.quoteIdentifier)(idxName)}
|
|
367
354
|
ON ${oraclevs.tableName}(embedding)
|
|
368
355
|
ORGANIZATION NEIGHBOR PARTITIONS
|
|
369
356
|
WITH TARGET ACCURACY ${accuracy}
|
|
@@ -376,16 +363,16 @@ async function createIVFIndex(connection, oraclevs, params = {}) {
|
|
|
376
363
|
await connection.execute(ddl);
|
|
377
364
|
}
|
|
378
365
|
catch (error) {
|
|
379
|
-
handleError(error);
|
|
366
|
+
(0, errors_js_1.handleError)(error);
|
|
380
367
|
}
|
|
381
368
|
}
|
|
382
369
|
async function dropTablePurge(connection, tableName) {
|
|
383
370
|
try {
|
|
384
|
-
const ddl = `DROP TABLE IF EXISTS ${quoteIdentifier(tableName)} PURGE`;
|
|
371
|
+
const ddl = `DROP TABLE IF EXISTS ${(0, utils_js_1.quoteIdentifier)(tableName)} PURGE`;
|
|
385
372
|
await connection.execute(ddl);
|
|
386
373
|
}
|
|
387
374
|
catch (error) {
|
|
388
|
-
handleError(error);
|
|
375
|
+
(0, errors_js_1.handleError)(error);
|
|
389
376
|
}
|
|
390
377
|
}
|
|
391
378
|
exports.dropTablePurge = dropTablePurge;
|
|
@@ -401,6 +388,14 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
401
388
|
writable: true,
|
|
402
389
|
value: void 0
|
|
403
390
|
});
|
|
391
|
+
// Tracks connections borrowed from a pool so retConnection() can return them
|
|
392
|
+
// without closing direct connections owned by the caller.
|
|
393
|
+
Object.defineProperty(this, "poolConnections", {
|
|
394
|
+
enumerable: true,
|
|
395
|
+
configurable: true,
|
|
396
|
+
writable: true,
|
|
397
|
+
value: new WeakSet()
|
|
398
|
+
});
|
|
404
399
|
Object.defineProperty(this, "embeddingDimension", {
|
|
405
400
|
enumerable: true,
|
|
406
401
|
configurable: true,
|
|
@@ -457,7 +452,7 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
457
452
|
});
|
|
458
453
|
try {
|
|
459
454
|
this.client = dbConfig.client;
|
|
460
|
-
this.tableName = quoteIdentifier(dbConfig.tableName);
|
|
455
|
+
this.tableName = (0, utils_js_1.quoteIdentifier)(dbConfig.tableName);
|
|
461
456
|
this.distanceStrategy =
|
|
462
457
|
dbConfig.distanceStrategy ?? this.distanceStrategy;
|
|
463
458
|
this.query = dbConfig.query;
|
|
@@ -470,20 +465,24 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
470
465
|
this.vectorFormat = dbConfig.format;
|
|
471
466
|
}
|
|
472
467
|
catch (error) {
|
|
473
|
-
handleError(error);
|
|
468
|
+
(0, errors_js_1.handleError)(error);
|
|
474
469
|
}
|
|
475
470
|
}
|
|
476
471
|
getActiveVectorType() {
|
|
477
|
-
return this.vectorType
|
|
472
|
+
return this.vectorType
|
|
473
|
+
? normalizeVectorTypeValue(this.vectorType)
|
|
474
|
+
: exports.VectorType.DENSE;
|
|
478
475
|
}
|
|
479
476
|
ensureEmbeddingDimension() {
|
|
480
|
-
if (this.embeddingDimension === undefined ||
|
|
481
|
-
|
|
477
|
+
if (this.embeddingDimension === undefined ||
|
|
478
|
+
this.embeddingDimension === null) {
|
|
479
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.STATE_INVALID, "Embedding dimension is not initialized for this vector store.");
|
|
482
480
|
}
|
|
483
481
|
return this.embeddingDimension;
|
|
484
482
|
}
|
|
485
483
|
prepareVectorForStorage(vector) {
|
|
486
|
-
if (this.embeddingDimension === undefined ||
|
|
484
|
+
if (this.embeddingDimension === undefined ||
|
|
485
|
+
this.embeddingDimension === null) {
|
|
487
486
|
this.embeddingDimension = vector.length;
|
|
488
487
|
}
|
|
489
488
|
const dimension = this.ensureEmbeddingDimension();
|
|
@@ -493,30 +492,63 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
493
492
|
: exports.VectorElementFormat.FLOAT32;
|
|
494
493
|
if (vectorType === exports.VectorType.SPARSE) {
|
|
495
494
|
if (vector.length !== dimension) {
|
|
496
|
-
|
|
495
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_VALUE, "Sparse vectors must supply full-dimension arrays for conversion.");
|
|
497
496
|
}
|
|
498
|
-
|
|
497
|
+
// The dense-input SparseVector constructor stores its values as a
|
|
498
|
+
// Float64Array regardless of the typed array passed in, so FLOAT32 and
|
|
499
|
+
// INT8 query vectors reach the database as FLOAT64 and VECTOR_DISTANCE()
|
|
500
|
+
// fails with ORA-51812 against a non-FLOAT64 sparse column. The
|
|
501
|
+
// object-form constructor preserves the values' typed array, so build
|
|
502
|
+
// the nonzero indices/values explicitly and use that form.
|
|
503
|
+
const indices = [];
|
|
504
|
+
const nonzero = [];
|
|
499
505
|
if (format === exports.VectorElementFormat.INT8) {
|
|
500
|
-
const clamped = new Int8Array(vector.length);
|
|
501
506
|
for (let i = 0; i < vector.length; i += 1) {
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
507
|
+
const value = vector[i];
|
|
508
|
+
const rounded = Math.round(value);
|
|
509
|
+
if (!Number.isFinite(value) || rounded < -128 || rounded > 127) {
|
|
510
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_VALUE, "INT8 sparse vector values must be finite and within [-128, 127].");
|
|
511
|
+
}
|
|
512
|
+
if (rounded !== 0) {
|
|
513
|
+
indices.push(i);
|
|
514
|
+
nonzero.push(rounded);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
else if (format === exports.VectorElementFormat.FLOAT32) {
|
|
519
|
+
for (let i = 0; i < vector.length; i += 1) {
|
|
520
|
+
if (Math.fround(vector[i]) !== 0) {
|
|
521
|
+
indices.push(i);
|
|
522
|
+
nonzero.push(vector[i]);
|
|
505
523
|
}
|
|
506
|
-
clamped[i] = rounded;
|
|
507
524
|
}
|
|
508
|
-
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
for (let i = 0; i < vector.length; i += 1) {
|
|
528
|
+
if (vector[i] !== 0) {
|
|
529
|
+
indices.push(i);
|
|
530
|
+
nonzero.push(vector[i]);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
let values;
|
|
535
|
+
if (format === exports.VectorElementFormat.INT8) {
|
|
536
|
+
values = new Int8Array(nonzero);
|
|
509
537
|
}
|
|
510
538
|
else if (format === exports.VectorElementFormat.FLOAT64) {
|
|
511
|
-
|
|
539
|
+
values = new Float64Array(nonzero);
|
|
512
540
|
}
|
|
513
|
-
else
|
|
514
|
-
|
|
541
|
+
else {
|
|
542
|
+
values = new Float32Array(nonzero);
|
|
515
543
|
}
|
|
516
|
-
return new oracledb_1.default.SparseVector(
|
|
544
|
+
return new oracledb_1.default.SparseVector({
|
|
545
|
+
values,
|
|
546
|
+
indices: new Uint32Array(indices),
|
|
547
|
+
numDimensions: vector.length,
|
|
548
|
+
});
|
|
517
549
|
}
|
|
518
550
|
if (vector.length !== dimension) {
|
|
519
|
-
|
|
551
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_INVALID_VALUE, "Vector length does not match the embedding dimension.");
|
|
520
552
|
}
|
|
521
553
|
return convertDenseVectorForFormat(vector, format);
|
|
522
554
|
}
|
|
@@ -529,7 +561,7 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
529
561
|
if (isSparseVector(value)) {
|
|
530
562
|
const dense = value.dense?.();
|
|
531
563
|
if (!dense) {
|
|
532
|
-
|
|
564
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_UNSUPPORTED_REPRESENTATION, "Unable to expand sparse vector to dense representation.");
|
|
533
565
|
}
|
|
534
566
|
if (isFloat32Array(dense)) {
|
|
535
567
|
return dense;
|
|
@@ -545,13 +577,16 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
545
577
|
}
|
|
546
578
|
return Float32Array.from(dense);
|
|
547
579
|
}
|
|
548
|
-
if (isFloat32Array(value) ||
|
|
580
|
+
if (isFloat32Array(value) ||
|
|
581
|
+
isFloat64Array(value) ||
|
|
582
|
+
isInt8Array(value) ||
|
|
583
|
+
isUint8Array(value)) {
|
|
549
584
|
return value;
|
|
550
585
|
}
|
|
551
586
|
if (Array.isArray(value)) {
|
|
552
587
|
return value;
|
|
553
588
|
}
|
|
554
|
-
|
|
589
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VECTOR_UNSUPPORTED_REPRESENTATION, "Received unsupported vector representation from the database.");
|
|
555
590
|
}
|
|
556
591
|
// Normalizes any supported vector representation into Float32Array so downstream math
|
|
557
592
|
// (MMR, distance calculations) can assume a consistent element type without forcing
|
|
@@ -589,34 +624,41 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
589
624
|
description: this.description,
|
|
590
625
|
annotations: this.annotations,
|
|
591
626
|
vectorType: this.vectorType,
|
|
592
|
-
format: this.vectorFormat
|
|
627
|
+
format: this.vectorFormat,
|
|
593
628
|
});
|
|
594
629
|
}
|
|
595
630
|
catch (error) {
|
|
596
|
-
handleError(error);
|
|
631
|
+
(0, errors_js_1.handleError)(error);
|
|
597
632
|
}
|
|
598
633
|
finally {
|
|
599
634
|
if (connection)
|
|
600
635
|
await this.retConnection(connection);
|
|
601
636
|
}
|
|
602
637
|
}
|
|
638
|
+
async resolveClient() {
|
|
639
|
+
return isClientProvider(this.client) ? await this.client() : this.client;
|
|
640
|
+
}
|
|
603
641
|
async getConnection() {
|
|
604
642
|
try {
|
|
605
|
-
|
|
606
|
-
|
|
643
|
+
const client = await this.resolveClient();
|
|
644
|
+
if (isPool(client)) {
|
|
645
|
+
const connection = await client.getConnection();
|
|
646
|
+
this.poolConnections.add(connection);
|
|
647
|
+
return connection;
|
|
607
648
|
}
|
|
608
|
-
return
|
|
649
|
+
return client;
|
|
609
650
|
}
|
|
610
651
|
catch (error) {
|
|
611
|
-
handleError(error);
|
|
652
|
+
(0, errors_js_1.handleError)(error);
|
|
612
653
|
}
|
|
613
654
|
}
|
|
614
655
|
// Close connection or return it to the pool
|
|
615
656
|
async retConnection(connection) {
|
|
616
657
|
try {
|
|
617
|
-
// If
|
|
618
|
-
if (
|
|
658
|
+
// If this public connection came from any pool, close it to return it to the pool.
|
|
659
|
+
if (this.poolConnections.has(connection)) {
|
|
619
660
|
await connection.close();
|
|
661
|
+
this.poolConnections.delete(connection);
|
|
620
662
|
}
|
|
621
663
|
}
|
|
622
664
|
catch (error) {
|
|
@@ -634,16 +676,15 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
634
676
|
*/
|
|
635
677
|
async addVectors(vectors, documents, options) {
|
|
636
678
|
if (vectors.length === 0) {
|
|
637
|
-
|
|
679
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VALIDATION_INVALID_INPUT, "Vectors input null. Nothing to add...");
|
|
638
680
|
}
|
|
639
681
|
const inputIds = options?.ids;
|
|
640
682
|
let connection = null;
|
|
641
683
|
try {
|
|
642
684
|
// Ensure there are IDs for all documents
|
|
643
685
|
if (inputIds !== undefined && inputIds.length !== vectors.length) {
|
|
644
|
-
|
|
686
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VALIDATION_INVALID_INPUT, "The number of ids must match the number of vectors provided.");
|
|
645
687
|
}
|
|
646
|
-
connection = await this.getConnection();
|
|
647
688
|
const finalIds = [];
|
|
648
689
|
const binds = [];
|
|
649
690
|
for (let index = 0; index < documents.length; index += 1) {
|
|
@@ -689,13 +730,14 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
689
730
|
},
|
|
690
731
|
autoCommit: false,
|
|
691
732
|
};
|
|
733
|
+
connection = await this.getConnection();
|
|
692
734
|
await connection.executeMany(sql, binds, executeOptions);
|
|
693
735
|
// Commit once all inserts are queued up
|
|
694
736
|
await connection.commit();
|
|
695
737
|
return finalIds;
|
|
696
738
|
}
|
|
697
739
|
catch (error) {
|
|
698
|
-
return handleError(error);
|
|
740
|
+
return (0, errors_js_1.handleError)(error);
|
|
699
741
|
}
|
|
700
742
|
finally {
|
|
701
743
|
if (connection) {
|
|
@@ -719,14 +761,22 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
719
761
|
let connection = null;
|
|
720
762
|
try {
|
|
721
763
|
const bindValues = [this.prepareQueryVector(query)];
|
|
764
|
+
const hasFilter = !!filter && Object.keys(filter).length > 0;
|
|
765
|
+
// Keep the vector index hint for unfiltered searches. When a JSON filter
|
|
766
|
+
// is present, forcing VECTOR_INDEX_TRANSFORM can change result semantics
|
|
767
|
+
// by doing approximate top-k before the filter is applied.
|
|
768
|
+
const selectClause = hasFilter
|
|
769
|
+
? "SELECT"
|
|
770
|
+
: `SELECT /*+ VECTOR_INDEX_TRANSFORM(${this.tableName}) */`;
|
|
722
771
|
let sqlQuery = `
|
|
723
|
-
|
|
772
|
+
${selectClause}
|
|
773
|
+
external_id,
|
|
724
774
|
text,
|
|
725
775
|
metadata,
|
|
726
776
|
vector_distance(embedding, :1, ${this.distanceStrategy}) as distance,
|
|
727
777
|
embedding
|
|
728
778
|
FROM ${this.tableName} `;
|
|
729
|
-
if (
|
|
779
|
+
if (hasFilter) {
|
|
730
780
|
sqlQuery += ` WHERE ${generateWhereClause(filter, bindValues)}`;
|
|
731
781
|
}
|
|
732
782
|
bindValues.push(k);
|
|
@@ -754,14 +804,10 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
754
804
|
docsScoresAndEmbeddings.push([document, distance, embedding]);
|
|
755
805
|
}
|
|
756
806
|
}
|
|
757
|
-
else {
|
|
758
|
-
// Throw an exception if no rows are found
|
|
759
|
-
throw new Error("No rows found.");
|
|
760
|
-
}
|
|
761
807
|
}
|
|
762
808
|
finally {
|
|
763
809
|
if (connection) {
|
|
764
|
-
await
|
|
810
|
+
await this.retConnection(connection);
|
|
765
811
|
}
|
|
766
812
|
}
|
|
767
813
|
return docsScoresAndEmbeddings;
|
|
@@ -839,17 +885,19 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
839
885
|
}
|
|
840
886
|
}
|
|
841
887
|
catch (error) {
|
|
842
|
-
handleError(error);
|
|
888
|
+
(0, errors_js_1.handleError)(error);
|
|
843
889
|
}
|
|
844
890
|
finally {
|
|
845
|
-
if (connection)
|
|
846
|
-
await
|
|
891
|
+
if (connection) {
|
|
892
|
+
await this.retConnection(connection);
|
|
893
|
+
}
|
|
847
894
|
}
|
|
848
895
|
}
|
|
849
896
|
static async fromDocuments(documents, embeddings, dbConfig, options) {
|
|
850
897
|
const { client } = dbConfig;
|
|
851
|
-
if (!client)
|
|
852
|
-
|
|
898
|
+
if (!client) {
|
|
899
|
+
(0, errors_js_1.throwError)(errors_js_1.ErrorCode.VALIDATION_MISSING_REQUIRED_PARAMETER, "client");
|
|
900
|
+
}
|
|
853
901
|
try {
|
|
854
902
|
const vss = new OracleVS(embeddings, dbConfig);
|
|
855
903
|
await vss.initialize();
|
|
@@ -860,7 +908,7 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
860
908
|
return vss;
|
|
861
909
|
}
|
|
862
910
|
catch (error) {
|
|
863
|
-
handleError(error);
|
|
911
|
+
(0, errors_js_1.handleError)(error);
|
|
864
912
|
}
|
|
865
913
|
}
|
|
866
914
|
/**
|
|
@@ -869,8 +917,8 @@ class OracleVS extends vectorstores_1.VectorStore {
|
|
|
869
917
|
* inside the pool are terminated.
|
|
870
918
|
*/
|
|
871
919
|
async end() {
|
|
872
|
-
if (isPool(this.client)) {
|
|
873
|
-
await this.client
|
|
920
|
+
if (!isClientProvider(this.client) && isPool(this.client)) {
|
|
921
|
+
await this.client.close();
|
|
874
922
|
}
|
|
875
923
|
}
|
|
876
924
|
}
|