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.
Files changed (87) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +212 -0
  3. package/dist/errors.d.ts +50 -0
  4. package/dist/errors.d.ts.map +1 -0
  5. package/dist/errors.js +87 -0
  6. package/dist/errors.js.map +1 -0
  7. package/dist/index.d.ts +21 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +25 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/indexes/search-index.d.ts +368 -0
  12. package/dist/indexes/search-index.d.ts.map +1 -0
  13. package/dist/indexes/search-index.js +475 -0
  14. package/dist/indexes/search-index.js.map +1 -0
  15. package/dist/query/base.d.ts +51 -0
  16. package/dist/query/base.d.ts.map +1 -0
  17. package/dist/query/base.js +6 -0
  18. package/dist/query/base.js.map +1 -0
  19. package/dist/query/index.d.ts +7 -0
  20. package/dist/query/index.d.ts.map +1 -0
  21. package/dist/query/index.js +7 -0
  22. package/dist/query/index.js.map +1 -0
  23. package/dist/query/vector.d.ts +199 -0
  24. package/dist/query/vector.d.ts.map +1 -0
  25. package/dist/query/vector.js +198 -0
  26. package/dist/query/vector.js.map +1 -0
  27. package/dist/redis/index-info-parser.d.ts +25 -0
  28. package/dist/redis/index-info-parser.d.ts.map +1 -0
  29. package/dist/redis/index-info-parser.js +301 -0
  30. package/dist/redis/index-info-parser.js.map +1 -0
  31. package/dist/redis/schema-types.d.ts +81 -0
  32. package/dist/redis/schema-types.d.ts.map +1 -0
  33. package/dist/redis/schema-types.js +18 -0
  34. package/dist/redis/schema-types.js.map +1 -0
  35. package/dist/redis/utils.d.ts +7 -0
  36. package/dist/redis/utils.d.ts.map +1 -0
  37. package/dist/redis/utils.js +221 -0
  38. package/dist/redis/utils.js.map +1 -0
  39. package/dist/schema/fields.d.ts +163 -0
  40. package/dist/schema/fields.d.ts.map +1 -0
  41. package/dist/schema/fields.js +304 -0
  42. package/dist/schema/fields.js.map +1 -0
  43. package/dist/schema/index.d.ts +8 -0
  44. package/dist/schema/index.d.ts.map +1 -0
  45. package/dist/schema/index.js +8 -0
  46. package/dist/schema/index.js.map +1 -0
  47. package/dist/schema/schema.d.ts +247 -0
  48. package/dist/schema/schema.d.ts.map +1 -0
  49. package/dist/schema/schema.js +403 -0
  50. package/dist/schema/schema.js.map +1 -0
  51. package/dist/schema/types.d.ts +56 -0
  52. package/dist/schema/types.d.ts.map +1 -0
  53. package/dist/schema/types.js +62 -0
  54. package/dist/schema/types.js.map +1 -0
  55. package/dist/storage/base-storage.d.ts +107 -0
  56. package/dist/storage/base-storage.d.ts.map +1 -0
  57. package/dist/storage/base-storage.js +187 -0
  58. package/dist/storage/base-storage.js.map +1 -0
  59. package/dist/storage/hash-storage.d.ts +29 -0
  60. package/dist/storage/hash-storage.d.ts.map +1 -0
  61. package/dist/storage/hash-storage.js +122 -0
  62. package/dist/storage/hash-storage.js.map +1 -0
  63. package/dist/storage/index.d.ts +4 -0
  64. package/dist/storage/index.d.ts.map +1 -0
  65. package/dist/storage/index.js +4 -0
  66. package/dist/storage/index.js.map +1 -0
  67. package/dist/storage/json-storage.d.ts +19 -0
  68. package/dist/storage/json-storage.d.ts.map +1 -0
  69. package/dist/storage/json-storage.js +81 -0
  70. package/dist/storage/json-storage.js.map +1 -0
  71. package/dist/utils/distance.d.ts +92 -0
  72. package/dist/utils/distance.d.ts.map +1 -0
  73. package/dist/utils/distance.js +98 -0
  74. package/dist/utils/distance.js.map +1 -0
  75. package/dist/vectorizers/base-vectorizer.d.ts +88 -0
  76. package/dist/vectorizers/base-vectorizer.d.ts.map +1 -0
  77. package/dist/vectorizers/base-vectorizer.js +32 -0
  78. package/dist/vectorizers/base-vectorizer.js.map +1 -0
  79. package/dist/vectorizers/huggingface-vectorizer.d.ts +103 -0
  80. package/dist/vectorizers/huggingface-vectorizer.d.ts.map +1 -0
  81. package/dist/vectorizers/huggingface-vectorizer.js +142 -0
  82. package/dist/vectorizers/huggingface-vectorizer.js.map +1 -0
  83. package/dist/vectorizers/index.d.ts +10 -0
  84. package/dist/vectorizers/index.d.ts.map +1 -0
  85. package/dist/vectorizers/index.js +10 -0
  86. package/dist/vectorizers/index.js.map +1 -0
  87. 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,4 @@
1
+ export { BaseStorage, generateUlid, type RedisClient, type WriteOptions } from './base-storage.js';
2
+ export { HashStorage } from './hash-storage.js';
3
+ export { JsonStorage } from './json-storage.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -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,4 @@
1
+ export { BaseStorage, generateUlid } from './base-storage.js';
2
+ export { HashStorage } from './hash-storage.js';
3
+ export { JsonStorage } from './json-storage.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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"}