redis-vl 0.1.0-beta.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/LICENSE +22 -0
- package/README.md +212 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +87 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/indexes/search-index.d.ts +368 -0
- package/dist/indexes/search-index.d.ts.map +1 -0
- package/dist/indexes/search-index.js +475 -0
- package/dist/indexes/search-index.js.map +1 -0
- package/dist/query/base.d.ts +51 -0
- package/dist/query/base.d.ts.map +1 -0
- package/dist/query/base.js +6 -0
- package/dist/query/base.js.map +1 -0
- package/dist/query/index.d.ts +7 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +7 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/vector.d.ts +199 -0
- package/dist/query/vector.d.ts.map +1 -0
- package/dist/query/vector.js +198 -0
- package/dist/query/vector.js.map +1 -0
- package/dist/redis/index-info-parser.d.ts +25 -0
- package/dist/redis/index-info-parser.d.ts.map +1 -0
- package/dist/redis/index-info-parser.js +301 -0
- package/dist/redis/index-info-parser.js.map +1 -0
- package/dist/redis/schema-types.d.ts +81 -0
- package/dist/redis/schema-types.d.ts.map +1 -0
- package/dist/redis/schema-types.js +18 -0
- package/dist/redis/schema-types.js.map +1 -0
- package/dist/redis/utils.d.ts +7 -0
- package/dist/redis/utils.d.ts.map +1 -0
- package/dist/redis/utils.js +221 -0
- package/dist/redis/utils.js.map +1 -0
- package/dist/schema/fields.d.ts +163 -0
- package/dist/schema/fields.d.ts.map +1 -0
- package/dist/schema/fields.js +304 -0
- package/dist/schema/fields.js.map +1 -0
- package/dist/schema/index.d.ts +8 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +8 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/schema.d.ts +247 -0
- package/dist/schema/schema.d.ts.map +1 -0
- package/dist/schema/schema.js +403 -0
- package/dist/schema/schema.js.map +1 -0
- package/dist/schema/types.d.ts +56 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +62 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/storage/base-storage.d.ts +107 -0
- package/dist/storage/base-storage.d.ts.map +1 -0
- package/dist/storage/base-storage.js +187 -0
- package/dist/storage/base-storage.js.map +1 -0
- package/dist/storage/hash-storage.d.ts +29 -0
- package/dist/storage/hash-storage.d.ts.map +1 -0
- package/dist/storage/hash-storage.js +122 -0
- package/dist/storage/hash-storage.js.map +1 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +4 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/json-storage.d.ts +19 -0
- package/dist/storage/json-storage.d.ts.map +1 -0
- package/dist/storage/json-storage.js +81 -0
- package/dist/storage/json-storage.js.map +1 -0
- package/dist/utils/distance.d.ts +92 -0
- package/dist/utils/distance.d.ts.map +1 -0
- package/dist/utils/distance.js +98 -0
- package/dist/utils/distance.js.map +1 -0
- package/dist/vectorizers/base-vectorizer.d.ts +88 -0
- package/dist/vectorizers/base-vectorizer.d.ts.map +1 -0
- package/dist/vectorizers/base-vectorizer.js +32 -0
- package/dist/vectorizers/base-vectorizer.js.map +1 -0
- package/dist/vectorizers/huggingface-vectorizer.d.ts +103 -0
- package/dist/vectorizers/huggingface-vectorizer.d.ts.map +1 -0
- package/dist/vectorizers/huggingface-vectorizer.js +142 -0
- package/dist/vectorizers/huggingface-vectorizer.js.map +1 -0
- package/dist/vectorizers/index.d.ts +10 -0
- package/dist/vectorizers/index.d.ts.map +1 -0
- package/dist/vectorizers/index.js +10 -0
- package/dist/vectorizers/index.js.map +1 -0
- package/package.json +96 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field types supported by RedisVL
|
|
3
|
+
*/
|
|
4
|
+
export declare enum FieldType {
|
|
5
|
+
TAG = "tag",
|
|
6
|
+
TEXT = "text",
|
|
7
|
+
NUMERIC = "numeric",
|
|
8
|
+
GEO = "geo",
|
|
9
|
+
VECTOR = "vector"
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Storage types for documents in Redis
|
|
13
|
+
*/
|
|
14
|
+
export declare enum StorageType {
|
|
15
|
+
HASH = "hash",
|
|
16
|
+
JSON = "json"
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Vector distance metrics
|
|
20
|
+
*/
|
|
21
|
+
export declare enum VectorDistanceMetric {
|
|
22
|
+
COSINE = "COSINE",
|
|
23
|
+
L2 = "L2",
|
|
24
|
+
IP = "IP"
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Vector data types
|
|
28
|
+
*/
|
|
29
|
+
export declare enum VectorDataType {
|
|
30
|
+
BFLOAT16 = "BFLOAT16",
|
|
31
|
+
FLOAT16 = "FLOAT16",
|
|
32
|
+
FLOAT32 = "FLOAT32",
|
|
33
|
+
FLOAT64 = "FLOAT64",
|
|
34
|
+
INT8 = "INT8",
|
|
35
|
+
UINT8 = "UINT8"
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Vector index algorithms
|
|
39
|
+
*/
|
|
40
|
+
export declare enum VectorIndexAlgorithm {
|
|
41
|
+
FLAT = "FLAT",
|
|
42
|
+
HNSW = "HNSW",
|
|
43
|
+
SVS_VAMANA = "SVS-VAMANA"
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Vector compression types for SVS-VAMANA algorithm
|
|
47
|
+
*/
|
|
48
|
+
export declare enum CompressionType {
|
|
49
|
+
LVQ4 = "LVQ4",
|
|
50
|
+
LVQ4x4 = "LVQ4x4",
|
|
51
|
+
LVQ4x8 = "LVQ4x8",
|
|
52
|
+
LVQ8 = "LVQ8",
|
|
53
|
+
LeanVec4x8 = "LeanVec4x8",
|
|
54
|
+
LeanVec8x8 = "LeanVec8x8"
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,SAAS;IACjB,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,GAAG,QAAQ;IACX,MAAM,WAAW;CACpB;AAED;;GAEG;AACH,oBAAY,WAAW;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;CAChB;AAED;;GAEG;AACH,oBAAY,oBAAoB;IAC5B,MAAM,WAAW;IACjB,EAAE,OAAO;IACT,EAAE,OAAO;CACZ;AAED;;GAEG;AACH,oBAAY,cAAc;IACtB,QAAQ,aAAa;IACrB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,OAAO,YAAY;IACnB,IAAI,SAAS;IACb,KAAK,UAAU;CAClB;AAED;;GAEG;AACH,oBAAY,oBAAoB;IAC5B,IAAI,SAAS;IACb,IAAI,SAAS;IACb,UAAU,eAAe;CAC5B;AAED;;GAEG;AACH,oBAAY,eAAe;IACvB,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,UAAU,eAAe;CAC5B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Field types supported by RedisVL
|
|
3
|
+
*/
|
|
4
|
+
export var FieldType;
|
|
5
|
+
(function (FieldType) {
|
|
6
|
+
FieldType["TAG"] = "tag";
|
|
7
|
+
FieldType["TEXT"] = "text";
|
|
8
|
+
FieldType["NUMERIC"] = "numeric";
|
|
9
|
+
FieldType["GEO"] = "geo";
|
|
10
|
+
FieldType["VECTOR"] = "vector";
|
|
11
|
+
})(FieldType || (FieldType = {}));
|
|
12
|
+
/**
|
|
13
|
+
* Storage types for documents in Redis
|
|
14
|
+
*/
|
|
15
|
+
export var StorageType;
|
|
16
|
+
(function (StorageType) {
|
|
17
|
+
StorageType["HASH"] = "hash";
|
|
18
|
+
StorageType["JSON"] = "json";
|
|
19
|
+
})(StorageType || (StorageType = {}));
|
|
20
|
+
/**
|
|
21
|
+
* Vector distance metrics
|
|
22
|
+
*/
|
|
23
|
+
export var VectorDistanceMetric;
|
|
24
|
+
(function (VectorDistanceMetric) {
|
|
25
|
+
VectorDistanceMetric["COSINE"] = "COSINE";
|
|
26
|
+
VectorDistanceMetric["L2"] = "L2";
|
|
27
|
+
VectorDistanceMetric["IP"] = "IP";
|
|
28
|
+
})(VectorDistanceMetric || (VectorDistanceMetric = {}));
|
|
29
|
+
/**
|
|
30
|
+
* Vector data types
|
|
31
|
+
*/
|
|
32
|
+
export var VectorDataType;
|
|
33
|
+
(function (VectorDataType) {
|
|
34
|
+
VectorDataType["BFLOAT16"] = "BFLOAT16";
|
|
35
|
+
VectorDataType["FLOAT16"] = "FLOAT16";
|
|
36
|
+
VectorDataType["FLOAT32"] = "FLOAT32";
|
|
37
|
+
VectorDataType["FLOAT64"] = "FLOAT64";
|
|
38
|
+
VectorDataType["INT8"] = "INT8";
|
|
39
|
+
VectorDataType["UINT8"] = "UINT8";
|
|
40
|
+
})(VectorDataType || (VectorDataType = {}));
|
|
41
|
+
/**
|
|
42
|
+
* Vector index algorithms
|
|
43
|
+
*/
|
|
44
|
+
export var VectorIndexAlgorithm;
|
|
45
|
+
(function (VectorIndexAlgorithm) {
|
|
46
|
+
VectorIndexAlgorithm["FLAT"] = "FLAT";
|
|
47
|
+
VectorIndexAlgorithm["HNSW"] = "HNSW";
|
|
48
|
+
VectorIndexAlgorithm["SVS_VAMANA"] = "SVS-VAMANA";
|
|
49
|
+
})(VectorIndexAlgorithm || (VectorIndexAlgorithm = {}));
|
|
50
|
+
/**
|
|
51
|
+
* Vector compression types for SVS-VAMANA algorithm
|
|
52
|
+
*/
|
|
53
|
+
export var CompressionType;
|
|
54
|
+
(function (CompressionType) {
|
|
55
|
+
CompressionType["LVQ4"] = "LVQ4";
|
|
56
|
+
CompressionType["LVQ4x4"] = "LVQ4x4";
|
|
57
|
+
CompressionType["LVQ4x8"] = "LVQ4x8";
|
|
58
|
+
CompressionType["LVQ8"] = "LVQ8";
|
|
59
|
+
CompressionType["LeanVec4x8"] = "LeanVec4x8";
|
|
60
|
+
CompressionType["LeanVec8x8"] = "LeanVec8x8";
|
|
61
|
+
})(CompressionType || (CompressionType = {}));
|
|
62
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAN,IAAY,SAMX;AAND,WAAY,SAAS;IACjB,wBAAW,CAAA;IACX,0BAAa,CAAA;IACb,gCAAmB,CAAA;IACnB,wBAAW,CAAA;IACX,8BAAiB,CAAA;AACrB,CAAC,EANW,SAAS,KAAT,SAAS,QAMpB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,WAGX;AAHD,WAAY,WAAW;IACnB,4BAAa,CAAA;IACb,4BAAa,CAAA;AACjB,CAAC,EAHW,WAAW,KAAX,WAAW,QAGtB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC5B,yCAAiB,CAAA;IACjB,iCAAS,CAAA;IACT,iCAAS,CAAA;AACb,CAAC,EAJW,oBAAoB,KAApB,oBAAoB,QAI/B;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACtB,uCAAqB,CAAA;IACrB,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,qCAAmB,CAAA;IACnB,+BAAa,CAAA;IACb,iCAAe,CAAA;AACnB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC5B,qCAAa,CAAA;IACb,qCAAa,CAAA;IACb,iDAAyB,CAAA;AAC7B,CAAC,EAJW,oBAAoB,KAApB,oBAAoB,QAI/B;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACvB,gCAAa,CAAA;IACb,oCAAiB,CAAA;IACjB,oCAAiB,CAAA;IACjB,gCAAa,CAAA;IACb,4CAAyB,CAAA;IACzB,4CAAyB,CAAA;AAC7B,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { RedisClientType, RedisClusterType } from 'redis';
|
|
2
|
+
import type { IndexSchema } from '../schema/schema.js';
|
|
3
|
+
/**
|
|
4
|
+
* Redis client type (standalone or cluster)
|
|
5
|
+
*/
|
|
6
|
+
export type RedisClient = RedisClientType | RedisClusterType;
|
|
7
|
+
/**
|
|
8
|
+
* Generate a ULID-like unique identifier.
|
|
9
|
+
* Format: timestamp (10 chars) + random (16 chars) = 26 chars total
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateUlid(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Options for writing data to Redis
|
|
14
|
+
*/
|
|
15
|
+
export interface WriteOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Field name to use as the document ID
|
|
18
|
+
*/
|
|
19
|
+
idField?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Explicit keys to use for the documents
|
|
22
|
+
*/
|
|
23
|
+
keys?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Time-to-live in seconds for the documents
|
|
26
|
+
*/
|
|
27
|
+
ttl?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Number of objects to write in a single Redis pipeline execution
|
|
30
|
+
* @default 200
|
|
31
|
+
*/
|
|
32
|
+
batchSize?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Preprocessing function to transform documents before storage.
|
|
35
|
+
*/
|
|
36
|
+
preprocess?: (doc: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
37
|
+
/**
|
|
38
|
+
* Whether to validate documents against schema
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
validateOnLoad?: boolean;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Base class for internal storage handling in Redis.
|
|
45
|
+
* Provides foundational methods for key management, data preprocessing,
|
|
46
|
+
* validation, and basic read/write operations.
|
|
47
|
+
*/
|
|
48
|
+
export declare abstract class BaseStorage {
|
|
49
|
+
protected readonly schema: IndexSchema;
|
|
50
|
+
protected readonly defaultBatchSize: number;
|
|
51
|
+
constructor(schema: IndexSchema);
|
|
52
|
+
/**
|
|
53
|
+
* Create a Redis key using prefix, separator, and ID.
|
|
54
|
+
* Normalizes the prefix by removing trailing separators to avoid double separators.
|
|
55
|
+
*/
|
|
56
|
+
protected createKey(id: string, prefix: string | string[], keySeparator: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Generate a key for a document.
|
|
59
|
+
* If idField is provided, extract the ID from the document.
|
|
60
|
+
* Otherwise, generate a ULID.
|
|
61
|
+
*/
|
|
62
|
+
protected createKeyForDocument(doc: Record<string, unknown>, idField: string | undefined, prefix: string | string[], keySeparator: string): string;
|
|
63
|
+
/**
|
|
64
|
+
* Preprocess a document using the provided async function.
|
|
65
|
+
*/
|
|
66
|
+
protected preprocess(doc: Record<string, unknown>, preprocessFn?: (doc: Record<string, unknown>) => Promise<Record<string, unknown>>): Promise<Record<string, unknown>>;
|
|
67
|
+
/**
|
|
68
|
+
* Validate a document against the schema
|
|
69
|
+
* @throws {SchemaValidationError} If validation fails
|
|
70
|
+
*/
|
|
71
|
+
protected validate(doc: Record<string, unknown>): Record<string, unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* Validate a single field value against its schema definition
|
|
74
|
+
* @throws {SchemaValidationError} If validation fails
|
|
75
|
+
*/
|
|
76
|
+
private validateField;
|
|
77
|
+
/**
|
|
78
|
+
* Validate a vector field value
|
|
79
|
+
* @throws {SchemaValidationError} If validation fails
|
|
80
|
+
*/
|
|
81
|
+
private validateVectorField;
|
|
82
|
+
/**
|
|
83
|
+
* Preprocess and validate documents before writing to Redis:
|
|
84
|
+
* 1. Generate Redis keys for each document (from provided keys or idField)
|
|
85
|
+
* 2. Apply preprocessing transformations (if provided)
|
|
86
|
+
* 3. Validate documents against schema (if validateOnLoad is true)
|
|
87
|
+
*
|
|
88
|
+
* @param data - Array of documents to preprocess and validate
|
|
89
|
+
* @param options - Write options containing idField, keys, preprocess, and validateOnLoad
|
|
90
|
+
* @returns Array of prepared documents with their Redis keys
|
|
91
|
+
* @throws {SchemaValidationError} If validation fails for any document (includes document index)
|
|
92
|
+
* @throws {Error} If key generation or preprocessing fails for any document
|
|
93
|
+
*/
|
|
94
|
+
protected preprocessAndValidateDocuments(data: Record<string, unknown>[], options: WriteOptions): Promise<Array<{
|
|
95
|
+
key: string;
|
|
96
|
+
doc: Record<string, unknown>;
|
|
97
|
+
}>>;
|
|
98
|
+
/**
|
|
99
|
+
* Write documents to Redis
|
|
100
|
+
*/
|
|
101
|
+
abstract write(client: RedisClient, data: Record<string, unknown>[], options?: WriteOptions): Promise<string[]>;
|
|
102
|
+
/**
|
|
103
|
+
* Read documents from Redis by keys
|
|
104
|
+
*/
|
|
105
|
+
abstract get(client: RedisClient, keys: string[], batchSize?: number): Promise<(Record<string, unknown> | null)[]>;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=base-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-storage.d.ts","sourceRoot":"","sources":["../../src/storage/base-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { FieldType } from '../schema/types.js';
|
|
2
|
+
import { SchemaValidationError } from '../errors.js';
|
|
3
|
+
import { randomBytes } from 'crypto';
|
|
4
|
+
import { vectorElementByteLength } from '../redis/utils.js';
|
|
5
|
+
/**
|
|
6
|
+
* Generate a ULID-like unique identifier.
|
|
7
|
+
* Format: timestamp (10 chars) + random (16 chars) = 26 chars total
|
|
8
|
+
*/
|
|
9
|
+
export function generateUlid() {
|
|
10
|
+
const timestamp = Date.now().toString(36).toUpperCase().padStart(10, '0');
|
|
11
|
+
const randomPart = randomBytes(10).toString('base64url').substring(0, 16).toUpperCase();
|
|
12
|
+
return timestamp + randomPart;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Base class for internal storage handling in Redis.
|
|
16
|
+
* Provides foundational methods for key management, data preprocessing,
|
|
17
|
+
* validation, and basic read/write operations.
|
|
18
|
+
*/
|
|
19
|
+
export class BaseStorage {
|
|
20
|
+
schema;
|
|
21
|
+
defaultBatchSize = 200;
|
|
22
|
+
constructor(schema) {
|
|
23
|
+
this.schema = schema;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a Redis key using prefix, separator, and ID.
|
|
27
|
+
* Normalizes the prefix by removing trailing separators to avoid double separators.
|
|
28
|
+
*/
|
|
29
|
+
createKey(id, prefix, keySeparator) {
|
|
30
|
+
// Handle array prefix - use first element
|
|
31
|
+
const prefixStr = Array.isArray(prefix) ? prefix[0] : prefix;
|
|
32
|
+
if (!prefixStr) {
|
|
33
|
+
return id;
|
|
34
|
+
}
|
|
35
|
+
// Normalize prefix by removing trailing separators
|
|
36
|
+
const normalizedPrefix = keySeparator
|
|
37
|
+
? prefixStr.replace(new RegExp(`${keySeparator}+$`), '')
|
|
38
|
+
: prefixStr;
|
|
39
|
+
if (!normalizedPrefix) {
|
|
40
|
+
return id;
|
|
41
|
+
}
|
|
42
|
+
return `${normalizedPrefix}${keySeparator}${id}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Generate a key for a document.
|
|
46
|
+
* If idField is provided, extract the ID from the document.
|
|
47
|
+
* Otherwise, generate a ULID.
|
|
48
|
+
*/
|
|
49
|
+
createKeyForDocument(doc, idField, prefix, keySeparator) {
|
|
50
|
+
let keyValue;
|
|
51
|
+
if (idField) {
|
|
52
|
+
if (!(idField in doc)) {
|
|
53
|
+
throw new SchemaValidationError(`Key field "${idField}" not found in document`);
|
|
54
|
+
}
|
|
55
|
+
keyValue = String(doc[idField]);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
keyValue = generateUlid();
|
|
59
|
+
}
|
|
60
|
+
return this.createKey(keyValue, prefix, keySeparator);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Preprocess a document using the provided async function.
|
|
64
|
+
*/
|
|
65
|
+
async preprocess(doc, preprocessFn) {
|
|
66
|
+
return preprocessFn ? await preprocessFn(doc) : doc;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Validate a document against the schema
|
|
70
|
+
* @throws {SchemaValidationError} If validation fails
|
|
71
|
+
*/
|
|
72
|
+
validate(doc) {
|
|
73
|
+
if (!this.schema || !this.schema.fields) {
|
|
74
|
+
return doc;
|
|
75
|
+
}
|
|
76
|
+
const fields = Object.values(this.schema.fields);
|
|
77
|
+
// Only validate the fields that are present in the document
|
|
78
|
+
for (const [fieldName, value] of Object.entries(doc)) {
|
|
79
|
+
// Find the field definition in the schema
|
|
80
|
+
const field = fields.find((f) => f.name === fieldName);
|
|
81
|
+
if (field && value !== null && value !== undefined) {
|
|
82
|
+
this.validateField(field, fieldName, value);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return doc;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validate a single field value against its schema definition
|
|
89
|
+
* @throws {SchemaValidationError} If validation fails
|
|
90
|
+
*/
|
|
91
|
+
validateField(field, fieldName, value) {
|
|
92
|
+
const fieldType = field.type;
|
|
93
|
+
switch (fieldType) {
|
|
94
|
+
case FieldType.NUMERIC:
|
|
95
|
+
if (typeof value !== 'number') {
|
|
96
|
+
throw new SchemaValidationError(`Field '${fieldName}' should be numeric but got: ${typeof value}`);
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
case FieldType.VECTOR:
|
|
100
|
+
this.validateVectorField(field, fieldName, value);
|
|
101
|
+
break;
|
|
102
|
+
case FieldType.TEXT:
|
|
103
|
+
case FieldType.TAG:
|
|
104
|
+
if (typeof value !== 'string') {
|
|
105
|
+
throw new SchemaValidationError(`Field '${fieldName}' should be string but got: ${typeof value}`);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
case FieldType.GEO:
|
|
109
|
+
// TODO: Implement geo validation
|
|
110
|
+
// Geo fields should be in format "longitude,latitude"
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Validate a vector field value
|
|
116
|
+
* @throws {SchemaValidationError} If validation fails
|
|
117
|
+
*/
|
|
118
|
+
validateVectorField(field, fieldName, value) {
|
|
119
|
+
// Check if value is an array or Buffer
|
|
120
|
+
if (!Array.isArray(value) && !Buffer.isBuffer(value)) {
|
|
121
|
+
throw new SchemaValidationError(`Field '${fieldName}' expects a vector (array or Buffer), but got ${typeof value}. ` +
|
|
122
|
+
`For vector fields, provide a list of numbers or bytes.`);
|
|
123
|
+
}
|
|
124
|
+
// Get dimensions from field attributes
|
|
125
|
+
const attrs = field.attrs;
|
|
126
|
+
const expectedDims = attrs?.dims || attrs?.dim;
|
|
127
|
+
if (expectedDims) {
|
|
128
|
+
const actualDims = Array.isArray(value)
|
|
129
|
+
? value.length
|
|
130
|
+
: value.byteLength / vectorElementByteLength(attrs.datatype);
|
|
131
|
+
if (actualDims !== expectedDims) {
|
|
132
|
+
throw new SchemaValidationError(`Vector field '${fieldName}' has incorrect dimensions. ` +
|
|
133
|
+
`Expected ${expectedDims} dimensions but got ${actualDims}.`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Validate array elements are numbers
|
|
137
|
+
if (Array.isArray(value)) {
|
|
138
|
+
for (let i = 0; i < value.length; i++) {
|
|
139
|
+
if (typeof value[i] !== 'number') {
|
|
140
|
+
throw new SchemaValidationError(`Vector field '${fieldName}' contains non-numeric value at index ${i}: ${typeof value[i]}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Preprocess and validate documents before writing to Redis:
|
|
147
|
+
* 1. Generate Redis keys for each document (from provided keys or idField)
|
|
148
|
+
* 2. Apply preprocessing transformations (if provided)
|
|
149
|
+
* 3. Validate documents against schema (if validateOnLoad is true)
|
|
150
|
+
*
|
|
151
|
+
* @param data - Array of documents to preprocess and validate
|
|
152
|
+
* @param options - Write options containing idField, keys, preprocess, and validateOnLoad
|
|
153
|
+
* @returns Array of prepared documents with their Redis keys
|
|
154
|
+
* @throws {SchemaValidationError} If validation fails for any document (includes document index)
|
|
155
|
+
* @throws {Error} If key generation or preprocessing fails for any document
|
|
156
|
+
*/
|
|
157
|
+
async preprocessAndValidateDocuments(data, options) {
|
|
158
|
+
const { idField, keys, preprocess, validateOnLoad = false } = options;
|
|
159
|
+
const prefix = this.schema.index.prefix;
|
|
160
|
+
const keySeparator = this.schema.index.keySeparator;
|
|
161
|
+
const preparedDocs = [];
|
|
162
|
+
for (let i = 0; i < data.length; i++) {
|
|
163
|
+
try {
|
|
164
|
+
// Generate key
|
|
165
|
+
const key = keys
|
|
166
|
+
? keys[i]
|
|
167
|
+
: this.createKeyForDocument(data[i], idField, prefix, keySeparator);
|
|
168
|
+
// Preprocess
|
|
169
|
+
let processedDoc = await this.preprocess(data[i], preprocess);
|
|
170
|
+
// Validate if enabled
|
|
171
|
+
if (validateOnLoad) {
|
|
172
|
+
processedDoc = this.validate(processedDoc);
|
|
173
|
+
}
|
|
174
|
+
preparedDocs.push({ key, doc: processedDoc });
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
if (error instanceof SchemaValidationError) {
|
|
178
|
+
// Re-throw validation errors with index context
|
|
179
|
+
throw new SchemaValidationError(error.message, i);
|
|
180
|
+
}
|
|
181
|
+
throw new SchemaValidationError(`Error processing document at index ${i}: ${error instanceof Error ? error.message : String(error)}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return preparedDocs;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=base-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-storage.js","sourceRoot":"","sources":["../../src/storage/base-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RedisClient, WriteOptions } from './base-storage.js';
|
|
2
|
+
import { BaseStorage } from './base-storage.js';
|
|
3
|
+
import type { IndexSchema } from '../schema/schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* Storage implementation for Redis HASH data type.
|
|
6
|
+
* Implements hash-specific logic for validation and read/write operations.
|
|
7
|
+
*/
|
|
8
|
+
export declare class HashStorage extends BaseStorage {
|
|
9
|
+
constructor(schema: IndexSchema);
|
|
10
|
+
/**
|
|
11
|
+
* Write documents to Redis as HASH entries using pipelining for performance.
|
|
12
|
+
*/
|
|
13
|
+
write(client: RedisClient, data: Record<string, unknown>[], options?: WriteOptions): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Encode vector fields as binary buffers; pass other fields through unchanged.
|
|
16
|
+
* Required because Redis HSET only accepts strings, numbers, or Buffers.
|
|
17
|
+
*/
|
|
18
|
+
private serializeHashDocument;
|
|
19
|
+
/**
|
|
20
|
+
* Convert a HASH document returned in Buffer mode into public API values.
|
|
21
|
+
* Non-vector fields preserve the existing string-based HASH behavior.
|
|
22
|
+
*/
|
|
23
|
+
private deserializeHashDocument;
|
|
24
|
+
/**
|
|
25
|
+
* Read documents from Redis by keys using pipelining.
|
|
26
|
+
*/
|
|
27
|
+
get(client: RedisClient, keys: string[], batchSize?: number): Promise<(Record<string, unknown> | null)[]>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=hash-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-storage.d.ts","sourceRoot":"","sources":["../../src/storage/hash-storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAMvD;;;GAGG;AACH,qBAAa,WAAY,SAAQ,WAAW;gBAC5B,MAAM,EAAE,WAAW;IAI/B;;OAEG;IACG,KAAK,CACP,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC;IAiDpB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAgB7B;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;IACG,GAAG,CACL,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,SAAwB,GAClC,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;CAqCjD"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { RESP_TYPES } from 'redis';
|
|
2
|
+
import { BaseStorage } from './base-storage.js';
|
|
3
|
+
import { FieldType } from '../schema/types.js';
|
|
4
|
+
import { SchemaValidationError } from '../errors.js';
|
|
5
|
+
import { decodeVectorBuffer, encodeVectorBuffer } from '../redis/utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* Storage implementation for Redis HASH data type.
|
|
8
|
+
* Implements hash-specific logic for validation and read/write operations.
|
|
9
|
+
*/
|
|
10
|
+
export class HashStorage extends BaseStorage {
|
|
11
|
+
constructor(schema) {
|
|
12
|
+
super(schema);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Write documents to Redis as HASH entries using pipelining for performance.
|
|
16
|
+
*/
|
|
17
|
+
async write(client, data, options = {}) {
|
|
18
|
+
const { keys, ttl, batchSize = this.defaultBatchSize } = options;
|
|
19
|
+
// Validate inputs
|
|
20
|
+
if (data.length === 0) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
if (keys && keys.length !== data.length) {
|
|
24
|
+
throw new SchemaValidationError('Length of keys does not match the length of data');
|
|
25
|
+
}
|
|
26
|
+
// Pass 1: Preprocess and validate all documents
|
|
27
|
+
const preparedDocs = await this.preprocessAndValidateDocuments(data, options);
|
|
28
|
+
// Pass 2: Write all valid documents in batches using pipeline
|
|
29
|
+
const loadedKeys = [];
|
|
30
|
+
let pipeline = client.multi();
|
|
31
|
+
let commandCount = 0;
|
|
32
|
+
for (let i = 0; i < preparedDocs.length; i++) {
|
|
33
|
+
const { key, doc } = preparedDocs[i];
|
|
34
|
+
// Convert public JS values to Redis HASH-compatible values
|
|
35
|
+
const processedDoc = this.serializeHashDocument(doc);
|
|
36
|
+
// Add HSET command to pipeline
|
|
37
|
+
pipeline.hSet(key, processedDoc);
|
|
38
|
+
commandCount++;
|
|
39
|
+
// Add EXPIRE command if TTL is provided
|
|
40
|
+
if (ttl) {
|
|
41
|
+
pipeline.expire(key, ttl);
|
|
42
|
+
commandCount++;
|
|
43
|
+
}
|
|
44
|
+
loadedKeys.push(key);
|
|
45
|
+
// Execute pipeline in batches
|
|
46
|
+
if (commandCount >= batchSize || i === preparedDocs.length - 1) {
|
|
47
|
+
await pipeline.execAsPipeline();
|
|
48
|
+
pipeline = client.multi();
|
|
49
|
+
commandCount = 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return loadedKeys;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Encode vector fields as binary buffers; pass other fields through unchanged.
|
|
56
|
+
* Required because Redis HSET only accepts strings, numbers, or Buffers.
|
|
57
|
+
*/
|
|
58
|
+
serializeHashDocument(doc) {
|
|
59
|
+
const result = {};
|
|
60
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
61
|
+
const field = this.schema.fields[key];
|
|
62
|
+
if (field?.type === FieldType.VECTOR && Array.isArray(value)) {
|
|
63
|
+
result[key] = encodeVectorBuffer(value, field.attrs.datatype);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
result[key] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert a HASH document returned in Buffer mode into public API values.
|
|
73
|
+
* Non-vector fields preserve the existing string-based HASH behavior.
|
|
74
|
+
*/
|
|
75
|
+
deserializeHashDocument(doc) {
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [fieldName, value] of Object.entries(doc)) {
|
|
78
|
+
const field = this.schema.fields[fieldName];
|
|
79
|
+
if (field?.type === FieldType.VECTOR) {
|
|
80
|
+
result[fieldName] = decodeVectorBuffer(value, field.attrs.datatype);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
result[fieldName] = value.toString();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Read documents from Redis by keys using pipelining.
|
|
90
|
+
*/
|
|
91
|
+
async get(client, keys, batchSize = this.defaultBatchSize) {
|
|
92
|
+
if (!keys || keys.length === 0) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const results = [];
|
|
96
|
+
const binaryClient = client.withTypeMapping({
|
|
97
|
+
[RESP_TYPES.BLOB_STRING]: Buffer,
|
|
98
|
+
});
|
|
99
|
+
// Process in batches
|
|
100
|
+
for (let i = 0; i < keys.length; i += batchSize) {
|
|
101
|
+
const batch = keys.slice(i, i + batchSize);
|
|
102
|
+
const pipeline = binaryClient.multi();
|
|
103
|
+
// Add HGETALL commands to pipeline
|
|
104
|
+
for (const key of batch) {
|
|
105
|
+
pipeline.hGetAll(key);
|
|
106
|
+
}
|
|
107
|
+
// Execute pipeline and get results
|
|
108
|
+
const batchResults = (await pipeline.execAsPipeline());
|
|
109
|
+
// Process batch results
|
|
110
|
+
for (const data of batchResults) {
|
|
111
|
+
if (data && Object.keys(data).length > 0) {
|
|
112
|
+
results.push(this.deserializeHashDocument(data));
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
results.push(null);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return results;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=hash-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-storage.js","sourceRoot":"","sources":["../../src/storage/hash-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAuC,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RedisClient, WriteOptions } from './base-storage.js';
|
|
2
|
+
import { BaseStorage } from './base-storage.js';
|
|
3
|
+
import type { IndexSchema } from '../schema/schema.js';
|
|
4
|
+
/**
|
|
5
|
+
* Storage implementation for Redis JSON data type.
|
|
6
|
+
* Implements JSON-specific logic for validation and read/write operations.
|
|
7
|
+
*/
|
|
8
|
+
export declare class JsonStorage extends BaseStorage {
|
|
9
|
+
constructor(schema: IndexSchema);
|
|
10
|
+
/**
|
|
11
|
+
* Write documents to Redis as JSON entries using pipelining for performance.
|
|
12
|
+
*/
|
|
13
|
+
write(client: RedisClient, data: Record<string, unknown>[], options?: WriteOptions): Promise<string[]>;
|
|
14
|
+
/**
|
|
15
|
+
* Read documents from Redis by keys using pipelining.
|
|
16
|
+
*/
|
|
17
|
+
get(client: RedisClient, keys: string[], batchSize?: number): Promise<(Record<string, unknown> | null)[]>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=json-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-storage.d.ts","sourceRoot":"","sources":["../../src/storage/json-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD;;;GAGG;AACH,qBAAa,WAAY,SAAQ,WAAW;gBAC5B,MAAM,EAAE,WAAW;IAI/B;;OAEG;IACG,KAAK,CACP,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,GAAE,YAAiB,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC;IA+CpB;;OAEG;IACG,GAAG,CACL,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EAAE,EACd,SAAS,SAAwB,GAClC,OAAO,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;CAmCjD"}
|