diff --git a/packages/search/lib/commands/CREATE.spec.ts b/packages/search/lib/commands/CREATE.spec.ts index 1a0a4f244b..021d8fa429 100644 --- a/packages/search/lib/commands/CREATE.spec.ts +++ b/packages/search/lib/commands/CREATE.spec.ts @@ -1,418 +1,415 @@ import { strict as assert } from 'assert'; import testUtils, { GLOBAL } from '../test-utils'; -import { transformArguments } from './CREATE'; -import { SchemaFieldTypes, SchemaTextFieldPhonetics, RedisSearchLanguages, VectorAlgorithms } from '.'; +import CREATE, { SCHEMA_FIELD_TYPE, SCHEMA_TEXT_FIELD_PHONETIC, SCHEMA_VECTOR_FIELD_ALGORITHM, REDISEARCH_LANGUAGE } from './CREATE'; -describe('CREATE', () => { - describe('transformArguments', () => { - it('simple', () => { - assert.deepEqual( - transformArguments('index', {}), - ['FT.CREATE', 'index', 'SCHEMA'] - ); - }); - - describe('with fields', () => { - describe('TEXT', () => { - it('without options', () => { - assert.deepEqual( - transformArguments('index', { - field: SchemaFieldTypes.TEXT - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT'] - ); - }); - - it('with NOSTEM', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - NOSTEM: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOSTEM'] - ); - }); - - it('with WEIGHT', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - WEIGHT: 1 - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WEIGHT', '1'] - ); - }); - - it('with PHONETIC', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - PHONETIC: SchemaTextFieldPhonetics.DM_EN - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'PHONETIC', SchemaTextFieldPhonetics.DM_EN] - ); - }); - - it('with WITHSUFFIXTRIE', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - WITHSUFFIXTRIE: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WITHSUFFIXTRIE'] - ); - }); - }); - - it('NUMERIC', () => { - assert.deepEqual( - transformArguments('index', { - field: SchemaFieldTypes.NUMERIC - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'NUMERIC'] - ); - }); - - it('GEO', () => { - assert.deepEqual( - transformArguments('index', { - field: SchemaFieldTypes.GEO - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEO'] - ); - }); - - describe('TAG', () => { - describe('without options', () => { - it('SchemaFieldTypes.TAG', () => { - assert.deepEqual( - transformArguments('index', { - field: SchemaFieldTypes.TAG - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG'] - ); - }); - - it('{ type: SchemaFieldTypes.TAG }', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TAG - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG'] - ); - }); - }); - - it('with SEPARATOR', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TAG, - SEPARATOR: 'separator' - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'SEPARATOR', 'separator'] - ); - }); - - it('with CASESENSITIVE', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TAG, - CASESENSITIVE: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'CASESENSITIVE'] - ); - }); - - it('with WITHSUFFIXTRIE', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TAG, - WITHSUFFIXTRIE: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'WITHSUFFIXTRIE'] - ); - }); - }); - - describe('VECTOR', () => { - it('Flat algorithm', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.VECTOR, - ALGORITHM: VectorAlgorithms.FLAT, - TYPE: 'FLOAT32', - DIM: 2, - DISTANCE_METRIC: 'L2', - INITIAL_CAP: 1000000, - BLOCK_SIZE: 1000 - } - }), - [ - 'FT.CREATE', 'index', 'SCHEMA', 'field', 'VECTOR', 'FLAT', '10', 'TYPE', - 'FLOAT32', 'DIM', '2', 'DISTANCE_METRIC', 'L2', 'INITIAL_CAP', '1000000', - 'BLOCK_SIZE', '1000' - ] - ); - }); - - it('HNSW algorithm', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.VECTOR, - ALGORITHM: VectorAlgorithms.HNSW, - TYPE: 'FLOAT32', - DIM: 2, - DISTANCE_METRIC: 'L2', - INITIAL_CAP: 1000000, - M: 40, - EF_CONSTRUCTION: 250, - EF_RUNTIME: 20 - } - }), - [ - 'FT.CREATE', 'index', 'SCHEMA', 'field', 'VECTOR', 'HNSW', '14', 'TYPE', - 'FLOAT32', 'DIM', '2', 'DISTANCE_METRIC', 'L2', 'INITIAL_CAP', '1000000', - 'M', '40', 'EF_CONSTRUCTION', '250', 'EF_RUNTIME', '20' - ] - ); - }); - }); - - describe('with generic options', () => { - it('with AS', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - AS: 'as' - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'AS', 'as', 'TEXT'] - ); - }); - - describe('with SORTABLE', () => { - it('true', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - SORTABLE: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'SORTABLE'] - ); - }); - - it('UNF', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - SORTABLE: 'UNF' - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'SORTABLE', 'UNF'] - ); - }); - }); - - it('with NOINDEX', () => { - assert.deepEqual( - transformArguments('index', { - field: { - type: SchemaFieldTypes.TEXT, - NOINDEX: true - } - }), - ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOINDEX'] - ); - }); - }); - }); - - it('with ON', () => { - assert.deepEqual( - transformArguments('index', {}, { - ON: 'HASH' - }), - ['FT.CREATE', 'index', 'ON', 'HASH', 'SCHEMA'] - ); - }); - - describe('with PREFIX', () => { - it('string', () => { - assert.deepEqual( - transformArguments('index', {}, { - PREFIX: 'prefix' - }), - ['FT.CREATE', 'index', 'PREFIX', '1', 'prefix', 'SCHEMA'] - ); - }); - - it('Array', () => { - assert.deepEqual( - transformArguments('index', {}, { - PREFIX: ['1', '2'] - }), - ['FT.CREATE', 'index', 'PREFIX', '2', '1', '2', 'SCHEMA'] - ); - }); - }); - - it('with FILTER', () => { - assert.deepEqual( - transformArguments('index', {}, { - FILTER: '@field != ""' - }), - ['FT.CREATE', 'index', 'FILTER', '@field != ""', 'SCHEMA'] - ); - }); - - it('with LANGUAGE', () => { - assert.deepEqual( - transformArguments('index', {}, { - LANGUAGE: RedisSearchLanguages.ARABIC - }), - ['FT.CREATE', 'index', 'LANGUAGE', RedisSearchLanguages.ARABIC, 'SCHEMA'] - ); - }); - - it('with LANGUAGE_FIELD', () => { - assert.deepEqual( - transformArguments('index', {}, { - LANGUAGE_FIELD: '@field' - }), - ['FT.CREATE', 'index', 'LANGUAGE_FIELD', '@field', 'SCHEMA'] - ); - }); - - it('with SCORE', () => { - assert.deepEqual( - transformArguments('index', {}, { - SCORE: 1 - }), - ['FT.CREATE', 'index', 'SCORE', '1', 'SCHEMA'] - ); - }); - - it('with SCORE_FIELD', () => { - assert.deepEqual( - transformArguments('index', {}, { - SCORE_FIELD: '@field' - }), - ['FT.CREATE', 'index', 'SCORE_FIELD', '@field', 'SCHEMA'] - ); - }); - - it('with MAXTEXTFIELDS', () => { - assert.deepEqual( - transformArguments('index', {}, { - MAXTEXTFIELDS: true - }), - ['FT.CREATE', 'index', 'MAXTEXTFIELDS', 'SCHEMA'] - ); - }); - - it('with TEMPORARY', () => { - assert.deepEqual( - transformArguments('index', {}, { - TEMPORARY: 1 - }), - ['FT.CREATE', 'index', 'TEMPORARY', '1', 'SCHEMA'] - ); - }); - - it('with NOOFFSETS', () => { - assert.deepEqual( - transformArguments('index', {}, { - NOOFFSETS: true - }), - ['FT.CREATE', 'index', 'NOOFFSETS', 'SCHEMA'] - ); - }); - - it('with NOHL', () => { - assert.deepEqual( - transformArguments('index', {}, { - NOHL: true - }), - ['FT.CREATE', 'index', 'NOHL', 'SCHEMA'] - ); - }); - - it('with NOFIELDS', () => { - assert.deepEqual( - transformArguments('index', {}, { - NOFIELDS: true - }), - ['FT.CREATE', 'index', 'NOFIELDS', 'SCHEMA'] - ); - }); - - it('with NOFREQS', () => { - assert.deepEqual( - transformArguments('index', {}, { - NOFREQS: true - }), - ['FT.CREATE', 'index', 'NOFREQS', 'SCHEMA'] - ); - }); - - it('with SKIPINITIALSCAN', () => { - assert.deepEqual( - transformArguments('index', {}, { - SKIPINITIALSCAN: true - }), - ['FT.CREATE', 'index', 'SKIPINITIALSCAN', 'SCHEMA'] - ); - }); - - describe('with STOPWORDS', () => { - it('string', () => { - assert.deepEqual( - transformArguments('index', {}, { - STOPWORDS: 'stopword' - }), - ['FT.CREATE', 'index', 'STOPWORDS', '1', 'stopword', 'SCHEMA'] - ); - }); - - it('Array', () => { - assert.deepEqual( - transformArguments('index', {}, { - STOPWORDS: ['1', '2'] - }), - ['FT.CREATE', 'index', 'STOPWORDS', '2', '1', '2', 'SCHEMA'] - ); - }); - }); +describe.only('FT.CREATE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}), + ['FT.CREATE', 'index', 'SCHEMA'] + ); }); - testUtils.testWithClient('client.ft.create', async client => { - assert.equal( - await client.ft.create('index', { - field: SchemaFieldTypes.TEXT + describe('with fields', () => { + describe('TEXT', () => { + it('without options', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: SCHEMA_FIELD_TYPE.TEXT }), - 'OK' + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT'] + ); + }); + + it('with NOSTEM', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + NOSTEM: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOSTEM'] + ); + }); + + it('with WEIGHT', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + WEIGHT: 1 + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WEIGHT', '1'] + ); + }); + + it('with PHONETIC', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + PHONETIC: SCHEMA_TEXT_FIELD_PHONETIC.DM_EN + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'PHONETIC', SCHEMA_TEXT_FIELD_PHONETIC.DM_EN] + ); + }); + + it('with WITHSUFFIXTRIE', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + WITHSUFFIXTRIE: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WITHSUFFIXTRIE'] + ); + }); + }); + + it('NUMERIC', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: SCHEMA_FIELD_TYPE.NUMERIC + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'NUMERIC'] ); - }, GLOBAL.SERVERS.OPEN); + }); + + it('GEO', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: SCHEMA_FIELD_TYPE.GEO + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEO'] + ); + }); + + describe('TAG', () => { + describe('without options', () => { + it('SCHEMA_FIELD_TYPE.TAG', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: SCHEMA_FIELD_TYPE.TAG + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG'] + ); + }); + + it('{ type: SCHEMA_FIELD_TYPE.TAG }', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TAG + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG'] + ); + }); + }); + + it('with SEPARATOR', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TAG, + SEPARATOR: 'separator' + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'SEPARATOR', 'separator'] + ); + }); + + it('with CASESENSITIVE', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TAG, + CASESENSITIVE: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'CASESENSITIVE'] + ); + }); + + it('with WITHSUFFIXTRIE', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TAG, + WITHSUFFIXTRIE: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'WITHSUFFIXTRIE'] + ); + }); + }); + + describe('VECTOR', () => { + it('Flat algorithm', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.VECTOR, + ALGORITHM: SCHEMA_VECTOR_FIELD_ALGORITHM.FLAT, + TYPE: 'FLOAT32', + DIM: 2, + DISTANCE_METRIC: 'L2', + INITIAL_CAP: 1000000, + BLOCK_SIZE: 1000 + } + }), + [ + 'FT.CREATE', 'index', 'SCHEMA', 'field', 'VECTOR', 'FLAT', '10', 'TYPE', + 'FLOAT32', 'DIM', '2', 'DISTANCE_METRIC', 'L2', 'INITIAL_CAP', '1000000', + 'BLOCK_SIZE', '1000' + ] + ); + }); + + it('HNSW algorithm', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.VECTOR, + ALGORITHM: SCHEMA_VECTOR_FIELD_ALGORITHM.HNSW, + TYPE: 'FLOAT32', + DIM: 2, + DISTANCE_METRIC: 'L2', + INITIAL_CAP: 1000000, + M: 40, + EF_CONSTRUCTION: 250, + EF_RUNTIME: 20 + } + }), + [ + 'FT.CREATE', 'index', 'SCHEMA', 'field', 'VECTOR', 'HNSW', '14', 'TYPE', + 'FLOAT32', 'DIM', '2', 'DISTANCE_METRIC', 'L2', 'INITIAL_CAP', '1000000', + 'M', '40', 'EF_CONSTRUCTION', '250', 'EF_RUNTIME', '20' + ] + ); + }); + }); + + it('with AS', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + AS: 'as' + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'AS', 'as', 'TEXT'] + ); + }); + + describe('with SORTABLE', () => { + it('true', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + SORTABLE: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'SORTABLE'] + ); + }); + + it('UNF', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + SORTABLE: 'UNF' + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'SORTABLE', 'UNF'] + ); + }); + }); + + it('with NOINDEX', () => { + assert.deepEqual( + CREATE.transformArguments('index', { + field: { + type: SCHEMA_FIELD_TYPE.TEXT, + NOINDEX: true + } + }), + ['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOINDEX'] + ); + }); + }); + + it('with ON', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + ON: 'HASH' + }), + ['FT.CREATE', 'index', 'ON', 'HASH', 'SCHEMA'] + ); + }); + + describe('with PREFIX', () => { + it('string', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + PREFIX: 'prefix' + }), + ['FT.CREATE', 'index', 'PREFIX', '1', 'prefix', 'SCHEMA'] + ); + }); + + it('Array', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + PREFIX: ['1', '2'] + }), + ['FT.CREATE', 'index', 'PREFIX', '2', '1', '2', 'SCHEMA'] + ); + }); + }); + + it('with FILTER', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + FILTER: '@field != ""' + }), + ['FT.CREATE', 'index', 'FILTER', '@field != ""', 'SCHEMA'] + ); + }); + + it('with LANGUAGE', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + LANGUAGE: REDISEARCH_LANGUAGE.ARABIC + }), + ['FT.CREATE', 'index', 'LANGUAGE', REDISEARCH_LANGUAGE.ARABIC, 'SCHEMA'] + ); + }); + + it('with LANGUAGE_FIELD', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + LANGUAGE_FIELD: '@field' + }), + ['FT.CREATE', 'index', 'LANGUAGE_FIELD', '@field', 'SCHEMA'] + ); + }); + + it('with SCORE', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + SCORE: 1 + }), + ['FT.CREATE', 'index', 'SCORE', '1', 'SCHEMA'] + ); + }); + + it('with SCORE_FIELD', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + SCORE_FIELD: '@field' + }), + ['FT.CREATE', 'index', 'SCORE_FIELD', '@field', 'SCHEMA'] + ); + }); + + it('with MAXTEXTFIELDS', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + MAXTEXTFIELDS: true + }), + ['FT.CREATE', 'index', 'MAXTEXTFIELDS', 'SCHEMA'] + ); + }); + + it('with TEMPORARY', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + TEMPORARY: 1 + }), + ['FT.CREATE', 'index', 'TEMPORARY', '1', 'SCHEMA'] + ); + }); + + it('with NOOFFSETS', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + NOOFFSETS: true + }), + ['FT.CREATE', 'index', 'NOOFFSETS', 'SCHEMA'] + ); + }); + + it('with NOHL', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + NOHL: true + }), + ['FT.CREATE', 'index', 'NOHL', 'SCHEMA'] + ); + }); + + it('with NOFIELDS', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + NOFIELDS: true + }), + ['FT.CREATE', 'index', 'NOFIELDS', 'SCHEMA'] + ); + }); + + it('with NOFREQS', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + NOFREQS: true + }), + ['FT.CREATE', 'index', 'NOFREQS', 'SCHEMA'] + ); + }); + + it('with SKIPINITIALSCAN', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + SKIPINITIALSCAN: true + }), + ['FT.CREATE', 'index', 'SKIPINITIALSCAN', 'SCHEMA'] + ); + }); + + describe('with STOPWORDS', () => { + it('string', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + STOPWORDS: 'stopword' + }), + ['FT.CREATE', 'index', 'STOPWORDS', '1', 'stopword', 'SCHEMA'] + ); + }); + + it('Array', () => { + assert.deepEqual( + CREATE.transformArguments('index', {}, { + STOPWORDS: ['1', '2'] + }), + ['FT.CREATE', 'index', 'STOPWORDS', '2', '1', '2', 'SCHEMA'] + ); + }); + }); + }); + + testUtils.testWithClient('client.ft.create', async client => { + assert.equal( + await client.ft.create('index', { + field: SCHEMA_FIELD_TYPE.TEXT + }), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/search/lib/commands/CREATE.ts b/packages/search/lib/commands/CREATE.ts index 32440ede38..bc7603fe70 100644 --- a/packages/search/lib/commands/CREATE.ts +++ b/packages/search/lib/commands/CREATE.ts @@ -1,52 +1,291 @@ -import { pushOptionalVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers'; -import { RedisSearchLanguages, PropertyName, RediSearchSchema, pushSchema } from '.'; +import { RedisArgument, SimpleStringReply, Command, CommandArguments } from '@redis/client/dist/lib/RESP/types'; +import { RedisVariadicArgument, pushOptionalVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers'; +import { PropertyName } from '.'; -interface CreateOptions { - ON?: 'HASH' | 'JSON'; - PREFIX?: string | Array; - FILTER?: string; - LANGUAGE?: RedisSearchLanguages; - LANGUAGE_FIELD?: PropertyName; - SCORE?: number; - SCORE_FIELD?: PropertyName; - // PAYLOAD_FIELD?: string; - MAXTEXTFIELDS?: true; - TEMPORARY?: number; - NOOFFSETS?: true; - NOHL?: true; - NOFIELDS?: true; - NOFREQS?: true; - SKIPINITIALSCAN?: true; - STOPWORDS?: string | Array; +export const SCHEMA_FIELD_TYPE = { + TEXT: 'TEXT', + NUMERIC: 'NUMERIC', + GEO: 'GEO', + TAG: 'TAG', + VECTOR: 'VECTOR' +} as const; + +export type SchemaFieldType = typeof SCHEMA_FIELD_TYPE[keyof typeof SCHEMA_FIELD_TYPE]; + +type SchemaField< + T extends SchemaFieldType, + E = Record +> = T | ({ + type: T; + AS?: RedisArgument; +} & E); + +type SchemaCommonField< + T extends SchemaFieldType, + E = Record +> = SchemaField< + T, + ({ + SORTABLE?: boolean | 'UNF'; + NOINDEX?: boolean; + } & E) +>; + +export const SCHEMA_TEXT_FIELD_PHONETIC = { + DM_EN: 'dm:en', + DM_FR: 'dm:fr', + FM_PT: 'dm:pt', + DM_ES: 'dm:es' +} as const; + +export type SchemaTextFieldPhonetic = typeof SCHEMA_TEXT_FIELD_PHONETIC[keyof typeof SCHEMA_TEXT_FIELD_PHONETIC]; + +type SchemaTextField = SchemaCommonField; + +type SchemaNumericField = SchemaCommonField; + +type SchemaGeoField = SchemaCommonField; + +type SchemaTagField = SchemaCommonField; + +export const SCHEMA_VECTOR_FIELD_ALGORITHM = { + FLAT: 'FLAT', + HNSW: 'HNSW' +} as const; + +export type SchemaVectorFieldAlgorithm = typeof SCHEMA_VECTOR_FIELD_ALGORITHM[keyof typeof SCHEMA_VECTOR_FIELD_ALGORITHM]; + +type SchemaVectorField< + T extends SchemaVectorFieldAlgorithm, + A extends Record +> = SchemaField; + +type SchemaFlatVectorField = SchemaVectorField; + +type SchemaHNSWVectorField = SchemaVectorField; + +export interface RediSearchSchema { + [field: string]:( + SchemaTextField | + SchemaNumericField | + SchemaGeoField | + SchemaTagField | + SchemaFlatVectorField | + SchemaHNSWVectorField + ); } -export function transformArguments(index: string, schema: RediSearchSchema, options?: CreateOptions): Array { +export function pushSchema(args: CommandArguments, schema: RediSearchSchema) { + for (const [field, fieldOptions] of Object.entries(schema)) { + args.push(field); + + if (typeof fieldOptions === 'string') { + args.push(fieldOptions); + continue; + } + + if (fieldOptions.AS) { + args.push('AS', fieldOptions.AS); + } + + args.push(fieldOptions.type); + + switch (fieldOptions.type) { + case SCHEMA_FIELD_TYPE.TEXT: + if (fieldOptions.NOSTEM) { + args.push('NOSTEM'); + } + + if (fieldOptions.WEIGHT) { + args.push('WEIGHT', fieldOptions.WEIGHT.toString()); + } + + if (fieldOptions.PHONETIC) { + args.push('PHONETIC', fieldOptions.PHONETIC); + } + + if (fieldOptions.WITHSUFFIXTRIE) { + args.push('WITHSUFFIXTRIE'); + } + + break; + + // case SchemaFieldTypes.NUMERIC: + // case SchemaFieldTypes.GEO: + // break; + + case SCHEMA_FIELD_TYPE.TAG: + if (fieldOptions.SEPARATOR) { + args.push('SEPARATOR', fieldOptions.SEPARATOR); + } + + if (fieldOptions.CASESENSITIVE) { + args.push('CASESENSITIVE'); + } + + if (fieldOptions.WITHSUFFIXTRIE) { + args.push('WITHSUFFIXTRIE'); + } + + break; + + case SCHEMA_FIELD_TYPE.VECTOR: + args.push(fieldOptions.ALGORITHM); + + const lengthIndex = args.push('') - 1; + + args.push( + 'TYPE', fieldOptions.TYPE, + 'DIM', fieldOptions.DIM.toString(), + 'DISTANCE_METRIC', fieldOptions.DISTANCE_METRIC + ); + + if (fieldOptions.INITIAL_CAP) { + args.push('INITIAL_CAP', fieldOptions.INITIAL_CAP.toString()); + } + + switch (fieldOptions.ALGORITHM) { + case SCHEMA_VECTOR_FIELD_ALGORITHM.FLAT: + if (fieldOptions.BLOCK_SIZE) { + args.push('BLOCK_SIZE', fieldOptions.BLOCK_SIZE.toString()); + } + + break; + + case SCHEMA_VECTOR_FIELD_ALGORITHM.HNSW: + if (fieldOptions.M) { + args.push('M', fieldOptions.M.toString()); + } + + if (fieldOptions.EF_CONSTRUCTION) { + args.push('EF_CONSTRUCTION', fieldOptions.EF_CONSTRUCTION.toString()); + } + + if (fieldOptions.EF_RUNTIME) { + args.push('EF_RUNTIME', fieldOptions.EF_RUNTIME.toString()); + } + + break; + } + args[lengthIndex] = (args.length - lengthIndex - 1).toString(); + + continue; // vector fields do not contain SORTABLE and NOINDEX options + } + + if (fieldOptions.SORTABLE) { + args.push('SORTABLE'); + + if (fieldOptions.SORTABLE === 'UNF') { + args.push('UNF'); + } + } + + if (fieldOptions.NOINDEX) { + args.push('NOINDEX'); + } + } +} + +export const REDISEARCH_LANGUAGE = { + ARABIC: 'Arabic', + BASQUE: 'Basque', + CATALANA: 'Catalan', + DANISH: 'Danish', + DUTCH: 'Dutch', + ENGLISH: 'English', + FINNISH: 'Finnish', + FRENCH: 'French', + GERMAN: 'German', + GREEK: 'Greek', + HUNGARIAN: 'Hungarian', + INDONESAIN: 'Indonesian', + IRISH: 'Irish', + ITALIAN: 'Italian', + LITHUANIAN: 'Lithuanian', + NEPALI: 'Nepali', + NORWEIGAN: 'Norwegian', + PORTUGUESE: 'Portuguese', + ROMANIAN: 'Romanian', + RUSSIAN: 'Russian', + SPANISH: 'Spanish', + SWEDISH: 'Swedish', + TAMIL: 'Tamil', + TURKISH: 'Turkish', + CHINESE: 'Chinese' +} as const; + +export type RediSearchLanguage = typeof REDISEARCH_LANGUAGE[keyof typeof REDISEARCH_LANGUAGE]; + +export interface CreateOptions { + ON?: 'HASH' | 'JSON'; + PREFIX?: RedisVariadicArgument; + FILTER?: RedisArgument; + LANGUAGE?: RediSearchLanguage; + LANGUAGE_FIELD?: PropertyName; + SCORE?: number; + SCORE_FIELD?: PropertyName; + // PAYLOAD_FIELD?: string; + MAXTEXTFIELDS?: boolean; + TEMPORARY?: number; + NOOFFSETS?: boolean; + NOHL?: boolean; + NOFIELDS?: boolean; + NOFREQS?: boolean; + SKIPINITIALSCAN?: boolean; + STOPWORDS?: RedisVariadicArgument; +} + +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: false, + transformArguments(index: RedisArgument, schema: RediSearchSchema, options?: CreateOptions) { const args = ['FT.CREATE', index]; if (options?.ON) { - args.push('ON', options.ON); + args.push('ON', options.ON); } pushOptionalVariadicArgument(args, 'PREFIX', options?.PREFIX); if (options?.FILTER) { - args.push('FILTER', options.FILTER); + args.push('FILTER', options.FILTER); } if (options?.LANGUAGE) { - args.push('LANGUAGE', options.LANGUAGE); + args.push('LANGUAGE', options.LANGUAGE); } if (options?.LANGUAGE_FIELD) { - args.push('LANGUAGE_FIELD', options.LANGUAGE_FIELD); + args.push('LANGUAGE_FIELD', options.LANGUAGE_FIELD); } if (options?.SCORE) { - args.push('SCORE', options.SCORE.toString()); + args.push('SCORE', options.SCORE.toString()); } if (options?.SCORE_FIELD) { - args.push('SCORE_FIELD', options.SCORE_FIELD); + args.push('SCORE_FIELD', options.SCORE_FIELD); } // if (options?.PAYLOAD_FIELD) { @@ -54,31 +293,31 @@ export function transformArguments(index: string, schema: RediSearchSchema, opti // } if (options?.MAXTEXTFIELDS) { - args.push('MAXTEXTFIELDS'); + args.push('MAXTEXTFIELDS'); } if (options?.TEMPORARY) { - args.push('TEMPORARY', options.TEMPORARY.toString()); + args.push('TEMPORARY', options.TEMPORARY.toString()); } if (options?.NOOFFSETS) { - args.push('NOOFFSETS'); + args.push('NOOFFSETS'); } if (options?.NOHL) { - args.push('NOHL'); + args.push('NOHL'); } if (options?.NOFIELDS) { - args.push('NOFIELDS'); + args.push('NOFIELDS'); } if (options?.NOFREQS) { - args.push('NOFREQS'); + args.push('NOFREQS'); } if (options?.SKIPINITIALSCAN) { - args.push('SKIPINITIALSCAN'); + args.push('SKIPINITIALSCAN'); } pushOptionalVariadicArgument(args, 'STOPWORDS', options?.STOPWORDS); @@ -86,6 +325,6 @@ export function transformArguments(index: string, schema: RediSearchSchema, opti pushSchema(args, schema); return args; -} - -export declare function transformReply(): 'OK'; + }, + transformReply: undefined as unknown as () => SimpleStringReply<'OK'> +} as const satisfies Command; diff --git a/packages/search/lib/commands/index.ts b/packages/search/lib/commands/index.ts index 82808605de..17fb67e047 100644 --- a/packages/search/lib/commands/index.ts +++ b/packages/search/lib/commands/index.ts @@ -1,641 +1,642 @@ -import * as _LIST from './_LIST'; -import * as ALTER from './ALTER'; -import * as AGGREGATE_WITHCURSOR from './AGGREGATE_WITHCURSOR'; -import * as AGGREGATE from './AGGREGATE'; -import * as ALIASADD from './ALIASADD'; -import * as ALIASDEL from './ALIASDEL'; -import * as ALIASUPDATE from './ALIASUPDATE'; -import * as CONFIG_GET from './CONFIG_GET'; -import * as CONFIG_SET from './CONFIG_SET'; -import * as CREATE from './CREATE'; -import * as CURSOR_DEL from './CURSOR_DEL'; -import * as CURSOR_READ from './CURSOR_READ'; -import * as DICTADD from './DICTADD'; -import * as DICTDEL from './DICTDEL'; -import * as DICTDUMP from './DICTDUMP'; -import * as DROPINDEX from './DROPINDEX'; -import * as EXPLAIN from './EXPLAIN'; -import * as EXPLAINCLI from './EXPLAINCLI'; -import * as INFO from './INFO'; -import * as PROFILESEARCH from './PROFILE_SEARCH'; -import * as PROFILEAGGREGATE from './PROFILE_AGGREGATE'; -import * as SEARCH from './SEARCH'; -import * as SPELLCHECK from './SPELLCHECK'; -import * as SUGADD from './SUGADD'; -import * as SUGDEL from './SUGDEL'; -import * as SUGGET_WITHPAYLOADS from './SUGGET_WITHPAYLOADS'; -import * as SUGGET_WITHSCORES_WITHPAYLOADS from './SUGGET_WITHSCORES_WITHPAYLOADS'; -import * as SUGGET_WITHSCORES from './SUGGET_WITHSCORES'; -import * as SUGGET from './SUGGET'; -import * as SUGLEN from './SUGLEN'; -import * as SYNDUMP from './SYNDUMP'; -import * as SYNUPDATE from './SYNUPDATE'; -import * as TAGVALS from './TAGVALS'; -import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands'; +import _LIST from './_LIST'; +// import ALTER from './ALTER'; +// import AGGREGATE_WITHCURSOR from './AGGREGATE_WITHCURSOR'; +// import AGGREGATE from './AGGREGATE'; +// import ALIASADD from './ALIASADD'; +// import ALIASDEL from './ALIASDEL'; +// import ALIASUPDATE from './ALIASUPDATE'; +// import CONFIG_GET from './CONFIG_GET'; +// import CONFIG_SET from './CONFIG_SET'; +import CREATE from './CREATE'; +// import CURSOR_DEL from './CURSOR_DEL'; +// import CURSOR_READ from './CURSOR_READ'; +import DICTADD from './DICTADD'; +import DICTDEL from './DICTDEL'; +import DICTDUMP from './DICTDUMP'; +import DROPINDEX from './DROPINDEX'; +import EXPLAIN from './EXPLAIN'; +import EXPLAINCLI from './EXPLAINCLI'; +// import INFO from './INFO'; +// import PROFILESEARCH from './PROFILE_SEARCH'; +// import PROFILEAGGREGATE from './PROFILE_AGGREGATE'; +// import SEARCH from './SEARCH'; +// import SPELLCHECK from './SPELLCHECK'; +import SUGADD from './SUGADD'; +import SUGDEL from './SUGDEL'; +// import SUGGET_WITHPAYLOADS from './SUGGET_WITHPAYLOADS'; +// import SUGGET_WITHSCORES_WITHPAYLOADS from './SUGGET_WITHSCORES_WITHPAYLOADS'; +// import SUGGET_WITHSCORES from './SUGGET_WITHSCORES'; +// import SUGGET from './SUGGET'; +import SUGLEN from './SUGLEN'; +// import SYNDUMP from './SYNDUMP'; +// import SYNUPDATE from './SYNUPDATE'; +import TAGVALS from './TAGVALS'; +// import { RedisCommandArgument, RedisCommandArguments } from '@redis/client/dist/lib/commands'; import { pushOptionalVariadicArgument, pushVariadicArgument } from '@redis/client/dist/lib/commands/generic-transformers'; import { SearchOptions } from './SEARCH'; +import { CommandArguments } from '@redis/client/dist/lib/RESP/types'; export default { - _LIST, - _list: _LIST, - ALTER, - alter: ALTER, - AGGREGATE_WITHCURSOR, - aggregateWithCursor: AGGREGATE_WITHCURSOR, - AGGREGATE, - aggregate: AGGREGATE, - ALIASADD, - aliasAdd: ALIASADD, - ALIASDEL, - aliasDel: ALIASDEL, - ALIASUPDATE, - aliasUpdate: ALIASUPDATE, - CONFIG_GET, - configGet: CONFIG_GET, - CONFIG_SET, - configSet: CONFIG_SET, - CREATE, - create: CREATE, - CURSOR_DEL, - cursorDel: CURSOR_DEL, - CURSOR_READ, - cursorRead: CURSOR_READ, - DICTADD, - dictAdd: DICTADD, - DICTDEL, - dictDel: DICTDEL, - DICTDUMP, - dictDump: DICTDUMP, - DROPINDEX, - dropIndex: DROPINDEX, - EXPLAIN, - explain: EXPLAIN, - EXPLAINCLI, - explainCli: EXPLAINCLI, - INFO, - info: INFO, - PROFILESEARCH, - profileSearch: PROFILESEARCH, - PROFILEAGGREGATE, - profileAggregate: PROFILEAGGREGATE, - SEARCH, - search: SEARCH, - SPELLCHECK, - spellCheck: SPELLCHECK, - SUGADD, - sugAdd: SUGADD, - SUGDEL, - sugDel: SUGDEL, - SUGGET_WITHPAYLOADS, - sugGetWithPayloads: SUGGET_WITHPAYLOADS, - SUGGET_WITHSCORES_WITHPAYLOADS, - sugGetWithScoresWithPayloads: SUGGET_WITHSCORES_WITHPAYLOADS, - SUGGET_WITHSCORES, - sugGetWithScores: SUGGET_WITHSCORES, - SUGGET, - sugGet: SUGGET, - SUGLEN, - sugLen: SUGLEN, - SYNDUMP, - synDump: SYNDUMP, - SYNUPDATE, - synUpdate: SYNUPDATE, - TAGVALS, - tagVals: TAGVALS + _LIST, + _list: _LIST, + // ALTER, + // alter: ALTER, + // AGGREGATE_WITHCURSOR, + // aggregateWithCursor: AGGREGATE_WITHCURSOR, + // AGGREGATE, + // aggregate: AGGREGATE, + // ALIASADD, + // aliasAdd: ALIASADD, + // ALIASDEL, + // aliasDel: ALIASDEL, + // ALIASUPDATE, + // aliasUpdate: ALIASUPDATE, + // CONFIG_GET, + // configGet: CONFIG_GET, + // CONFIG_SET, + // configSet: CONFIG_SET, + CREATE, + create: CREATE, + // CURSOR_DEL, + // cursorDel: CURSOR_DEL, + // CURSOR_READ, + // cursorRead: CURSOR_READ, + DICTADD, + dictAdd: DICTADD, + DICTDEL, + dictDel: DICTDEL, + DICTDUMP, + dictDump: DICTDUMP, + DROPINDEX, + dropIndex: DROPINDEX, + EXPLAIN, + explain: EXPLAIN, + EXPLAINCLI, + explainCli: EXPLAINCLI, + // INFO, + // info: INFO, + // PROFILESEARCH, + // profileSearch: PROFILESEARCH, + // PROFILEAGGREGATE, + // profileAggregate: PROFILEAGGREGATE, + // SEARCH, + // search: SEARCH, + // SPELLCHECK, + // spellCheck: SPELLCHECK, + SUGADD, + sugAdd: SUGADD, + SUGDEL, + sugDel: SUGDEL, + // SUGGET_WITHPAYLOADS, + // sugGetWithPayloads: SUGGET_WITHPAYLOADS, + // SUGGET_WITHSCORES_WITHPAYLOADS, + // sugGetWithScoresWithPayloads: SUGGET_WITHSCORES_WITHPAYLOADS, + // SUGGET_WITHSCORES, + // sugGetWithScores: SUGGET_WITHSCORES, + // SUGGET, + // sugGet: SUGGET, + SUGLEN, + sugLen: SUGLEN, + // SYNDUMP, + // synDump: SYNDUMP, + // SYNUPDATE, + // synUpdate: SYNUPDATE, + TAGVALS, + tagVals: TAGVALS }; -export enum RedisSearchLanguages { - ARABIC = 'Arabic', - BASQUE = 'Basque', - CATALANA = 'Catalan', - DANISH = 'Danish', - DUTCH = 'Dutch', - ENGLISH = 'English', - FINNISH = 'Finnish', - FRENCH = 'French', - GERMAN = 'German', - GREEK = 'Greek', - HUNGARIAN = 'Hungarian', - INDONESAIN = 'Indonesian', - IRISH = 'Irish', - ITALIAN = 'Italian', - LITHUANIAN = 'Lithuanian', - NEPALI = 'Nepali', - NORWEIGAN = 'Norwegian', - PORTUGUESE = 'Portuguese', - ROMANIAN = 'Romanian', - RUSSIAN = 'Russian', - SPANISH = 'Spanish', - SWEDISH = 'Swedish', - TAMIL = 'Tamil', - TURKISH = 'Turkish', - CHINESE = 'Chinese' -} +// export enum RedisSearchLanguages { +// ARABIC = 'Arabic', +// BASQUE = 'Basque', +// CATALANA = 'Catalan', +// DANISH = 'Danish', +// DUTCH = 'Dutch', +// ENGLISH = 'English', +// FINNISH = 'Finnish', +// FRENCH = 'French', +// GERMAN = 'German', +// GREEK = 'Greek', +// HUNGARIAN = 'Hungarian', +// INDONESAIN = 'Indonesian', +// IRISH = 'Irish', +// ITALIAN = 'Italian', +// LITHUANIAN = 'Lithuanian', +// NEPALI = 'Nepali', +// NORWEIGAN = 'Norwegian', +// PORTUGUESE = 'Portuguese', +// ROMANIAN = 'Romanian', +// RUSSIAN = 'Russian', +// SPANISH = 'Spanish', +// SWEDISH = 'Swedish', +// TAMIL = 'Tamil', +// TURKISH = 'Turkish', +// CHINESE = 'Chinese' +// } export type PropertyName = `${'@' | '$.'}${string}`; export type SortByProperty = string | { - BY: string; - DIRECTION?: 'ASC' | 'DESC'; + BY: string; + DIRECTION?: 'ASC' | 'DESC'; }; export function pushSortByProperty(args: RedisCommandArguments, sortBy: SortByProperty): void { - if (typeof sortBy === 'string') { - args.push(sortBy); - } else { - args.push(sortBy.BY); + if (typeof sortBy === 'string') { + args.push(sortBy); + } else { + args.push(sortBy.BY); - if (sortBy.DIRECTION) { - args.push(sortBy.DIRECTION); - } + if (sortBy.DIRECTION) { + args.push(sortBy.DIRECTION); } + } } export function pushSortByArguments(args: RedisCommandArguments, name: string, sortBy: SortByProperty | Array): RedisCommandArguments { - const lengthBefore = args.push( - name, - '' // will be overwritten - ); + const lengthBefore = args.push( + name, + '' // will be overwritten + ); - if (Array.isArray(sortBy)) { - for (const field of sortBy) { - pushSortByProperty(args, field); - } - } else { - pushSortByProperty(args, sortBy); + if (Array.isArray(sortBy)) { + for (const field of sortBy) { + pushSortByProperty(args, field); } + } else { + pushSortByProperty(args, sortBy); + } - args[lengthBefore - 1] = (args.length - lengthBefore).toString(); + args[lengthBefore - 1] = (args.length - lengthBefore).toString(); - return args; + return args; } -export function pushArgumentsWithLength(args: RedisCommandArguments, fn: (args: RedisCommandArguments) => void): RedisCommandArguments { - const lengthIndex = args.push('') - 1; - fn(args); - args[lengthIndex] = (args.length - lengthIndex - 1).toString(); - return args; -} +// export function pushArgumentsWithLength(args: CommandArguments, fn: (args: CommandArguments) => void) { +// const lengthIndex = args.push('') - 1; +// fn(args); +// args[lengthIndex] = (args.length - lengthIndex - 1).toString(); +// return args; +// } -export enum SchemaFieldTypes { - TEXT = 'TEXT', - NUMERIC = 'NUMERIC', - GEO = 'GEO', - TAG = 'TAG', - VECTOR = 'VECTOR' -} +// export enum SchemaFieldTypes { +// TEXT = 'TEXT', +// NUMERIC = 'NUMERIC', +// GEO = 'GEO', +// TAG = 'TAG', +// VECTOR = 'VECTOR' +// } -type CreateSchemaField< - T extends SchemaFieldTypes, - E = Record -> = T | ({ - type: T; - AS?: string; -} & E); +// type CreateSchemaField< +// T extends SchemaFieldTypes, +// E = Record +// > = T | ({ +// type: T; +// AS?: string; +// } & E); -type CreateSchemaCommonField< - T extends SchemaFieldTypes, - E = Record -> = CreateSchemaField< - T, - ({ - SORTABLE?: true | 'UNF'; - NOINDEX?: true; - } & E) ->; +// type CreateSchemaCommonField< +// T extends SchemaFieldTypes, +// E = Record +// > = CreateSchemaField< +// T, +// ({ +// SORTABLE?: true | 'UNF'; +// NOINDEX?: true; +// } & E) +// >; -export enum SchemaTextFieldPhonetics { - DM_EN = 'dm:en', - DM_FR = 'dm:fr', - FM_PT = 'dm:pt', - DM_ES = 'dm:es' -} +// export enum SchemaTextFieldPhonetics { +// DM_EN = 'dm:en', +// DM_FR = 'dm:fr', +// FM_PT = 'dm:pt', +// DM_ES = 'dm:es' +// } -type CreateSchemaTextField = CreateSchemaCommonField; +// type CreateSchemaTextField = CreateSchemaCommonField; -type CreateSchemaNumericField = CreateSchemaCommonField; +// type CreateSchemaNumericField = CreateSchemaCommonField; -type CreateSchemaGeoField = CreateSchemaCommonField; +// type CreateSchemaGeoField = CreateSchemaCommonField; -type CreateSchemaTagField = CreateSchemaCommonField; +// type CreateSchemaTagField = CreateSchemaCommonField; -export enum VectorAlgorithms { - FLAT = 'FLAT', - HNSW = 'HNSW' -} +// export enum VectorAlgorithms { +// FLAT = 'FLAT', +// HNSW = 'HNSW' +// } -type CreateSchemaVectorField< - T extends VectorAlgorithms, - A extends Record -> = CreateSchemaField; +// type CreateSchemaVectorField< +// T extends VectorAlgorithms, +// A extends Record +// > = CreateSchemaField; -type CreateSchemaFlatVectorField = CreateSchemaVectorField; +// type CreateSchemaFlatVectorField = CreateSchemaVectorField; -type CreateSchemaHNSWVectorField = CreateSchemaVectorField; +// type CreateSchemaHNSWVectorField = CreateSchemaVectorField; -export interface RediSearchSchema { - [field: string]: - CreateSchemaTextField | - CreateSchemaNumericField | - CreateSchemaGeoField | - CreateSchemaTagField | - CreateSchemaFlatVectorField | - CreateSchemaHNSWVectorField; -} +// export interface RediSearchSchema { +// [field: string]: +// CreateSchemaTextField | +// CreateSchemaNumericField | +// CreateSchemaGeoField | +// CreateSchemaTagField | +// CreateSchemaFlatVectorField | +// CreateSchemaHNSWVectorField; +// } -export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema) { - for (const [field, fieldOptions] of Object.entries(schema)) { - args.push(field); +// export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema) { +// for (const [field, fieldOptions] of Object.entries(schema)) { +// args.push(field); - if (typeof fieldOptions === 'string') { - args.push(fieldOptions); - continue; - } +// if (typeof fieldOptions === 'string') { +// args.push(fieldOptions); +// continue; +// } - if (fieldOptions.AS) { - args.push('AS', fieldOptions.AS); - } +// if (fieldOptions.AS) { +// args.push('AS', fieldOptions.AS); +// } - args.push(fieldOptions.type); +// args.push(fieldOptions.type); - switch (fieldOptions.type) { - case SchemaFieldTypes.TEXT: - if (fieldOptions.NOSTEM) { - args.push('NOSTEM'); - } +// switch (fieldOptions.type) { +// case SchemaFieldTypes.TEXT: +// if (fieldOptions.NOSTEM) { +// args.push('NOSTEM'); +// } - if (fieldOptions.WEIGHT) { - args.push('WEIGHT', fieldOptions.WEIGHT.toString()); - } +// if (fieldOptions.WEIGHT) { +// args.push('WEIGHT', fieldOptions.WEIGHT.toString()); +// } - if (fieldOptions.PHONETIC) { - args.push('PHONETIC', fieldOptions.PHONETIC); - } +// if (fieldOptions.PHONETIC) { +// args.push('PHONETIC', fieldOptions.PHONETIC); +// } - if (fieldOptions.WITHSUFFIXTRIE) { - args.push('WITHSUFFIXTRIE'); - } +// if (fieldOptions.WITHSUFFIXTRIE) { +// args.push('WITHSUFFIXTRIE'); +// } - break; +// break; - // case SchemaFieldTypes.NUMERIC: - // case SchemaFieldTypes.GEO: - // break; +// // case SchemaFieldTypes.NUMERIC: +// // case SchemaFieldTypes.GEO: +// // break; - case SchemaFieldTypes.TAG: - if (fieldOptions.SEPARATOR) { - args.push('SEPARATOR', fieldOptions.SEPARATOR); - } +// case SchemaFieldTypes.TAG: +// if (fieldOptions.SEPARATOR) { +// args.push('SEPARATOR', fieldOptions.SEPARATOR); +// } - if (fieldOptions.CASESENSITIVE) { - args.push('CASESENSITIVE'); - } +// if (fieldOptions.CASESENSITIVE) { +// args.push('CASESENSITIVE'); +// } - if (fieldOptions.WITHSUFFIXTRIE) { - args.push('WITHSUFFIXTRIE'); - } +// if (fieldOptions.WITHSUFFIXTRIE) { +// args.push('WITHSUFFIXTRIE'); +// } - break; +// break; - case SchemaFieldTypes.VECTOR: - args.push(fieldOptions.ALGORITHM); +// case SchemaFieldTypes.VECTOR: +// args.push(fieldOptions.ALGORITHM); - pushArgumentsWithLength(args, () => { - args.push( - 'TYPE', fieldOptions.TYPE, - 'DIM', fieldOptions.DIM.toString(), - 'DISTANCE_METRIC', fieldOptions.DISTANCE_METRIC - ); +// pushArgumentsWithLength(args, () => { +// args.push( +// 'TYPE', fieldOptions.TYPE, +// 'DIM', fieldOptions.DIM.toString(), +// 'DISTANCE_METRIC', fieldOptions.DISTANCE_METRIC +// ); - if (fieldOptions.INITIAL_CAP) { - args.push('INITIAL_CAP', fieldOptions.INITIAL_CAP.toString()); - } +// if (fieldOptions.INITIAL_CAP) { +// args.push('INITIAL_CAP', fieldOptions.INITIAL_CAP.toString()); +// } - switch (fieldOptions.ALGORITHM) { - case VectorAlgorithms.FLAT: - if (fieldOptions.BLOCK_SIZE) { - args.push('BLOCK_SIZE', fieldOptions.BLOCK_SIZE.toString()); - } +// switch (fieldOptions.ALGORITHM) { +// case VectorAlgorithms.FLAT: +// if (fieldOptions.BLOCK_SIZE) { +// args.push('BLOCK_SIZE', fieldOptions.BLOCK_SIZE.toString()); +// } - break; +// break; - case VectorAlgorithms.HNSW: - if (fieldOptions.M) { - args.push('M', fieldOptions.M.toString()); - } +// case VectorAlgorithms.HNSW: +// if (fieldOptions.M) { +// args.push('M', fieldOptions.M.toString()); +// } - if (fieldOptions.EF_CONSTRUCTION) { - args.push('EF_CONSTRUCTION', fieldOptions.EF_CONSTRUCTION.toString()); - } +// if (fieldOptions.EF_CONSTRUCTION) { +// args.push('EF_CONSTRUCTION', fieldOptions.EF_CONSTRUCTION.toString()); +// } - if (fieldOptions.EF_RUNTIME) { - args.push('EF_RUNTIME', fieldOptions.EF_RUNTIME.toString()); - } +// if (fieldOptions.EF_RUNTIME) { +// args.push('EF_RUNTIME', fieldOptions.EF_RUNTIME.toString()); +// } - break; - } - }); +// break; +// } +// }); - continue; // vector fields do not contain SORTABLE and NOINDEX options - } +// continue; // vector fields do not contain SORTABLE and NOINDEX options +// } - if (fieldOptions.SORTABLE) { - args.push('SORTABLE'); +// if (fieldOptions.SORTABLE) { +// args.push('SORTABLE'); - if (fieldOptions.SORTABLE === 'UNF') { - args.push('UNF'); - } - } +// if (fieldOptions.SORTABLE === 'UNF') { +// args.push('UNF'); +// } +// } - if (fieldOptions.NOINDEX) { - args.push('NOINDEX'); - } - } -} +// if (fieldOptions.NOINDEX) { +// args.push('NOINDEX'); +// } +// } +// } export type Params = Record; export function pushParamsArgs( - args: RedisCommandArguments, - params?: Params + args: RedisCommandArguments, + params?: Params ): RedisCommandArguments { - if (params) { - const enrties = Object.entries(params); - args.push('PARAMS', (enrties.length * 2).toString()); - for (const [key, value] of enrties) { - args.push(key, typeof value === 'number' ? value.toString() : value); - } + if (params) { + const enrties = Object.entries(params); + args.push('PARAMS', (enrties.length * 2).toString()); + for (const [key, value] of enrties) { + args.push(key, typeof value === 'number' ? value.toString() : value); } + } - return args; + return args; } export function pushSearchOptions( - args: RedisCommandArguments, - options?: SearchOptions + args: RedisCommandArguments, + options?: SearchOptions ): RedisCommandArguments { - if (options?.VERBATIM) { - args.push('VERBATIM'); + if (options?.VERBATIM) { + args.push('VERBATIM'); + } + + if (options?.NOSTOPWORDS) { + args.push('NOSTOPWORDS'); + } + + // if (options?.WITHSCORES) { + // args.push('WITHSCORES'); + // } + + // if (options?.WITHPAYLOADS) { + // args.push('WITHPAYLOADS'); + // } + + pushOptionalVariadicArgument(args, 'INKEYS', options?.INKEYS); + pushOptionalVariadicArgument(args, 'INFIELDS', options?.INFIELDS); + pushOptionalVariadicArgument(args, 'RETURN', options?.RETURN); + + if (options?.SUMMARIZE) { + args.push('SUMMARIZE'); + + if (typeof options.SUMMARIZE === 'object') { + if (options.SUMMARIZE.FIELDS) { + args.push('FIELDS'); + pushVariadicArgument(args, options.SUMMARIZE.FIELDS); + } + + if (options.SUMMARIZE.FRAGS) { + args.push('FRAGS', options.SUMMARIZE.FRAGS.toString()); + } + + if (options.SUMMARIZE.LEN) { + args.push('LEN', options.SUMMARIZE.LEN.toString()); + } + + if (options.SUMMARIZE.SEPARATOR) { + args.push('SEPARATOR', options.SUMMARIZE.SEPARATOR); + } } + } - if (options?.NOSTOPWORDS) { - args.push('NOSTOPWORDS'); + if (options?.HIGHLIGHT) { + args.push('HIGHLIGHT'); + + if (typeof options.HIGHLIGHT === 'object') { + if (options.HIGHLIGHT.FIELDS) { + args.push('FIELDS'); + pushVariadicArgument(args, options.HIGHLIGHT.FIELDS); + } + + if (options.HIGHLIGHT.TAGS) { + args.push('TAGS', options.HIGHLIGHT.TAGS.open, options.HIGHLIGHT.TAGS.close); + } } + } - // if (options?.WITHSCORES) { - // args.push('WITHSCORES'); - // } + if (options?.SLOP) { + args.push('SLOP', options.SLOP.toString()); + } - // if (options?.WITHPAYLOADS) { - // args.push('WITHPAYLOADS'); - // } + if (options?.INORDER) { + args.push('INORDER'); + } - pushOptionalVariadicArgument(args, 'INKEYS', options?.INKEYS); - pushOptionalVariadicArgument(args, 'INFIELDS', options?.INFIELDS); - pushOptionalVariadicArgument(args, 'RETURN', options?.RETURN); + if (options?.LANGUAGE) { + args.push('LANGUAGE', options.LANGUAGE); + } - if (options?.SUMMARIZE) { - args.push('SUMMARIZE'); + if (options?.EXPANDER) { + args.push('EXPANDER', options.EXPANDER); + } - if (typeof options.SUMMARIZE === 'object') { - if (options.SUMMARIZE.FIELDS) { - args.push('FIELDS'); - pushVariadicArgument(args, options.SUMMARIZE.FIELDS); - } + if (options?.SCORER) { + args.push('SCORER', options.SCORER); + } - if (options.SUMMARIZE.FRAGS) { - args.push('FRAGS', options.SUMMARIZE.FRAGS.toString()); - } + // if (options?.EXPLAINSCORE) { + // args.push('EXPLAINSCORE'); + // } - if (options.SUMMARIZE.LEN) { - args.push('LEN', options.SUMMARIZE.LEN.toString()); - } + // if (options?.PAYLOAD) { + // args.push('PAYLOAD', options.PAYLOAD); + // } - if (options.SUMMARIZE.SEPARATOR) { - args.push('SEPARATOR', options.SUMMARIZE.SEPARATOR); - } - } - } + if (options?.SORTBY) { + args.push('SORTBY'); + pushSortByProperty(args, options.SORTBY); + } - if (options?.HIGHLIGHT) { - args.push('HIGHLIGHT'); + // if (options?.MSORTBY) { + // pushSortByArguments(args, 'MSORTBY', options.MSORTBY); + // } - if (typeof options.HIGHLIGHT === 'object') { - if (options.HIGHLIGHT.FIELDS) { - args.push('FIELDS'); - pushVariadicArgument(args, options.HIGHLIGHT.FIELDS); - } + if (options?.LIMIT) { + args.push( + 'LIMIT', + options.LIMIT.from.toString(), + options.LIMIT.size.toString() + ); + } - if (options.HIGHLIGHT.TAGS) { - args.push('TAGS', options.HIGHLIGHT.TAGS.open, options.HIGHLIGHT.TAGS.close); - } - } - } + if (options?.PARAMS) { + pushParamsArgs(args, options.PARAMS); + } - if (options?.SLOP) { - args.push('SLOP', options.SLOP.toString()); - } + if (options?.DIALECT) { + args.push('DIALECT', options.DIALECT.toString()); + } - if (options?.INORDER) { - args.push('INORDER'); - } + if (options?.RETURN?.length === 0) { + args.preserve = true; + } - if (options?.LANGUAGE) { - args.push('LANGUAGE', options.LANGUAGE); - } + if (options?.TIMEOUT !== undefined) { + args.push('TIMEOUT', options.TIMEOUT.toString()); + } - if (options?.EXPANDER) { - args.push('EXPANDER', options.EXPANDER); - } - - if (options?.SCORER) { - args.push('SCORER', options.SCORER); - } - - // if (options?.EXPLAINSCORE) { - // args.push('EXPLAINSCORE'); - // } - - // if (options?.PAYLOAD) { - // args.push('PAYLOAD', options.PAYLOAD); - // } - - if (options?.SORTBY) { - args.push('SORTBY'); - pushSortByProperty(args, options.SORTBY); - } - - // if (options?.MSORTBY) { - // pushSortByArguments(args, 'MSORTBY', options.MSORTBY); - // } - - if (options?.LIMIT) { - args.push( - 'LIMIT', - options.LIMIT.from.toString(), - options.LIMIT.size.toString() - ); - } - - if (options?.PARAMS) { - pushParamsArgs(args, options.PARAMS); - } - - if (options?.DIALECT) { - args.push('DIALECT', options.DIALECT.toString()); - } - - if (options?.RETURN?.length === 0) { - args.preserve = true; - } - - if (options?.TIMEOUT !== undefined) { - args.push('TIMEOUT', options.TIMEOUT.toString()); - } - - return args; + return args; } interface SearchDocumentValue { - [key: string]: string | number | null | Array | SearchDocumentValue; + [key: string]: string | number | null | Array | SearchDocumentValue; } export interface SearchReply { - total: number; - documents: Array<{ - id: string; - value: SearchDocumentValue; - }>; + total: number; + documents: Array<{ + id: string; + value: SearchDocumentValue; + }>; } export interface ProfileOptions { - LIMITED?: true; + LIMITED?: true; } export type ProfileRawReply = [ - results: T, - profile: [ - _: string, - TotalProfileTime: string, - _: string, - ParsingTime: string, - _: string, - PipelineCreationTime: string, - _: string, - IteratorsProfile: Array - ] + results: T, + profile: [ + _: string, + TotalProfileTime: string, + _: string, + ParsingTime: string, + _: string, + PipelineCreationTime: string, + _: string, + IteratorsProfile: Array + ] ]; export interface ProfileReply { - results: SearchReply | AGGREGATE.AggregateReply; - profile: ProfileData; + results: SearchReply | AGGREGATE.AggregateReply; + profile: ProfileData; } interface ChildIterator { - type?: string, - counter?: number, - term?: string, - size?: number, - time?: string, - childIterators?: Array + type?: string, + counter?: number, + term?: string, + size?: number, + time?: string, + childIterators?: Array } interface IteratorsProfile { - type?: string, - counter?: number, - queryType?: string, - time?: string, - childIterators?: Array + type?: string, + counter?: number, + queryType?: string, + time?: string, + childIterators?: Array } interface ProfileData { - totalProfileTime: string, - parsingTime: string, - pipelineCreationTime: string, - iteratorsProfile: IteratorsProfile + totalProfileTime: string, + parsingTime: string, + pipelineCreationTime: string, + iteratorsProfile: IteratorsProfile } -export function transformProfile(reply: Array): ProfileData{ - return { - totalProfileTime: reply[0][1], - parsingTime: reply[1][1], - pipelineCreationTime: reply[2][1], - iteratorsProfile: transformIterators(reply[3][1]) - }; +export function transformProfile(reply: Array): ProfileData { + return { + totalProfileTime: reply[0][1], + parsingTime: reply[1][1], + pipelineCreationTime: reply[2][1], + iteratorsProfile: transformIterators(reply[3][1]) + }; } function transformIterators(IteratorsProfile: Array): IteratorsProfile { - var res: IteratorsProfile = {}; - for (let i = 0; i < IteratorsProfile.length; i += 2) { - const value = IteratorsProfile[i+1]; - switch (IteratorsProfile[i]) { - case 'Type': - res.type = value; - break; - case 'Counter': - res.counter = value; - break; - case 'Time': - res.time = value; - break; - case 'Query type': - res.queryType = value; - break; - case 'Child iterators': - res.childIterators = value.map(transformChildIterators); - break; - } + var res: IteratorsProfile = {}; + for (let i = 0; i < IteratorsProfile.length; i += 2) { + const value = IteratorsProfile[i + 1]; + switch (IteratorsProfile[i]) { + case 'Type': + res.type = value; + break; + case 'Counter': + res.counter = value; + break; + case 'Time': + res.time = value; + break; + case 'Query type': + res.queryType = value; + break; + case 'Child iterators': + res.childIterators = value.map(transformChildIterators); + break; } + } - return res; + return res; } function transformChildIterators(IteratorsProfile: Array): ChildIterator { - var res: ChildIterator = {}; - for (let i = 1; i < IteratorsProfile.length; i += 2) { - const value = IteratorsProfile[i+1]; - switch (IteratorsProfile[i]) { - case 'Type': - res.type = value; - break; - case 'Counter': - res.counter = value; - break; - case 'Time': - res.time = value; - break; - case 'Size': - res.size = value; - break; - case 'Term': - res.term = value; - break; - case 'Child iterators': - res.childIterators = value.map(transformChildIterators); - break; - } + var res: ChildIterator = {}; + for (let i = 1; i < IteratorsProfile.length; i += 2) { + const value = IteratorsProfile[i + 1]; + switch (IteratorsProfile[i]) { + case 'Type': + res.type = value; + break; + case 'Counter': + res.counter = value; + break; + case 'Time': + res.time = value; + break; + case 'Size': + res.size = value; + break; + case 'Term': + res.term = value; + break; + case 'Child iterators': + res.childIterators = value.map(transformChildIterators); + break; } + } - return res; + return res; }