You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-07 13:22:56 +03:00
Update doctest client with latest v4 release (#2844)
This commit is contained in:
@@ -12,7 +12,7 @@ For complete examples, see [`search-hashes.js`](https://github.com/redis/node-re
|
||||
|
||||
#### Creating an Index
|
||||
|
||||
Before we can perform any searches, we need to tell RediSearch how to index our data, and which Redis keys to find that data in. The [FT.CREATE](https://oss.redis.com/redisearch/Commands/#ftcreate) command creates a RediSearch index. Here's how to use it to create an index we'll call `idx:animals` where we want to index hashes containing `name`, `species` and `age` fields, and whose key names in Redis begin with the prefix `noderedis:animals`:
|
||||
Before we can perform any searches, we need to tell RediSearch how to index our data, and which Redis keys to find that data in. The [FT.CREATE](https://redis.io/commands/ft.create) command creates a RediSearch index. Here's how to use it to create an index we'll call `idx:animals` where we want to index hashes containing `name`, `species` and `age` fields, and whose key names in Redis begin with the prefix `noderedis:animals`:
|
||||
|
||||
```javascript
|
||||
await client.ft.create('idx:animals', {
|
||||
@@ -28,11 +28,11 @@ await client.ft.create('idx:animals', {
|
||||
});
|
||||
```
|
||||
|
||||
See the [`FT.CREATE` documentation](https://oss.redis.com/redisearch/Commands/#ftcreate) for information about the different field types and additional options.
|
||||
See the [`FT.CREATE` documentation](https://redis.io/commands/ft.create/#description) for information about the different field types and additional options.
|
||||
|
||||
#### Querying the Index
|
||||
|
||||
Once we've created an index, and added some data to Redis hashes whose keys begin with the prefix `noderedis:animals`, we can start writing some search queries. RediSearch supports a rich query syntax for full-text search, faceted search, aggregation and more. Check out the [`FT.SEARCH` documentation](https://oss.redis.com/redisearch/Commands/#ftsearch) and the [query syntax reference](https://oss.redis.com/redisearch/Query_Syntax/) for more information.
|
||||
Once we've created an index, and added some data to Redis hashes whose keys begin with the prefix `noderedis:animals`, we can start writing some search queries. RediSearch supports a rich query syntax for full-text search, faceted search, aggregation and more. Check out the [`FT.SEARCH` documentation](https://redis.io/commands/ft.search) and the [query syntax reference](https://redis.io/docs/interact/search-and-query/query) for more information.
|
||||
|
||||
Let's write a query to find all the animals where the `species` field has the value `dog`:
|
||||
|
||||
@@ -112,7 +112,7 @@ Note that we're using JSON Path to specify where the fields to index are in our
|
||||
|
||||
Now we have an index and some data stored as JSON documents in Redis (see the [JSON package documentation](https://github.com/redis/node-redis/tree/master/packages/json) for examples of how to store JSON), we can write some queries...
|
||||
|
||||
We'll use the [RediSearch query language](https://oss.redis.com/redisearch/Query_Syntax/) and [`FT.SEARCH`](https://oss.redis.com/redisearch/Commands/#ftsearch) command. Here's a query to find users under the age of 30:
|
||||
We'll use the [RediSearch query language](https://redis.io/docs/interact/search-and-query/query) and [`FT.SEARCH`](https://redis.io/commands/ft.search) command. Here's a query to find users under the age of 30:
|
||||
|
||||
```javascript
|
||||
await client.ft.search('idx:users', '@age:[0 30]');
|
||||
|
@@ -19,6 +19,13 @@ describe('AGGREGATE', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('with ADDSCORES', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', '*', { ADDSCORES: true }),
|
||||
['FT.AGGREGATE', 'index', '*', 'ADDSCORES']
|
||||
);
|
||||
});
|
||||
|
||||
describe('with LOAD', () => {
|
||||
describe('single', () => {
|
||||
describe('without alias', () => {
|
||||
@@ -454,6 +461,13 @@ describe('AGGREGATE', () => {
|
||||
['FT.AGGREGATE', 'index', '*', 'DIALECT', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with TIMEOUT', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', '*', { TIMEOUT: 10 }),
|
||||
['FT.AGGREGATE', 'index', '*', 'TIMEOUT', '10']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.ft.aggregate', async client => {
|
||||
|
@@ -119,11 +119,13 @@ type LoadField = PropertyName | {
|
||||
}
|
||||
|
||||
export interface AggregateOptions {
|
||||
VERBATIM?: true;
|
||||
VERBATIM?: boolean;
|
||||
ADDSCORES?: boolean;
|
||||
LOAD?: LoadField | Array<LoadField>;
|
||||
STEPS?: Array<GroupByStep | SortStep | ApplyStep | LimitStep | FilterStep>;
|
||||
PARAMS?: Params;
|
||||
DIALECT?: number;
|
||||
TIMEOUT?: number;
|
||||
}
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
@@ -149,6 +151,10 @@ export function pushAggregatehOptions(
|
||||
args.push('VERBATIM');
|
||||
}
|
||||
|
||||
if (options?.ADDSCORES) {
|
||||
args.push('ADDSCORES');
|
||||
}
|
||||
|
||||
if (options?.LOAD) {
|
||||
args.push('LOAD');
|
||||
pushArgumentsWithLength(args, () => {
|
||||
@@ -213,6 +219,10 @@ export function pushAggregatehOptions(
|
||||
args.push('DIALECT', options.DIALECT.toString());
|
||||
}
|
||||
|
||||
if (options?.TIMEOUT !== undefined) {
|
||||
args.push('TIMEOUT', options.TIMEOUT.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -303,4 +313,4 @@ export function transformReply(rawReply: AggregateRawReply): AggregateReply {
|
||||
total: rawReply[0],
|
||||
results
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './CREATE';
|
||||
import { SchemaFieldTypes, SchemaTextFieldPhonetics, RedisSearchLanguages, VectorAlgorithms } from '.';
|
||||
import { SchemaFieldTypes, SchemaTextFieldPhonetics, RedisSearchLanguages, VectorAlgorithms, SCHEMA_GEO_SHAPE_COORD_SYSTEM } from '.';
|
||||
|
||||
describe('CREATE', () => {
|
||||
describe('transformArguments', () => {
|
||||
@@ -70,6 +70,18 @@ describe('CREATE', () => {
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'WITHSUFFIXTRIE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with INDEXEMPTY', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.TEXT,
|
||||
INDEXEMPTY: true
|
||||
}
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'INDEXEMPTY']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('NUMERIC', () => {
|
||||
@@ -148,6 +160,18 @@ describe('CREATE', () => {
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'WITHSUFFIXTRIE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with INDEXEMPTY', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.TAG,
|
||||
INDEXEMPTY: true
|
||||
}
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TAG', 'INDEXEMPTY']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('VECTOR', () => {
|
||||
@@ -196,6 +220,42 @@ describe('CREATE', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('GEOSHAPE', () => {
|
||||
describe('without options', () => {
|
||||
it('SCHEMA_FIELD_TYPE.GEOSHAPE', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: SchemaFieldTypes.GEOSHAPE
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE']
|
||||
);
|
||||
});
|
||||
|
||||
it('{ type: SCHEMA_FIELD_TYPE.GEOSHAPE }', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.GEOSHAPE
|
||||
}
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('with COORD_SYSTEM', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.GEOSHAPE,
|
||||
COORD_SYSTEM: SCHEMA_GEO_SHAPE_COORD_SYSTEM.SPHERICAL
|
||||
}
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'GEOSHAPE', 'COORD_SYSTEM', 'SPHERICAL']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with generic options', () => {
|
||||
it('with AS', () => {
|
||||
assert.deepEqual(
|
||||
@@ -246,6 +306,18 @@ describe('CREATE', () => {
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'NOINDEX']
|
||||
);
|
||||
});
|
||||
|
||||
it('with INDEXMISSING', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.TEXT,
|
||||
INDEXMISSING: true
|
||||
}
|
||||
}),
|
||||
['FT.CREATE', 'index', 'SCHEMA', 'field', 'TEXT', 'INDEXMISSING']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -4,15 +4,24 @@ import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments } from './CURSOR_READ';
|
||||
|
||||
describe('CURSOR READ', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', 0),
|
||||
['FT.CURSOR', 'READ', 'index', '0']
|
||||
);
|
||||
describe('transformArguments', () => {
|
||||
it('without options', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', 0),
|
||||
['FT.CURSOR', 'READ', 'index', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('with COUNT', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', 0, { COUNT: 1 }),
|
||||
['FT.CURSOR', 'READ', 'index', '0', 'COUNT', '1']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
testUtils.testWithClient('client.ft.cursorRead', async client => {
|
||||
const [ ,, { cursor } ] = await Promise.all([
|
||||
const [, , { cursor }] = await Promise.all([
|
||||
client.ft.create('idx', {
|
||||
field: {
|
||||
type: SchemaFieldTypes.TEXT
|
||||
|
@@ -4,16 +4,27 @@ export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
interface CursorReadOptions {
|
||||
COUNT?: number;
|
||||
}
|
||||
|
||||
export function transformArguments(
|
||||
index: RedisCommandArgument,
|
||||
cursor: number
|
||||
cursor: number,
|
||||
options?: CursorReadOptions
|
||||
): RedisCommandArguments {
|
||||
return [
|
||||
const args = [
|
||||
'FT.CURSOR',
|
||||
'READ',
|
||||
index,
|
||||
cursor.toString()
|
||||
];
|
||||
|
||||
if (options?.COUNT) {
|
||||
args.push('COUNT', options.COUNT.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
export { transformReply } from './AGGREGATE_WITHCURSOR';
|
||||
|
@@ -9,7 +9,7 @@ export function transformArguments(
|
||||
query: string,
|
||||
options?: ProfileOptions & SearchOptions
|
||||
): RedisCommandArguments {
|
||||
const args = ['FT.PROFILE', index, 'SEARCH'];
|
||||
let args: RedisCommandArguments = ['FT.PROFILE', index, 'SEARCH'];
|
||||
|
||||
if (options?.LIMITED) {
|
||||
args.push('LIMITED');
|
||||
@@ -21,9 +21,9 @@ export function transformArguments(
|
||||
|
||||
type ProfileSearchRawReply = ProfileRawReply<SearchRawReply>;
|
||||
|
||||
export function transformReply(reply: ProfileSearchRawReply): ProfileReply {
|
||||
export function transformReply(reply: ProfileSearchRawReply, withoutDocuments: boolean): ProfileReply {
|
||||
return {
|
||||
results: transformSearchReply(reply[0]),
|
||||
results: transformSearchReply(reply[0], withoutDocuments),
|
||||
profile: transformProfile(reply[1])
|
||||
};
|
||||
}
|
||||
|
@@ -233,6 +233,15 @@ describe('SEARCH', () => {
|
||||
['FT.SEARCH', 'index', 'query', 'DIALECT', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with TIMEOUT', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', 'query', {
|
||||
TIMEOUT: 5
|
||||
}),
|
||||
['FT.SEARCH', 'index', 'query', 'TIMEOUT', '5']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('client.ft.search', () => {
|
||||
@@ -267,7 +276,8 @@ describe('SEARCH', () => {
|
||||
client.ft.create('index', {
|
||||
field: SchemaFieldTypes.NUMERIC
|
||||
}),
|
||||
client.hSet('1', 'field', '1')
|
||||
client.hSet('1', 'field', '1'),
|
||||
client.hSet('2', 'field', '2')
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
@@ -275,10 +285,13 @@ describe('SEARCH', () => {
|
||||
RETURN: []
|
||||
}),
|
||||
{
|
||||
total: 1,
|
||||
total: 2,
|
||||
documents: [{
|
||||
id: '1',
|
||||
value: Object.create(null)
|
||||
}, {
|
||||
id: '2',
|
||||
value: Object.create(null)
|
||||
}]
|
||||
}
|
||||
);
|
||||
|
@@ -6,7 +6,6 @@ export const FIRST_KEY_INDEX = 1;
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export interface SearchOptions {
|
||||
// NOCONTENT?: true; TODO
|
||||
VERBATIM?: true;
|
||||
NOSTOPWORDS?: true;
|
||||
// WITHSCORES?: true;
|
||||
@@ -55,6 +54,7 @@ export interface SearchOptions {
|
||||
};
|
||||
PARAMS?: Params;
|
||||
DIALECT?: number;
|
||||
TIMEOUT?: number;
|
||||
}
|
||||
|
||||
export function transformArguments(
|
||||
@@ -70,13 +70,13 @@ export function transformArguments(
|
||||
|
||||
export type SearchRawReply = Array<any>;
|
||||
|
||||
export function transformReply(reply: SearchRawReply): SearchReply {
|
||||
export function transformReply(reply: SearchRawReply, withoutDocuments: boolean): SearchReply {
|
||||
const documents = [];
|
||||
let i = 1;
|
||||
while (i < reply.length) {
|
||||
documents.push({
|
||||
id: reply[i++],
|
||||
value: documentValue(reply[i++])
|
||||
value: withoutDocuments ? Object.create(null) : documentValue(reply[i++])
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ export function transformReply(reply: SearchRawReply): SearchReply {
|
||||
|
||||
function documentValue(tuples: any) {
|
||||
const message = Object.create(null);
|
||||
if (tuples === undefined) return message;
|
||||
|
||||
let i = 0;
|
||||
while (i < tuples.length) {
|
||||
|
45
packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts
Normal file
45
packages/search/lib/commands/SEARCH_NOCONTENT.spec.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import { SchemaFieldTypes } from '.';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { transformArguments, transformReply } from './SEARCH_NOCONTENT';
|
||||
|
||||
describe('SEARCH_NOCONTENT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('without options', () => {
|
||||
assert.deepEqual(
|
||||
transformArguments('index', 'query'),
|
||||
['FT.SEARCH', 'index', 'query', 'NOCONTENT']
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformReply', () => {
|
||||
it('returns total and keys', () => {
|
||||
assert.deepEqual(transformReply([3, '1', '2', '3']), {
|
||||
total: 3,
|
||||
documents: ['1', '2', '3']
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe('client.ft.searchNoContent', () => {
|
||||
testUtils.testWithClient('returns total and keys', async client => {
|
||||
await Promise.all([
|
||||
client.ft.create('index', {
|
||||
field: SchemaFieldTypes.TEXT
|
||||
}),
|
||||
client.hSet('1', 'field', 'field1'),
|
||||
client.hSet('2', 'field', 'field2'),
|
||||
client.hSet('3', 'field', 'field3')
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
await client.ft.searchNoContent('index', '*'),
|
||||
{
|
||||
total: 3,
|
||||
documents: ['1','2','3']
|
||||
}
|
||||
);
|
||||
}, GLOBAL.SERVERS.OPEN);
|
||||
});
|
||||
});
|
30
packages/search/lib/commands/SEARCH_NOCONTENT.ts
Normal file
30
packages/search/lib/commands/SEARCH_NOCONTENT.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { RedisCommandArguments } from "@redis/client/dist/lib/commands";
|
||||
import { pushSearchOptions } from ".";
|
||||
import { SearchOptions, SearchRawReply } from "./SEARCH";
|
||||
|
||||
export const FIRST_KEY_INDEX = 1;
|
||||
|
||||
export const IS_READ_ONLY = true;
|
||||
|
||||
export function transformArguments(
|
||||
index: string,
|
||||
query: string,
|
||||
options?: SearchOptions
|
||||
): RedisCommandArguments {
|
||||
return pushSearchOptions(
|
||||
['FT.SEARCH', index, query, 'NOCONTENT'],
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
export interface SearchNoContentReply {
|
||||
total: number;
|
||||
documents: Array<string>;
|
||||
};
|
||||
|
||||
export function transformReply(reply: SearchRawReply): SearchNoContentReply {
|
||||
return {
|
||||
total: reply[0],
|
||||
documents: reply.slice(1)
|
||||
};
|
||||
}
|
@@ -20,6 +20,7 @@ import * as INFO from './INFO';
|
||||
import * as PROFILESEARCH from './PROFILE_SEARCH';
|
||||
import * as PROFILEAGGREGATE from './PROFILE_AGGREGATE';
|
||||
import * as SEARCH from './SEARCH';
|
||||
import * as SEARCH_NOCONTENT from './SEARCH_NOCONTENT';
|
||||
import * as SPELLCHECK from './SPELLCHECK';
|
||||
import * as SUGADD from './SUGADD';
|
||||
import * as SUGDEL from './SUGDEL';
|
||||
@@ -80,6 +81,8 @@ export default {
|
||||
profileAggregate: PROFILEAGGREGATE,
|
||||
SEARCH,
|
||||
search: SEARCH,
|
||||
SEARCH_NOCONTENT,
|
||||
searchNoContent: SEARCH_NOCONTENT,
|
||||
SPELLCHECK,
|
||||
spellCheck: SPELLCHECK,
|
||||
SUGADD,
|
||||
@@ -182,28 +185,46 @@ export enum SchemaFieldTypes {
|
||||
NUMERIC = 'NUMERIC',
|
||||
GEO = 'GEO',
|
||||
TAG = 'TAG',
|
||||
VECTOR = 'VECTOR'
|
||||
VECTOR = 'VECTOR',
|
||||
GEOSHAPE = 'GEOSHAPE'
|
||||
}
|
||||
|
||||
|
||||
type CreateSchemaField<
|
||||
T extends SchemaFieldTypes,
|
||||
E = Record<PropertyKey, unknown>
|
||||
> = T | ({
|
||||
type: T;
|
||||
AS?: string;
|
||||
INDEXMISSING?: boolean;
|
||||
} & E);
|
||||
|
||||
type CommonFieldArguments = {
|
||||
SORTABLE?: boolean | 'UNF';
|
||||
NOINDEX?: boolean;
|
||||
};
|
||||
|
||||
type CreateSchemaCommonField<
|
||||
T extends SchemaFieldTypes,
|
||||
E = Record<PropertyKey, unknown>
|
||||
> = CreateSchemaField<
|
||||
T,
|
||||
({
|
||||
SORTABLE?: true | 'UNF';
|
||||
NOINDEX?: true;
|
||||
} & E)
|
||||
(CommonFieldArguments & E)
|
||||
>;
|
||||
|
||||
function pushCommonFieldArguments(args: RedisCommandArguments, fieldOptions: CommonFieldArguments) {
|
||||
if (fieldOptions.SORTABLE) {
|
||||
args.push('SORTABLE');
|
||||
|
||||
if (fieldOptions.SORTABLE === 'UNF') {
|
||||
args.push('UNF');
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldOptions.NOINDEX) {
|
||||
args.push('NOINDEX');
|
||||
}
|
||||
}
|
||||
|
||||
export enum SchemaTextFieldPhonetics {
|
||||
DM_EN = 'dm:en',
|
||||
DM_FR = 'dm:fr',
|
||||
@@ -216,6 +237,7 @@ type CreateSchemaTextField = CreateSchemaCommonField<SchemaFieldTypes.TEXT, {
|
||||
WEIGHT?: number;
|
||||
PHONETIC?: SchemaTextFieldPhonetics;
|
||||
WITHSUFFIXTRIE?: boolean;
|
||||
INDEXEMPTY?: boolean;
|
||||
}>;
|
||||
|
||||
type CreateSchemaNumericField = CreateSchemaCommonField<SchemaFieldTypes.NUMERIC>;
|
||||
@@ -226,6 +248,7 @@ type CreateSchemaTagField = CreateSchemaCommonField<SchemaFieldTypes.TAG, {
|
||||
SEPARATOR?: string;
|
||||
CASESENSITIVE?: true;
|
||||
WITHSUFFIXTRIE?: boolean;
|
||||
INDEXEMPTY?: boolean;
|
||||
}>;
|
||||
|
||||
export enum VectorAlgorithms {
|
||||
@@ -254,6 +277,17 @@ type CreateSchemaHNSWVectorField = CreateSchemaVectorField<VectorAlgorithms.HNSW
|
||||
EF_RUNTIME?: number;
|
||||
}>;
|
||||
|
||||
export const SCHEMA_GEO_SHAPE_COORD_SYSTEM = {
|
||||
SPHERICAL: 'SPHERICAL',
|
||||
FLAT: 'FLAT'
|
||||
} as const;
|
||||
|
||||
export type SchemaGeoShapeFieldCoordSystem = typeof SCHEMA_GEO_SHAPE_COORD_SYSTEM[keyof typeof SCHEMA_GEO_SHAPE_COORD_SYSTEM];
|
||||
|
||||
type CreateSchemaGeoShapeField = CreateSchemaCommonField<SchemaFieldTypes.GEOSHAPE, {
|
||||
COORD_SYSTEM?: SchemaGeoShapeFieldCoordSystem;
|
||||
}>;
|
||||
|
||||
export interface RediSearchSchema {
|
||||
[field: string]:
|
||||
CreateSchemaTextField |
|
||||
@@ -261,7 +295,8 @@ export interface RediSearchSchema {
|
||||
CreateSchemaGeoField |
|
||||
CreateSchemaTagField |
|
||||
CreateSchemaFlatVectorField |
|
||||
CreateSchemaHNSWVectorField;
|
||||
CreateSchemaHNSWVectorField |
|
||||
CreateSchemaGeoShapeField;
|
||||
}
|
||||
|
||||
export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema) {
|
||||
@@ -297,11 +332,18 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
|
||||
args.push('WITHSUFFIXTRIE');
|
||||
}
|
||||
|
||||
pushCommonFieldArguments(args, fieldOptions);
|
||||
|
||||
if (fieldOptions.INDEXEMPTY) {
|
||||
args.push('INDEXEMPTY');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// case SchemaFieldTypes.NUMERIC:
|
||||
// case SchemaFieldTypes.GEO:
|
||||
// break;
|
||||
case SchemaFieldTypes.NUMERIC:
|
||||
case SchemaFieldTypes.GEO:
|
||||
pushCommonFieldArguments(args, fieldOptions);
|
||||
break;
|
||||
|
||||
case SchemaFieldTypes.TAG:
|
||||
if (fieldOptions.SEPARATOR) {
|
||||
@@ -316,6 +358,12 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
|
||||
args.push('WITHSUFFIXTRIE');
|
||||
}
|
||||
|
||||
pushCommonFieldArguments(args, fieldOptions);
|
||||
|
||||
if (fieldOptions.INDEXEMPTY) {
|
||||
args.push('INDEXEMPTY');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SchemaFieldTypes.VECTOR:
|
||||
@@ -357,19 +405,20 @@ export function pushSchema(args: RedisCommandArguments, schema: RediSearchSchema
|
||||
}
|
||||
});
|
||||
|
||||
continue; // vector fields do not contain SORTABLE and NOINDEX options
|
||||
break;
|
||||
|
||||
case SchemaFieldTypes.GEOSHAPE:
|
||||
if (fieldOptions.COORD_SYSTEM !== undefined) {
|
||||
args.push('COORD_SYSTEM', fieldOptions.COORD_SYSTEM);
|
||||
}
|
||||
|
||||
pushCommonFieldArguments(args, fieldOptions);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (fieldOptions.SORTABLE) {
|
||||
args.push('SORTABLE');
|
||||
|
||||
if (fieldOptions.SORTABLE === 'UNF') {
|
||||
args.push('UNF');
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldOptions.NOINDEX) {
|
||||
args.push('NOINDEX');
|
||||
if (fieldOptions.INDEXMISSING) {
|
||||
args.push('INDEXMISSING');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,6 +555,14 @@ export function pushSearchOptions(
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
export { default } from './commands';
|
||||
|
||||
export { RediSearchSchema, SchemaFieldTypes, SchemaTextFieldPhonetics, SearchReply, VectorAlgorithms } from './commands';
|
||||
export { AggregateSteps, AggregateGroupByReducers } from './commands/AGGREGATE';
|
||||
export { RediSearchSchema, RedisSearchLanguages, SchemaFieldTypes, SchemaTextFieldPhonetics, SearchReply, VectorAlgorithms } from './commands';
|
||||
export { AggregateGroupByReducers, AggregateSteps } from './commands/AGGREGATE';
|
||||
export { SearchOptions } from './commands/SEARCH';
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@redis/search",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -18,12 +18,24 @@
|
||||
"devDependencies": {
|
||||
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
||||
"@redis/test-utils": "*",
|
||||
"@types/node": "^18.11.6",
|
||||
"@types/node": "^20.6.2",
|
||||
"nyc": "^15.1.0",
|
||||
"release-it": "^15.5.0",
|
||||
"release-it": "^16.1.5",
|
||||
"source-map-support": "^0.5.21",
|
||||
"ts-node": "^10.9.1",
|
||||
"typedoc": "^0.23.18",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
"typedoc": "^0.25.1",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/redis/node-redis.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/redis/node-redis/issues"
|
||||
},
|
||||
"homepage": "https://github.com/redis/node-redis/tree/master/packages/search",
|
||||
"keywords": [
|
||||
"redis",
|
||||
"RediSearch"
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user