tsense 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -40
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -0
- package/dist/migrator.d.ts +17 -0
- package/dist/migrator.js +141 -0
- package/dist/transformers/date.d.ts +2 -0
- package/dist/transformers/date.js +6 -0
- package/dist/transformers/defaults.d.ts +2 -0
- package/dist/transformers/defaults.js +2 -0
- package/dist/transformers/types.d.ts +7 -0
- package/dist/transformers/types.js +1 -0
- package/dist/tsense.d.ts +69 -4
- package/dist/tsense.js +153 -52
- package/dist/types.d.ts +23 -4
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -40,6 +40,8 @@ const UsersCollection = new TSense({
|
|
|
40
40
|
validateOnUpsert: true,
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
type User = typeof UsersCollection.infer;
|
|
44
|
+
|
|
43
45
|
await UsersCollection.create();
|
|
44
46
|
|
|
45
47
|
await UsersCollection.upsert([
|
|
@@ -72,29 +74,6 @@ await UsersCollection.drop();
|
|
|
72
74
|
|
|
73
75
|
## API Reference
|
|
74
76
|
|
|
75
|
-
### Constructor
|
|
76
|
-
|
|
77
|
-
```typescript
|
|
78
|
-
new TSense({
|
|
79
|
-
name: string,
|
|
80
|
-
schema: Type,
|
|
81
|
-
connection: ConnectionConfig,
|
|
82
|
-
defaultSearchField?: keyof T,
|
|
83
|
-
defaultSortingField?: keyof T,
|
|
84
|
-
batchSize?: number,
|
|
85
|
-
validateOnUpsert?: boolean,
|
|
86
|
-
})
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### ConnectionConfig
|
|
90
|
-
|
|
91
|
-
| Option | Type | Description |
|
|
92
|
-
| ---------- | --------------------- | --------------------- |
|
|
93
|
-
| `host` | `string` | Typesense server host |
|
|
94
|
-
| `port` | `number` | Typesense server port |
|
|
95
|
-
| `protocol` | `"http"` \| `"https"` | Connection protocol |
|
|
96
|
-
| `apiKey` | `string` | Typesense API key |
|
|
97
|
-
|
|
98
77
|
### Schema Configuration
|
|
99
78
|
|
|
100
79
|
Use `.configure()` to set Typesense field options:
|
|
@@ -122,22 +101,6 @@ type("string").configure({
|
|
|
122
101
|
| `upsert(docs)` | Inserts or updates documents |
|
|
123
102
|
| `search(options)` | Searches the collection |
|
|
124
103
|
|
|
125
|
-
### Search Options
|
|
126
|
-
|
|
127
|
-
| Option | Type | Description |
|
|
128
|
-
| ----------- | --------------------------------- | ------------------------ |
|
|
129
|
-
| `query` | `string` | Text search query |
|
|
130
|
-
| `queryBy` | `(keyof T)[]` | Fields to search in |
|
|
131
|
-
| `filter` | `FilterFor<T>` | Filter conditions |
|
|
132
|
-
| `sortBy` | `"field:asc\|desc"[]` | Sort order |
|
|
133
|
-
| `facetBy` | `(keyof T)[]` | Fields to facet by |
|
|
134
|
-
| `page` | `number` | Page number |
|
|
135
|
-
| `limit` | `number` | Results per page |
|
|
136
|
-
| `pick` | `(keyof T)[]` | Only return these fields |
|
|
137
|
-
| `omit` | `(keyof T)[]` | Exclude these fields |
|
|
138
|
-
| `highlight` | `boolean \| HighlightOptions<T>` | Enable highlighting |
|
|
139
|
-
|
|
140
|
-
Note: `pick` and `omit` are mutually exclusive.
|
|
141
104
|
|
|
142
105
|
### Filter Syntax
|
|
143
106
|
|
|
@@ -148,4 +111,4 @@ filter: { age: [25, 30, 35] } // IN
|
|
|
148
111
|
filter: { age: { min: 20, max: 40 } } // Range
|
|
149
112
|
filter: { name: { not: "John" } } // Not equal
|
|
150
113
|
filter: { OR: [{ age: 25 }, { age: 30 }] } // OR conditions
|
|
151
|
-
```
|
|
114
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export type { TsenseFieldMeta, TsenseFieldType } from "./env.js";
|
|
2
2
|
export { TSense } from "./tsense.js";
|
|
3
|
-
export
|
|
3
|
+
export { defaultTransformers } from "./transformers/defaults.js";
|
|
4
|
+
export { DateTransformer } from "./transformers/date.js";
|
|
5
|
+
export type { FieldTransformer } from "./transformers/types.js";
|
|
6
|
+
export type { ConnectionConfig, DeleteResult, FilterFor, HighlightOptions, SearchListOptions, SearchListResult, SearchOptions, SearchResult, TsenseOptions, UpdateResult, UpsertResult, } from "./types.js";
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AxiosInstance } from "./tsense.js";
|
|
2
|
+
import type { FieldSchema } from "./types.js";
|
|
3
|
+
export declare class TSenseMigrator {
|
|
4
|
+
private collectionName;
|
|
5
|
+
private localFields;
|
|
6
|
+
private defaultSortingField;
|
|
7
|
+
private axios;
|
|
8
|
+
constructor(collectionName: string, localFields: FieldSchema[], defaultSortingField: string | undefined, axios: AxiosInstance);
|
|
9
|
+
sync(): Promise<void>;
|
|
10
|
+
private exists;
|
|
11
|
+
private getRemoteFields;
|
|
12
|
+
private diff;
|
|
13
|
+
private fieldsMatch;
|
|
14
|
+
private patch;
|
|
15
|
+
private create;
|
|
16
|
+
private drop;
|
|
17
|
+
}
|
package/dist/migrator.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
const COMPARABLE_KEYS = ["type", "facet", "sort", "index", "optional"];
|
|
11
|
+
const NESTED_TYPES = ["object", "object[]"];
|
|
12
|
+
export class TSenseMigrator {
|
|
13
|
+
constructor(collectionName, localFields, defaultSortingField, axios) {
|
|
14
|
+
this.collectionName = collectionName;
|
|
15
|
+
this.localFields = localFields;
|
|
16
|
+
this.defaultSortingField = defaultSortingField;
|
|
17
|
+
this.axios = axios;
|
|
18
|
+
}
|
|
19
|
+
sync() {
|
|
20
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
const exists = yield this.exists();
|
|
22
|
+
if (!exists) {
|
|
23
|
+
return yield this.create();
|
|
24
|
+
}
|
|
25
|
+
const remoteFields = yield this.getRemoteFields();
|
|
26
|
+
const diff = this.diff(remoteFields);
|
|
27
|
+
if (!diff.toAdd.length && !diff.toRemove.length && !diff.toModify.length) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const patched = yield this.patch(diff);
|
|
31
|
+
if (patched)
|
|
32
|
+
return;
|
|
33
|
+
yield this.drop();
|
|
34
|
+
yield this.create();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
exists() {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
return yield this.axios({
|
|
40
|
+
method: "GET",
|
|
41
|
+
url: `/collections/${this.collectionName}`,
|
|
42
|
+
})
|
|
43
|
+
.then(() => true)
|
|
44
|
+
.catch((e) => {
|
|
45
|
+
if (e.status === 404)
|
|
46
|
+
return false;
|
|
47
|
+
throw e;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
getRemoteFields() {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
const { data } = yield this.axios({
|
|
54
|
+
method: "GET",
|
|
55
|
+
url: `/collections/${this.collectionName}`,
|
|
56
|
+
});
|
|
57
|
+
return data.fields;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
diff(remote) {
|
|
61
|
+
const remoteByName = new Map(remote.map((f) => [f.name, f]));
|
|
62
|
+
const localByName = new Map(this.localFields.map((f) => [f.name, f]));
|
|
63
|
+
const toAdd = [];
|
|
64
|
+
const toRemove = [];
|
|
65
|
+
const toModify = [];
|
|
66
|
+
for (const local of this.localFields) {
|
|
67
|
+
if (local.name === "id")
|
|
68
|
+
continue;
|
|
69
|
+
const remoteField = remoteByName.get(local.name);
|
|
70
|
+
if (!remoteField) {
|
|
71
|
+
toAdd.push(local);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (this.fieldsMatch(local, remoteField))
|
|
75
|
+
continue;
|
|
76
|
+
toModify.push(local);
|
|
77
|
+
}
|
|
78
|
+
for (const remoteField of remote) {
|
|
79
|
+
if (remoteField.name === "id")
|
|
80
|
+
continue;
|
|
81
|
+
if (localByName.has(remoteField.name))
|
|
82
|
+
continue;
|
|
83
|
+
toRemove.push(remoteField);
|
|
84
|
+
}
|
|
85
|
+
return { toAdd, toRemove, toModify };
|
|
86
|
+
}
|
|
87
|
+
fieldsMatch(local, remote) {
|
|
88
|
+
var _a, _b;
|
|
89
|
+
for (const key of COMPARABLE_KEYS) {
|
|
90
|
+
if (((_a = local[key]) !== null && _a !== void 0 ? _a : undefined) !== ((_b = remote[key]) !== null && _b !== void 0 ? _b : undefined)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
patch(diff) {
|
|
97
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const fields = [];
|
|
99
|
+
for (const field of diff.toRemove) {
|
|
100
|
+
fields.push({ name: field.name, drop: true });
|
|
101
|
+
}
|
|
102
|
+
for (const field of diff.toModify) {
|
|
103
|
+
fields.push({ name: field.name, drop: true });
|
|
104
|
+
fields.push(field);
|
|
105
|
+
}
|
|
106
|
+
for (const field of diff.toAdd) {
|
|
107
|
+
fields.push(field);
|
|
108
|
+
}
|
|
109
|
+
return yield this.axios({
|
|
110
|
+
method: "PATCH",
|
|
111
|
+
url: `/collections/${this.collectionName}`,
|
|
112
|
+
data: { fields },
|
|
113
|
+
})
|
|
114
|
+
.then(() => true)
|
|
115
|
+
.catch(() => false);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
create() {
|
|
119
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
120
|
+
const enable_nested_fields = this.localFields.some((f) => NESTED_TYPES.includes(f.type));
|
|
121
|
+
yield this.axios({
|
|
122
|
+
method: "POST",
|
|
123
|
+
url: "/collections",
|
|
124
|
+
data: {
|
|
125
|
+
name: this.collectionName,
|
|
126
|
+
fields: this.localFields,
|
|
127
|
+
default_sorting_field: this.defaultSortingField,
|
|
128
|
+
enable_nested_fields,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
drop() {
|
|
134
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
+
yield this.axios({
|
|
136
|
+
method: "DELETE",
|
|
137
|
+
url: `/collections/${this.collectionName}`,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TsenseFieldType } from "../env.js";
|
|
2
|
+
export interface FieldTransformer<TJs = unknown, TStorage = unknown> {
|
|
3
|
+
match: (expression: string, domain?: string) => boolean;
|
|
4
|
+
storageType: TsenseFieldType;
|
|
5
|
+
serialize: (value: TJs) => TStorage;
|
|
6
|
+
deserialize: (value: TStorage) => TJs;
|
|
7
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tsense.d.ts
CHANGED
|
@@ -1,14 +1,77 @@
|
|
|
1
1
|
import type { Type } from "arktype";
|
|
2
|
-
import
|
|
2
|
+
import redaxios from "redaxios";
|
|
3
|
+
import type { DeleteResult, FilterFor, SearchListOptions, SearchListResult, SearchOptions, SearchResult, TsenseOptions, UpdateResult, UpsertResult } from "./types.js";
|
|
4
|
+
declare const redaxiosInstance: {
|
|
5
|
+
<T>(urlOrConfig: string | redaxios.Options, config?: redaxios.Options | undefined, _method?: any, data?: any, _undefined?: undefined): Promise<redaxios.Response<T>>;
|
|
6
|
+
request: (<T_1 = any>(config?: redaxios.Options | undefined) => Promise<redaxios.Response<T_1>>) | (<T_2 = any>(url: string, config?: redaxios.Options | undefined) => Promise<redaxios.Response<T_2>>);
|
|
7
|
+
get<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
8
|
+
delete<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
9
|
+
head<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
10
|
+
options<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
11
|
+
post<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
12
|
+
put<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
13
|
+
patch<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
14
|
+
all: {
|
|
15
|
+
<T_5>(values: Iterable<T_5 | PromiseLike<T_5>>): Promise<T_5[]>;
|
|
16
|
+
<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
|
17
|
+
<T1_1, T2_1, T3_1, T4_1, T5_1, T6_1, T7_1, T8_1, T9_1>(values: readonly [T1_1 | PromiseLike<T1_1>, T2_1 | PromiseLike<T2_1>, T3_1 | PromiseLike<T3_1>, T4_1 | PromiseLike<T4_1>, T5_1 | PromiseLike<T5_1>, T6_1 | PromiseLike<T6_1>, T7_1 | PromiseLike<T7_1>, T8_1 | PromiseLike<T8_1>, T9_1 | PromiseLike<T9_1>]): Promise<[T1_1, T2_1, T3_1, T4_1, T5_1, T6_1, T7_1, T8_1, T9_1]>;
|
|
18
|
+
<T1_2, T2_2, T3_2, T4_2, T5_2, T6_2, T7_2, T8_2>(values: readonly [T1_2 | PromiseLike<T1_2>, T2_2 | PromiseLike<T2_2>, T3_2 | PromiseLike<T3_2>, T4_2 | PromiseLike<T4_2>, T5_2 | PromiseLike<T5_2>, T6_2 | PromiseLike<T6_2>, T7_2 | PromiseLike<T7_2>, T8_2 | PromiseLike<T8_2>]): Promise<[T1_2, T2_2, T3_2, T4_2, T5_2, T6_2, T7_2, T8_2]>;
|
|
19
|
+
<T1_3, T2_3, T3_3, T4_3, T5_3, T6_3, T7_3>(values: readonly [T1_3 | PromiseLike<T1_3>, T2_3 | PromiseLike<T2_3>, T3_3 | PromiseLike<T3_3>, T4_3 | PromiseLike<T4_3>, T5_3 | PromiseLike<T5_3>, T6_3 | PromiseLike<T6_3>, T7_3 | PromiseLike<T7_3>]): Promise<[T1_3, T2_3, T3_3, T4_3, T5_3, T6_3, T7_3]>;
|
|
20
|
+
<T1_4, T2_4, T3_4, T4_4, T5_4, T6_4>(values: readonly [T1_4 | PromiseLike<T1_4>, T2_4 | PromiseLike<T2_4>, T3_4 | PromiseLike<T3_4>, T4_4 | PromiseLike<T4_4>, T5_4 | PromiseLike<T5_4>, T6_4 | PromiseLike<T6_4>]): Promise<[T1_4, T2_4, T3_4, T4_4, T5_4, T6_4]>;
|
|
21
|
+
<T1_5, T2_5, T3_5, T4_5, T5_5>(values: readonly [T1_5 | PromiseLike<T1_5>, T2_5 | PromiseLike<T2_5>, T3_5 | PromiseLike<T3_5>, T4_5 | PromiseLike<T4_5>, T5_5 | PromiseLike<T5_5>]): Promise<[T1_5, T2_5, T3_5, T4_5, T5_5]>;
|
|
22
|
+
<T1_6, T2_6, T3_6, T4_6>(values: readonly [T1_6 | PromiseLike<T1_6>, T2_6 | PromiseLike<T2_6>, T3_6 | PromiseLike<T3_6>, T4_6 | PromiseLike<T4_6>]): Promise<[T1_6, T2_6, T3_6, T4_6]>;
|
|
23
|
+
<T1_7, T2_7, T3_7>(values: readonly [T1_7 | PromiseLike<T1_7>, T2_7 | PromiseLike<T2_7>, T3_7 | PromiseLike<T3_7>]): Promise<[T1_7, T2_7, T3_7]>;
|
|
24
|
+
<T1_8, T2_8>(values: readonly [T1_8 | PromiseLike<T1_8>, T2_8 | PromiseLike<T2_8>]): Promise<[T1_8, T2_8]>;
|
|
25
|
+
<T_6>(values: readonly (T_6 | PromiseLike<T_6>)[]): Promise<T_6[]>;
|
|
26
|
+
};
|
|
27
|
+
spread<Args, R>(fn: (...args: Args[]) => R): (array: Args[]) => R;
|
|
28
|
+
CancelToken: AbortController;
|
|
29
|
+
defaults: redaxios.Options;
|
|
30
|
+
create: (defaults?: redaxios.Options | undefined) => {
|
|
31
|
+
<T>(urlOrConfig: string | redaxios.Options, config?: redaxios.Options | undefined, _method?: any, data?: any, _undefined?: undefined): Promise<redaxios.Response<T>>;
|
|
32
|
+
request: (<T_1 = any>(config?: redaxios.Options | undefined) => Promise<redaxios.Response<T_1>>) | (<T_2 = any>(url: string, config?: redaxios.Options | undefined) => Promise<redaxios.Response<T_2>>);
|
|
33
|
+
get<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
34
|
+
delete<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
35
|
+
head<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
36
|
+
options<T_3 = any>(url: string, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_3>>;
|
|
37
|
+
post<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
38
|
+
put<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
39
|
+
patch<T_4 = any>(url: string, body?: any, config?: redaxios.Options | undefined): Promise<redaxios.Response<T_4>>;
|
|
40
|
+
all: {
|
|
41
|
+
<T_5>(values: Iterable<T_5 | PromiseLike<T_5>>): Promise<T_5[]>;
|
|
42
|
+
<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
|
|
43
|
+
<T1_1, T2_1, T3_1, T4_1, T5_1, T6_1, T7_1, T8_1, T9_1>(values: readonly [T1_1 | PromiseLike<T1_1>, T2_1 | PromiseLike<T2_1>, T3_1 | PromiseLike<T3_1>, T4_1 | PromiseLike<T4_1>, T5_1 | PromiseLike<T5_1>, T6_1 | PromiseLike<T6_1>, T7_1 | PromiseLike<T7_1>, T8_1 | PromiseLike<T8_1>, T9_1 | PromiseLike<T9_1>]): Promise<[T1_1, T2_1, T3_1, T4_1, T5_1, T6_1, T7_1, T8_1, T9_1]>;
|
|
44
|
+
<T1_2, T2_2, T3_2, T4_2, T5_2, T6_2, T7_2, T8_2>(values: readonly [T1_2 | PromiseLike<T1_2>, T2_2 | PromiseLike<T2_2>, T3_2 | PromiseLike<T3_2>, T4_2 | PromiseLike<T4_2>, T5_2 | PromiseLike<T5_2>, T6_2 | PromiseLike<T6_2>, T7_2 | PromiseLike<T7_2>, T8_2 | PromiseLike<T8_2>]): Promise<[T1_2, T2_2, T3_2, T4_2, T5_2, T6_2, T7_2, T8_2]>;
|
|
45
|
+
<T1_3, T2_3, T3_3, T4_3, T5_3, T6_3, T7_3>(values: readonly [T1_3 | PromiseLike<T1_3>, T2_3 | PromiseLike<T2_3>, T3_3 | PromiseLike<T3_3>, T4_3 | PromiseLike<T4_3>, T5_3 | PromiseLike<T5_3>, T6_3 | PromiseLike<T6_3>, T7_3 | PromiseLike<T7_3>]): Promise<[T1_3, T2_3, T3_3, T4_3, T5_3, T6_3, T7_3]>;
|
|
46
|
+
<T1_4, T2_4, T3_4, T4_4, T5_4, T6_4>(values: readonly [T1_4 | PromiseLike<T1_4>, T2_4 | PromiseLike<T2_4>, T3_4 | PromiseLike<T3_4>, T4_4 | PromiseLike<T4_4>, T5_4 | PromiseLike<T5_4>, T6_4 | PromiseLike<T6_4>]): Promise<[T1_4, T2_4, T3_4, T4_4, T5_4, T6_4]>;
|
|
47
|
+
<T1_5, T2_5, T3_5, T4_5, T5_5>(values: readonly [T1_5 | PromiseLike<T1_5>, T2_5 | PromiseLike<T2_5>, T3_5 | PromiseLike<T3_5>, T4_5 | PromiseLike<T4_5>, T5_5 | PromiseLike<T5_5>]): Promise<[T1_5, T2_5, T3_5, T4_5, T5_5]>;
|
|
48
|
+
<T1_6, T2_6, T3_6, T4_6>(values: readonly [T1_6 | PromiseLike<T1_6>, T2_6 | PromiseLike<T2_6>, T3_6 | PromiseLike<T3_6>, T4_6 | PromiseLike<T4_6>]): Promise<[T1_6, T2_6, T3_6, T4_6]>;
|
|
49
|
+
<T1_7, T2_7, T3_7>(values: readonly [T1_7 | PromiseLike<T1_7>, T2_7 | PromiseLike<T2_7>, T3_7 | PromiseLike<T3_7>]): Promise<[T1_7, T2_7, T3_7]>;
|
|
50
|
+
<T1_8, T2_8>(values: readonly [T1_8 | PromiseLike<T1_8>, T2_8 | PromiseLike<T2_8>]): Promise<[T1_8, T2_8]>;
|
|
51
|
+
<T_6>(values: readonly (T_6 | PromiseLike<T_6>)[]): Promise<T_6[]>;
|
|
52
|
+
};
|
|
53
|
+
spread<Args, R>(fn: (...args: Args[]) => R): (array: Args[]) => R;
|
|
54
|
+
CancelToken: AbortController;
|
|
55
|
+
defaults: redaxios.Options;
|
|
56
|
+
create: any;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
export type AxiosInstance = ReturnType<typeof redaxiosInstance.create>;
|
|
3
60
|
export declare class TSense<T extends Type> {
|
|
4
61
|
private options;
|
|
5
62
|
private fields;
|
|
6
|
-
private
|
|
7
|
-
private
|
|
8
|
-
private
|
|
63
|
+
private axios;
|
|
64
|
+
private synced;
|
|
65
|
+
private fieldTransformers;
|
|
66
|
+
infer: T["infer"];
|
|
9
67
|
constructor(options: TsenseOptions<T>);
|
|
10
68
|
private inferType;
|
|
69
|
+
private serializeDoc;
|
|
70
|
+
private deserializeDoc;
|
|
71
|
+
private serializeFilterValue;
|
|
11
72
|
private extractFields;
|
|
73
|
+
private ensureSynced;
|
|
74
|
+
sync(): Promise<void>;
|
|
12
75
|
private buildObjectFilter;
|
|
13
76
|
private buildFilter;
|
|
14
77
|
private buildSort;
|
|
@@ -20,5 +83,7 @@ export declare class TSense<T extends Type> {
|
|
|
20
83
|
update(id: string, data: Partial<T["infer"]>): Promise<T["infer"]>;
|
|
21
84
|
updateMany(filter: FilterFor<T["infer"]>, data: Partial<T["infer"]>): Promise<UpdateResult>;
|
|
22
85
|
search(options: SearchOptions<T["infer"]>): Promise<SearchResult<T["infer"]>>;
|
|
86
|
+
searchList(options: SearchListOptions<T["infer"]>): Promise<SearchListResult<T["infer"]>>;
|
|
23
87
|
upsert(docs: T["infer"] | T["infer"][]): Promise<UpsertResult[]>;
|
|
24
88
|
}
|
|
89
|
+
export {};
|
package/dist/tsense.js
CHANGED
|
@@ -9,8 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
var _a;
|
|
11
11
|
import redaxios from "redaxios";
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import { TSenseMigrator } from "./migrator.js";
|
|
13
|
+
import { defaultTransformers } from "./transformers/defaults.js";
|
|
14
|
+
const redaxiosInstance = (_a = redaxios.default) !== null && _a !== void 0 ? _a : redaxios;
|
|
14
15
|
const arkToTsense = {
|
|
15
16
|
string: "string",
|
|
16
17
|
number: "float",
|
|
@@ -22,13 +23,17 @@ const arkToTsense = {
|
|
|
22
23
|
};
|
|
23
24
|
export class TSense {
|
|
24
25
|
constructor(options) {
|
|
26
|
+
var _a;
|
|
25
27
|
this.options = options;
|
|
26
28
|
this.fields = [];
|
|
27
|
-
this.
|
|
28
|
-
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
31
|
-
|
|
29
|
+
this.synced = false;
|
|
30
|
+
this.fieldTransformers = new Map();
|
|
31
|
+
this.infer = undefined;
|
|
32
|
+
this.axios = redaxiosInstance.create({
|
|
33
|
+
baseURL: `${options.connection.protocol}://${options.connection.host}:${options.connection.port}`,
|
|
34
|
+
headers: { "X-TYPESENSE-API-KEY": options.connection.apiKey },
|
|
35
|
+
});
|
|
36
|
+
this.extractFields((_a = options.transformers) !== null && _a !== void 0 ? _a : defaultTransformers);
|
|
32
37
|
}
|
|
33
38
|
inferType(arkType) {
|
|
34
39
|
const direct = arkToTsense[arkType];
|
|
@@ -42,20 +47,71 @@ export class TSense {
|
|
|
42
47
|
return "string";
|
|
43
48
|
return "string";
|
|
44
49
|
}
|
|
45
|
-
|
|
50
|
+
serializeDoc(doc) {
|
|
51
|
+
const result = Object.assign({}, doc);
|
|
52
|
+
for (const [field, transformer] of this.fieldTransformers) {
|
|
53
|
+
if (result[field] != null) {
|
|
54
|
+
result[field] = transformer.serialize(result[field]);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
deserializeDoc(doc) {
|
|
60
|
+
for (const [field, transformer] of this.fieldTransformers) {
|
|
61
|
+
if (doc[field] != null) {
|
|
62
|
+
doc[field] = transformer.deserialize(doc[field]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return doc;
|
|
66
|
+
}
|
|
67
|
+
serializeFilterValue(key, value) {
|
|
68
|
+
const transformer = this.fieldTransformers.get(key);
|
|
69
|
+
if (!transformer)
|
|
70
|
+
return value;
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
return value.map((v) => transformer.serialize(v));
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "object" && value !== null) {
|
|
75
|
+
const v = value;
|
|
76
|
+
const isFilterObject = "min" in v || "max" in v || "not" in v;
|
|
77
|
+
if (!isFilterObject) {
|
|
78
|
+
return transformer.serialize(value);
|
|
79
|
+
}
|
|
80
|
+
const result = Object.assign({}, v);
|
|
81
|
+
if ("min" in v && v.min != null)
|
|
82
|
+
result.min = transformer.serialize(v.min);
|
|
83
|
+
if ("max" in v && v.max != null)
|
|
84
|
+
result.max = transformer.serialize(v.max);
|
|
85
|
+
if ("not" in v && v.not != null)
|
|
86
|
+
result.not = transformer.serialize(v.not);
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
return transformer.serialize(value);
|
|
90
|
+
}
|
|
91
|
+
extractFields(transformers) {
|
|
46
92
|
var _a;
|
|
47
93
|
const internal = this.options.schema;
|
|
48
94
|
for (const prop of internal.structure.props) {
|
|
49
95
|
const meta = prop.value.meta;
|
|
50
96
|
const expression = String(prop.value.expression);
|
|
51
97
|
const domain = prop.value.domain;
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
this.
|
|
98
|
+
const transformer = transformers.find((t) => t.match(expression, domain));
|
|
99
|
+
if (transformer) {
|
|
100
|
+
this.fieldTransformers.set(prop.key, transformer);
|
|
101
|
+
this.fields.push({
|
|
102
|
+
name: prop.key,
|
|
103
|
+
type: transformer.storageType,
|
|
104
|
+
optional: prop.kind === "optional",
|
|
105
|
+
facet: meta === null || meta === void 0 ? void 0 : meta.facet,
|
|
106
|
+
sort: meta === null || meta === void 0 ? void 0 : meta.sort,
|
|
107
|
+
index: meta === null || meta === void 0 ? void 0 : meta.index,
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
55
110
|
}
|
|
111
|
+
const type = (_a = meta === null || meta === void 0 ? void 0 : meta.type) !== null && _a !== void 0 ? _a : this.inferType(domain !== null && domain !== void 0 ? domain : expression);
|
|
56
112
|
this.fields.push({
|
|
57
113
|
name: prop.key,
|
|
58
|
-
type
|
|
114
|
+
type,
|
|
59
115
|
optional: prop.kind === "optional",
|
|
60
116
|
facet: meta === null || meta === void 0 ? void 0 : meta.facet,
|
|
61
117
|
sort: meta === null || meta === void 0 ? void 0 : meta.sort,
|
|
@@ -63,6 +119,19 @@ export class TSense {
|
|
|
63
119
|
});
|
|
64
120
|
}
|
|
65
121
|
}
|
|
122
|
+
ensureSynced(force) {
|
|
123
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
if (!force && (this.synced || !this.options.autoSync))
|
|
125
|
+
return;
|
|
126
|
+
yield new TSenseMigrator(this.options.name, this.fields, this.options.defaultSortingField, this.axios).sync();
|
|
127
|
+
this.synced = true;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
sync() {
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
yield this.ensureSynced(true);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
66
135
|
buildObjectFilter(key, value) {
|
|
67
136
|
var _a, _b;
|
|
68
137
|
if (Array.isArray(value)) {
|
|
@@ -87,18 +156,19 @@ export class TSense {
|
|
|
87
156
|
buildFilter(filter) {
|
|
88
157
|
const result = [];
|
|
89
158
|
for (const entry of Object.entries(filter !== null && filter !== void 0 ? filter : {})) {
|
|
90
|
-
const [key,
|
|
91
|
-
if (
|
|
159
|
+
const [key, rawValue] = entry;
|
|
160
|
+
if (rawValue == null)
|
|
92
161
|
continue;
|
|
93
162
|
if (key === "OR") {
|
|
94
163
|
const orFilter = [];
|
|
95
|
-
for (const condition of
|
|
164
|
+
for (const condition of rawValue) {
|
|
96
165
|
const inner = this.buildFilter(condition);
|
|
97
166
|
orFilter.push(`(${inner.join("||")})`);
|
|
98
167
|
}
|
|
99
168
|
result.push(`(${orFilter.join("||")})`);
|
|
100
169
|
continue;
|
|
101
170
|
}
|
|
171
|
+
const value = this.serializeFilterValue(key, rawValue);
|
|
102
172
|
switch (typeof value) {
|
|
103
173
|
case "string":
|
|
104
174
|
case "number":
|
|
@@ -132,16 +202,15 @@ export class TSense {
|
|
|
132
202
|
}
|
|
133
203
|
create() {
|
|
134
204
|
return __awaiter(this, void 0, void 0, function* () {
|
|
135
|
-
|
|
205
|
+
const enableNested = this.fields.some((f) => f.type === "object" || f.type === "object[]");
|
|
206
|
+
yield this.axios({
|
|
136
207
|
method: "POST",
|
|
137
|
-
baseURL: this.baseURL,
|
|
138
208
|
url: "/collections",
|
|
139
|
-
headers: this.headers,
|
|
140
209
|
data: {
|
|
141
210
|
name: this.options.name,
|
|
142
211
|
fields: this.fields,
|
|
143
212
|
default_sorting_field: this.options.defaultSortingField,
|
|
144
|
-
enable_nested_fields:
|
|
213
|
+
enable_nested_fields: enableNested,
|
|
145
214
|
},
|
|
146
215
|
});
|
|
147
216
|
return this;
|
|
@@ -149,36 +218,32 @@ export class TSense {
|
|
|
149
218
|
}
|
|
150
219
|
drop() {
|
|
151
220
|
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
-
yield axios({
|
|
221
|
+
yield this.axios({
|
|
153
222
|
method: "DELETE",
|
|
154
|
-
baseURL: this.baseURL,
|
|
155
223
|
url: `/collections/${this.options.name}`,
|
|
156
|
-
headers: this.headers,
|
|
157
224
|
});
|
|
158
225
|
});
|
|
159
226
|
}
|
|
160
227
|
get(id) {
|
|
161
228
|
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
-
|
|
229
|
+
yield this.ensureSynced();
|
|
230
|
+
const { data } = yield this.axios({
|
|
163
231
|
method: "GET",
|
|
164
|
-
baseURL: this.baseURL,
|
|
165
232
|
url: `/collections/${this.options.name}/documents/${id}`,
|
|
166
|
-
headers: this.headers,
|
|
167
233
|
}).catch((e) => {
|
|
168
234
|
if (e.status === 404)
|
|
169
235
|
return { data: null };
|
|
170
236
|
throw e;
|
|
171
237
|
});
|
|
172
|
-
return data;
|
|
238
|
+
return data ? this.deserializeDoc(data) : null;
|
|
173
239
|
});
|
|
174
240
|
}
|
|
175
241
|
delete(id) {
|
|
176
242
|
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
-
|
|
243
|
+
yield this.ensureSynced();
|
|
244
|
+
const { data } = yield this.axios({
|
|
178
245
|
method: "DELETE",
|
|
179
|
-
baseURL: this.baseURL,
|
|
180
246
|
url: `/collections/${this.options.name}/documents/${id}`,
|
|
181
|
-
headers: this.headers,
|
|
182
247
|
}).catch((e) => {
|
|
183
248
|
if (e.status === 404)
|
|
184
249
|
return { data: null };
|
|
@@ -189,15 +254,14 @@ export class TSense {
|
|
|
189
254
|
}
|
|
190
255
|
deleteMany(filter) {
|
|
191
256
|
return __awaiter(this, void 0, void 0, function* () {
|
|
257
|
+
yield this.ensureSynced();
|
|
192
258
|
const filterBy = this.buildFilter(filter).join("&&");
|
|
193
259
|
if (!filterBy) {
|
|
194
260
|
throw new Error("FILTER_REQUIRED");
|
|
195
261
|
}
|
|
196
|
-
const { data } = yield axios({
|
|
262
|
+
const { data } = yield this.axios({
|
|
197
263
|
method: "DELETE",
|
|
198
|
-
baseURL: this.baseURL,
|
|
199
264
|
url: `/collections/${this.options.name}/documents`,
|
|
200
|
-
headers: this.headers,
|
|
201
265
|
params: { filter_by: filterBy },
|
|
202
266
|
});
|
|
203
267
|
return { deleted: data.num_deleted };
|
|
@@ -205,29 +269,29 @@ export class TSense {
|
|
|
205
269
|
}
|
|
206
270
|
update(id, data) {
|
|
207
271
|
return __awaiter(this, void 0, void 0, function* () {
|
|
208
|
-
|
|
272
|
+
yield this.ensureSynced();
|
|
273
|
+
const serialized = this.serializeDoc(data);
|
|
274
|
+
const { data: updated } = yield this.axios({
|
|
209
275
|
method: "PATCH",
|
|
210
|
-
baseURL: this.baseURL,
|
|
211
276
|
url: `/collections/${this.options.name}/documents/${id}`,
|
|
212
|
-
|
|
213
|
-
data,
|
|
277
|
+
data: serialized,
|
|
214
278
|
});
|
|
215
|
-
return updated;
|
|
279
|
+
return this.deserializeDoc(updated);
|
|
216
280
|
});
|
|
217
281
|
}
|
|
218
282
|
updateMany(filter, data) {
|
|
219
283
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
|
+
yield this.ensureSynced();
|
|
220
285
|
const filterBy = this.buildFilter(filter).join("&&");
|
|
221
286
|
if (!filterBy) {
|
|
222
287
|
throw new Error("FILTER_REQUIRED");
|
|
223
288
|
}
|
|
224
|
-
const
|
|
289
|
+
const serialized = this.serializeDoc(data);
|
|
290
|
+
const { data: result } = yield this.axios({
|
|
225
291
|
method: "PATCH",
|
|
226
|
-
baseURL: this.baseURL,
|
|
227
292
|
url: `/collections/${this.options.name}/documents`,
|
|
228
|
-
headers: this.headers,
|
|
229
293
|
params: { filter_by: filterBy },
|
|
230
|
-
data,
|
|
294
|
+
data: serialized,
|
|
231
295
|
});
|
|
232
296
|
return { updated: result.num_updated };
|
|
233
297
|
});
|
|
@@ -235,11 +299,10 @@ export class TSense {
|
|
|
235
299
|
search(options) {
|
|
236
300
|
return __awaiter(this, void 0, void 0, function* () {
|
|
237
301
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
302
|
+
yield this.ensureSynced();
|
|
238
303
|
const params = {
|
|
239
304
|
q: (_a = options.query) !== null && _a !== void 0 ? _a : "",
|
|
240
|
-
query_by: ((_b = options.queryBy) !== null && _b !== void 0 ? _b : [
|
|
241
|
-
this.options.defaultSearchField,
|
|
242
|
-
]).join(","),
|
|
305
|
+
query_by: ((_b = options.queryBy) !== null && _b !== void 0 ? _b : [this.options.defaultSearchField]).join(","),
|
|
243
306
|
};
|
|
244
307
|
const sortBy = this.buildSort(options);
|
|
245
308
|
if (sortBy)
|
|
@@ -275,11 +338,9 @@ export class TSense {
|
|
|
275
338
|
params.highlight_end_tag = highlightOpts.endTag;
|
|
276
339
|
}
|
|
277
340
|
}
|
|
278
|
-
const { data: res } = yield axios({
|
|
341
|
+
const { data: res } = yield this.axios({
|
|
279
342
|
method: "GET",
|
|
280
|
-
baseURL: this.baseURL,
|
|
281
343
|
url: `/collections/${this.options.name}/documents/search`,
|
|
282
|
-
headers: this.headers,
|
|
283
344
|
params,
|
|
284
345
|
});
|
|
285
346
|
const data = [];
|
|
@@ -295,7 +356,8 @@ export class TSense {
|
|
|
295
356
|
hit.document[key] = value.snippet;
|
|
296
357
|
}
|
|
297
358
|
}
|
|
298
|
-
|
|
359
|
+
const doc = this.deserializeDoc(hit.document);
|
|
360
|
+
data.push(doc);
|
|
299
361
|
scores.push((_f = hit.text_match) !== null && _f !== void 0 ? _f : 0);
|
|
300
362
|
}
|
|
301
363
|
const facets = {};
|
|
@@ -314,8 +376,48 @@ export class TSense {
|
|
|
314
376
|
};
|
|
315
377
|
});
|
|
316
378
|
}
|
|
379
|
+
searchList(options) {
|
|
380
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
381
|
+
var _a, _b, _c, _d;
|
|
382
|
+
yield this.ensureSynced();
|
|
383
|
+
const limit = Math.min((_a = options.limit) !== null && _a !== void 0 ? _a : 20, 100);
|
|
384
|
+
const field = options.sort.field;
|
|
385
|
+
const params = {
|
|
386
|
+
q: (_b = options.query) !== null && _b !== void 0 ? _b : "",
|
|
387
|
+
query_by: ((_c = options.queryBy) !== null && _c !== void 0 ? _c : [this.options.defaultSearchField]).join(","),
|
|
388
|
+
per_page: limit,
|
|
389
|
+
sort_by: `${field}:${options.sort.direction}`,
|
|
390
|
+
};
|
|
391
|
+
const filterParts = this.buildFilter(options.filter);
|
|
392
|
+
if (options.cursor) {
|
|
393
|
+
const op = options.sort.direction === "asc" ? ">" : "<";
|
|
394
|
+
filterParts.push(`${field}:${op}${options.cursor}`);
|
|
395
|
+
}
|
|
396
|
+
const filterBy = filterParts.join("&&");
|
|
397
|
+
if (filterBy)
|
|
398
|
+
params.filter_by = filterBy;
|
|
399
|
+
const { data: res } = yield this.axios({
|
|
400
|
+
method: "GET",
|
|
401
|
+
url: `/collections/${this.options.name}/documents/search`,
|
|
402
|
+
params,
|
|
403
|
+
});
|
|
404
|
+
const hits = (_d = res.hits) !== null && _d !== void 0 ? _d : [];
|
|
405
|
+
const data = [];
|
|
406
|
+
for (const hit of hits) {
|
|
407
|
+
const doc = this.deserializeDoc(hit.document);
|
|
408
|
+
data.push(doc);
|
|
409
|
+
}
|
|
410
|
+
if (data.length < limit) {
|
|
411
|
+
return { data, nextCursor: null };
|
|
412
|
+
}
|
|
413
|
+
const lastHit = hits[hits.length - 1].document;
|
|
414
|
+
const nextCursor = String(lastHit[field]);
|
|
415
|
+
return { data, nextCursor };
|
|
416
|
+
});
|
|
417
|
+
}
|
|
317
418
|
upsert(docs) {
|
|
318
419
|
return __awaiter(this, void 0, void 0, function* () {
|
|
420
|
+
yield this.ensureSynced();
|
|
319
421
|
const items = Array.isArray(docs) ? docs : [docs];
|
|
320
422
|
if (!items.length)
|
|
321
423
|
return [];
|
|
@@ -324,16 +426,15 @@ export class TSense {
|
|
|
324
426
|
this.options.schema.assert(item);
|
|
325
427
|
}
|
|
326
428
|
}
|
|
327
|
-
const payload = items.map((item) => JSON.stringify(item)).join("\n");
|
|
429
|
+
const payload = items.map((item) => JSON.stringify(this.serializeDoc(item))).join("\n");
|
|
328
430
|
const params = { action: "upsert" };
|
|
329
431
|
if (this.options.batchSize) {
|
|
330
432
|
params.batch_size = this.options.batchSize;
|
|
331
433
|
}
|
|
332
|
-
const { data } = yield axios({
|
|
434
|
+
const { data } = yield this.axios({
|
|
333
435
|
method: "POST",
|
|
334
|
-
baseURL: this.baseURL,
|
|
335
436
|
url: `/collections/${this.options.name}/documents/import`,
|
|
336
|
-
headers:
|
|
437
|
+
headers: { "Content-Type": "text/plain" },
|
|
337
438
|
params,
|
|
338
439
|
data: payload,
|
|
339
440
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Type } from "arktype";
|
|
2
|
+
import type { FieldTransformer } from "./transformers/types.js";
|
|
2
3
|
type BaseIfArray<T> = T extends (infer Q)[] ? Q : T;
|
|
3
4
|
export type FieldSchema = {
|
|
4
5
|
name: string;
|
|
@@ -41,14 +42,16 @@ export type TsenseOptions<T extends Type> = {
|
|
|
41
42
|
defaultSortingField?: keyof T["infer"];
|
|
42
43
|
batchSize?: number;
|
|
43
44
|
validateOnUpsert?: boolean;
|
|
45
|
+
autoSync?: boolean;
|
|
46
|
+
transformers?: FieldTransformer[];
|
|
44
47
|
};
|
|
45
48
|
type SingleFilter<T> = Partial<{
|
|
46
49
|
[K in keyof T]: BaseIfArray<T[K]> | NonNullable<BaseIfArray<T[K]>>[] | {
|
|
47
50
|
not?: BaseIfArray<T[K]>;
|
|
48
|
-
} | (NonNullable<T[K]> extends number ? {
|
|
49
|
-
min?:
|
|
50
|
-
max?:
|
|
51
|
-
} : never);
|
|
51
|
+
} | (NonNullable<T[K]> extends number | Date ? NonNullable<T[K]> extends infer Type ? {
|
|
52
|
+
min?: Type;
|
|
53
|
+
max?: Type;
|
|
54
|
+
} : never : never);
|
|
52
55
|
}>;
|
|
53
56
|
export type FilterFor<T> = SingleFilter<T> & {
|
|
54
57
|
OR?: FilterFor<T>[];
|
|
@@ -96,4 +99,20 @@ export type UpsertResult = {
|
|
|
96
99
|
error?: string;
|
|
97
100
|
document?: unknown;
|
|
98
101
|
};
|
|
102
|
+
type SearchListSort<T> = {
|
|
103
|
+
field: keyof T;
|
|
104
|
+
direction: "asc" | "desc";
|
|
105
|
+
};
|
|
106
|
+
export type SearchListOptions<T> = {
|
|
107
|
+
query?: string;
|
|
108
|
+
queryBy?: (keyof T)[];
|
|
109
|
+
filter?: FilterFor<T>;
|
|
110
|
+
sort: SearchListSort<T>;
|
|
111
|
+
limit?: number;
|
|
112
|
+
cursor?: string;
|
|
113
|
+
};
|
|
114
|
+
export type SearchListResult<T> = {
|
|
115
|
+
data: T[];
|
|
116
|
+
nextCursor: string | null;
|
|
117
|
+
};
|
|
99
118
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsense",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Opinionated, fully typed typesense client",
|
|
6
6
|
"keywords": [
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"@biomejs/biome": "2.1.4",
|
|
42
42
|
"@changesets/cli": "^2.29.7",
|
|
43
43
|
"@types/bun": "latest",
|
|
44
|
-
"arktype": "^2.1.29"
|
|
44
|
+
"arktype": "^2.1.29",
|
|
45
|
+
"oxfmt": "^0.23.0",
|
|
46
|
+
"oxlint": "^1.38.0"
|
|
45
47
|
},
|
|
46
48
|
"peerDependencies": {
|
|
47
49
|
"arktype": "^2.1.29",
|