@xata.io/client 0.1.0 → 0.1.4
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 +1 -0
- package/dist/index.d.ts +17 -19
- package/dist/index.js +60 -45
- package/dist/index.test.js +3 -3
- package/package.json +4 -3
- package/src/index.test.ts +3 -3
- package/src/index.ts +87 -68
package/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Visit https://github.com/xataio/client-ts for more information.
|
package/dist/index.d.ts
CHANGED
@@ -23,25 +23,32 @@ export declare type Include<T> = {
|
|
23
23
|
[key in keyof T as T[key] extends XataRecord ? key : never]?: boolean | Array<keyof Selectable<T[key]>>;
|
24
24
|
};
|
25
25
|
declare type SortDirection = 'asc' | 'desc';
|
26
|
-
declare type Operator = '
|
26
|
+
declare type Operator = '$gt' | '$lt' | '$ge' | '$le' | '$exists' | '$notExists' | '$endsWith' | '$startsWith' | '$pattern' | '$is' | '$isNot' | '$contains' | '$includes' | '$includesSubstring' | '$includesPattern' | '$includesAll';
|
27
27
|
declare type Constraint<T> = Partial<Record<Operator, T>>;
|
28
|
+
declare type DeepConstraint<T> = T extends Record<string, any> ? {
|
29
|
+
[key in keyof T]?: T[key] | DeepConstraint<T[key]>;
|
30
|
+
} : Constraint<T>;
|
28
31
|
declare type ComparableType = number | Date;
|
29
32
|
export declare const gt: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
33
|
+
export declare const ge: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
30
34
|
export declare const gte: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
31
35
|
export declare const lt: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
32
36
|
export declare const lte: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
37
|
+
export declare const le: <T extends ComparableType>(value: T) => Partial<Record<Operator, T>>;
|
33
38
|
export declare const exists: (column: string) => Constraint<string>;
|
34
39
|
export declare const notExists: (column: string) => Constraint<string>;
|
35
40
|
export declare const startsWith: (value: string) => Constraint<string>;
|
36
41
|
export declare const endsWith: (value: string) => Constraint<string>;
|
37
42
|
export declare const pattern: (value: string) => Constraint<string>;
|
43
|
+
export declare const is: <T>(value: T) => Partial<Record<Operator, T>>;
|
38
44
|
export declare const isNot: <T>(value: T) => Partial<Record<Operator, T>>;
|
45
|
+
export declare const contains: <T>(value: T) => Partial<Record<Operator, T>>;
|
39
46
|
export declare const includes: (value: string) => Constraint<string>;
|
40
47
|
export declare const includesSubstring: (value: string) => Constraint<string>;
|
41
48
|
export declare const includesPattern: (value: string) => Constraint<string>;
|
42
49
|
export declare const includesAll: (value: string) => Constraint<string>;
|
43
50
|
declare type FilterConstraints<T> = {
|
44
|
-
[key in keyof T]?: T[key] extends Record<string, any> ? FilterConstraints<T[key]> : T[key] |
|
51
|
+
[key in keyof T]?: T[key] extends Record<string, any> ? FilterConstraints<T[key]> : T[key] | DeepConstraint<T[key]>;
|
45
52
|
};
|
46
53
|
declare type BulkQueryOptions<T> = {
|
47
54
|
filter?: FilterConstraints<T>;
|
@@ -54,32 +61,23 @@ declare type QueryOrConstraint<T, R> = Query<T, R> | Constraint<T>;
|
|
54
61
|
export declare class Query<T, R = T> {
|
55
62
|
table: string;
|
56
63
|
repository: Repository<T>;
|
57
|
-
readonly
|
58
|
-
readonly
|
59
|
-
readonly
|
60
|
-
readonly
|
61
|
-
readonly
|
64
|
+
readonly $any?: QueryOrConstraint<T, R>[];
|
65
|
+
readonly $all?: QueryOrConstraint<T, R>[];
|
66
|
+
readonly $not?: QueryOrConstraint<T, R>[];
|
67
|
+
readonly $none?: QueryOrConstraint<T, R>[];
|
68
|
+
readonly $sort?: Record<string, SortDirection>;
|
62
69
|
constructor(repository: Repository<T> | null, table: string, data: Partial<Query<T, R>>, parent?: Query<T, R>);
|
63
70
|
any(...queries: Query<T, R>[]): Query<T, R>;
|
64
71
|
all(...queries: Query<T, R>[]): Query<T, R>;
|
65
72
|
not(...queries: Query<T, R>[]): Query<T, R>;
|
66
73
|
none(...queries: Query<T, R>[]): Query<T, R>;
|
67
74
|
filter(constraints: FilterConstraints<T>): Query<T, R>;
|
68
|
-
filter<F extends keyof T>(column: F, value: FilterConstraints<T[F]> |
|
75
|
+
filter<F extends keyof T>(column: F, value: FilterConstraints<T[F]> | DeepConstraint<T[F]>): Query<T, R>;
|
69
76
|
sort<F extends keyof T>(column: F, direction: SortDirection): Query<T, R>;
|
70
77
|
getMany(options?: BulkQueryOptions<T>): Promise<R[]>;
|
71
78
|
getOne(options?: BulkQueryOptions<T>): Promise<R | null>;
|
72
79
|
deleteAll(): Promise<number>;
|
73
80
|
include(columns: Include<T>): this;
|
74
|
-
toJSON(): {
|
75
|
-
_filter: {
|
76
|
-
_any: QueryOrConstraint<T, R>[] | undefined;
|
77
|
-
_all: QueryOrConstraint<T, R>[] | undefined;
|
78
|
-
_not: QueryOrConstraint<T, R>[] | undefined;
|
79
|
-
_none: QueryOrConstraint<T, R>[] | undefined;
|
80
|
-
} | undefined;
|
81
|
-
_sort: Record<string, SortDirection> | undefined;
|
82
|
-
};
|
83
81
|
}
|
84
82
|
export declare abstract class Repository<T> extends Query<T, Selectable<T>> {
|
85
83
|
select<K extends keyof Selectable<T>>(...columns: K[]): Query<T, Select<T, K>>;
|
@@ -109,8 +107,8 @@ export declare class RestRespositoryFactory implements RepositoryFactory {
|
|
109
107
|
}
|
110
108
|
export declare type XataClientOptions = {
|
111
109
|
fetch?: unknown;
|
112
|
-
|
113
|
-
|
110
|
+
databaseURL: string;
|
111
|
+
apiKey: string;
|
114
112
|
repositoryFactory?: RepositoryFactory;
|
115
113
|
};
|
116
114
|
export declare class BaseClient<D extends Record<string, Repository<any>>> {
|
package/dist/index.js
CHANGED
@@ -9,35 +9,43 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
9
9
|
});
|
10
10
|
};
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
12
|
-
exports.XataError = exports.BaseClient = exports.RestRespositoryFactory = exports.RestRepository = exports.Repository = exports.Query = exports.includesAll = exports.includesPattern = exports.includesSubstring = exports.includes = exports.isNot = exports.pattern = exports.endsWith = exports.startsWith = exports.notExists = exports.exists = exports.lte = exports.lt = exports.gte = exports.gt = void 0;
|
13
|
-
const gt = (value) => ({
|
12
|
+
exports.XataError = exports.BaseClient = exports.RestRespositoryFactory = exports.RestRepository = exports.Repository = exports.Query = exports.includesAll = exports.includesPattern = exports.includesSubstring = exports.includes = exports.contains = exports.isNot = exports.is = exports.pattern = exports.endsWith = exports.startsWith = exports.notExists = exports.exists = exports.le = exports.lte = exports.lt = exports.gte = exports.ge = exports.gt = void 0;
|
13
|
+
const gt = (value) => ({ $gt: value });
|
14
14
|
exports.gt = gt;
|
15
|
-
const
|
15
|
+
const ge = (value) => ({ $ge: value });
|
16
|
+
exports.ge = ge;
|
17
|
+
const gte = (value) => ({ $ge: value });
|
16
18
|
exports.gte = gte;
|
17
|
-
const lt = (value) => ({
|
19
|
+
const lt = (value) => ({ $lt: value });
|
18
20
|
exports.lt = lt;
|
19
|
-
const lte = (value) => ({
|
21
|
+
const lte = (value) => ({ $le: value });
|
20
22
|
exports.lte = lte;
|
21
|
-
const
|
23
|
+
const le = (value) => ({ $le: value });
|
24
|
+
exports.le = le;
|
25
|
+
const exists = (column) => ({ $exists: column });
|
22
26
|
exports.exists = exists;
|
23
|
-
const notExists = (column) => ({
|
27
|
+
const notExists = (column) => ({ $notExists: column });
|
24
28
|
exports.notExists = notExists;
|
25
|
-
const startsWith = (value) => ({
|
29
|
+
const startsWith = (value) => ({ $startsWith: value });
|
26
30
|
exports.startsWith = startsWith;
|
27
|
-
const endsWith = (value) => ({
|
31
|
+
const endsWith = (value) => ({ $endsWith: value });
|
28
32
|
exports.endsWith = endsWith;
|
29
|
-
const pattern = (value) => ({
|
33
|
+
const pattern = (value) => ({ $pattern: value });
|
30
34
|
exports.pattern = pattern;
|
31
|
-
const
|
35
|
+
const is = (value) => ({ $is: value });
|
36
|
+
exports.is = is;
|
37
|
+
const isNot = (value) => ({ $isNot: value });
|
32
38
|
exports.isNot = isNot;
|
39
|
+
const contains = (value) => ({ $contains: value });
|
40
|
+
exports.contains = contains;
|
33
41
|
// TODO: these can only be applied to columns of type "multiple"
|
34
|
-
const includes = (value) => ({
|
42
|
+
const includes = (value) => ({ $includes: value });
|
35
43
|
exports.includes = includes;
|
36
|
-
const includesSubstring = (value) => ({
|
44
|
+
const includesSubstring = (value) => ({ $includesSubstring: value });
|
37
45
|
exports.includesSubstring = includesSubstring;
|
38
|
-
const includesPattern = (value) => ({
|
46
|
+
const includesPattern = (value) => ({ $includesPattern: value });
|
39
47
|
exports.includesPattern = includesPattern;
|
40
|
-
const includesAll = (value) => ({
|
48
|
+
const includesAll = (value) => ({ $includesAll: value });
|
41
49
|
exports.includesAll = includesAll;
|
42
50
|
class Query {
|
43
51
|
constructor(repository, table, data, parent) {
|
@@ -50,11 +58,11 @@ class Query {
|
|
50
58
|
this.table = table;
|
51
59
|
// For some reason Object.assign(this, parent) didn't work in this case
|
52
60
|
// so doing all this manually:
|
53
|
-
this
|
54
|
-
this
|
55
|
-
this
|
56
|
-
this
|
57
|
-
this
|
61
|
+
this.$any = parent === null || parent === void 0 ? void 0 : parent.$any;
|
62
|
+
this.$all = parent === null || parent === void 0 ? void 0 : parent.$all;
|
63
|
+
this.$not = parent === null || parent === void 0 ? void 0 : parent.$not;
|
64
|
+
this.$none = parent === null || parent === void 0 ? void 0 : parent.$none;
|
65
|
+
this.$sort = parent === null || parent === void 0 ? void 0 : parent.$sort;
|
58
66
|
Object.assign(this, data);
|
59
67
|
// These bindings are used to support deconstructing
|
60
68
|
// const { any, not, filter, sort } = xata.users.query()
|
@@ -64,25 +72,27 @@ class Query {
|
|
64
72
|
this.filter = this.filter.bind(this);
|
65
73
|
this.sort = this.sort.bind(this);
|
66
74
|
this.none = this.none.bind(this);
|
75
|
+
Object.defineProperty(this, 'table', { enumerable: false });
|
76
|
+
Object.defineProperty(this, 'repository', { enumerable: false });
|
67
77
|
}
|
68
78
|
any(...queries) {
|
69
79
|
return new Query(this.repository, this.table, {
|
70
|
-
|
80
|
+
$any: (this.$any || []).concat(queries)
|
71
81
|
}, this);
|
72
82
|
}
|
73
83
|
all(...queries) {
|
74
84
|
return new Query(this.repository, this.table, {
|
75
|
-
|
85
|
+
$all: (this.$all || []).concat(queries)
|
76
86
|
}, this);
|
77
87
|
}
|
78
88
|
not(...queries) {
|
79
89
|
return new Query(this.repository, this.table, {
|
80
|
-
|
90
|
+
$not: (this.$not || []).concat(queries)
|
81
91
|
}, this);
|
82
92
|
}
|
83
93
|
none(...queries) {
|
84
94
|
return new Query(this.repository, this.table, {
|
85
|
-
|
95
|
+
$none: (this.$none || []).concat(queries)
|
86
96
|
}, this);
|
87
97
|
}
|
88
98
|
filter(a, b) {
|
@@ -93,21 +103,21 @@ class Query {
|
|
93
103
|
queries.push({ [column]: constraint });
|
94
104
|
}
|
95
105
|
return new Query(this.repository, this.table, {
|
96
|
-
|
106
|
+
$all: (this.$all || []).concat(queries)
|
97
107
|
}, this);
|
98
108
|
}
|
99
109
|
else {
|
100
110
|
const column = a;
|
101
111
|
const value = b;
|
102
112
|
return new Query(this.repository, this.table, {
|
103
|
-
|
113
|
+
$all: (this.$all || []).concat({ [column]: value })
|
104
114
|
}, this);
|
105
115
|
}
|
106
116
|
}
|
107
117
|
sort(column, direction) {
|
108
|
-
const sort = Object.assign(Object.assign({}, this
|
118
|
+
const sort = Object.assign(Object.assign({}, this.$sort), { [column]: direction });
|
109
119
|
const q = new Query(this.repository, this.table, {
|
110
|
-
|
120
|
+
$sort: sort
|
111
121
|
}, this);
|
112
122
|
return q;
|
113
123
|
}
|
@@ -136,18 +146,6 @@ class Query {
|
|
136
146
|
// TODO
|
137
147
|
return this;
|
138
148
|
}
|
139
|
-
toJSON() {
|
140
|
-
const _filter = {
|
141
|
-
_any: this._any,
|
142
|
-
_all: this._all,
|
143
|
-
_not: this._not,
|
144
|
-
_none: this._none
|
145
|
-
};
|
146
|
-
return {
|
147
|
-
_filter: Object.values(_filter).some(Boolean) ? _filter : undefined,
|
148
|
-
_sort: this._sort
|
149
|
-
};
|
150
|
-
}
|
151
149
|
}
|
152
150
|
exports.Query = Query;
|
153
151
|
class Repository extends Query {
|
@@ -186,13 +184,13 @@ class RestRepository extends Repository {
|
|
186
184
|
}
|
187
185
|
request(method, path, body) {
|
188
186
|
return __awaiter(this, void 0, void 0, function* () {
|
189
|
-
const {
|
190
|
-
const resp = yield this.fetch(`${
|
187
|
+
const { databaseURL } = this.client.options;
|
188
|
+
const resp = yield this.fetch(`${databaseURL}${path}`, {
|
191
189
|
method,
|
192
190
|
headers: {
|
193
191
|
Accept: '*/*',
|
194
192
|
'Content-Type': 'application/json',
|
195
|
-
Authorization: `Bearer ${this.client.options.
|
193
|
+
Authorization: `Bearer ${this.client.options.apiKey}`
|
196
194
|
},
|
197
195
|
body: JSON.stringify(body)
|
198
196
|
});
|
@@ -222,7 +220,14 @@ class RestRepository extends Repository {
|
|
222
220
|
}
|
223
221
|
create(object) {
|
224
222
|
return __awaiter(this, void 0, void 0, function* () {
|
225
|
-
const
|
223
|
+
const body = Object.assign({}, object);
|
224
|
+
for (const key of Object.keys(body)) {
|
225
|
+
const value = body[key];
|
226
|
+
if (value && typeof value === 'object' && typeof value._id === 'string') {
|
227
|
+
body[key] = value._id;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
const obj = yield this.request('POST', `/tables/${this.table}/data`, body);
|
226
231
|
return this.client.initObject(this.table, obj);
|
227
232
|
});
|
228
233
|
}
|
@@ -252,7 +257,17 @@ class RestRepository extends Repository {
|
|
252
257
|
}
|
253
258
|
query(query) {
|
254
259
|
return __awaiter(this, void 0, void 0, function* () {
|
255
|
-
const
|
260
|
+
const filter = {
|
261
|
+
$any: query.$any,
|
262
|
+
$all: query.$all,
|
263
|
+
$not: query.$not,
|
264
|
+
$none: query.$none
|
265
|
+
};
|
266
|
+
const body = {
|
267
|
+
filter: Object.values(filter).some(Boolean) ? filter : undefined,
|
268
|
+
sort: query.$sort
|
269
|
+
};
|
270
|
+
const result = yield this.request('POST', `/tables/${this.table}/query`, body);
|
256
271
|
return result.records.map((record) => this.client.initObject(this.table, record));
|
257
272
|
});
|
258
273
|
}
|
package/dist/index.test.js
CHANGED
@@ -13,8 +13,8 @@ const _1 = require("./");
|
|
13
13
|
const fetch = jest.fn();
|
14
14
|
const client = new _1.BaseClient({
|
15
15
|
fetch,
|
16
|
-
|
17
|
-
|
16
|
+
apiKey: '1234',
|
17
|
+
databaseURL: 'https://my-workspace-5df34do.staging.xatabase.co/db/xata:main'
|
18
18
|
}, {});
|
19
19
|
const users = new _1.RestRepository(client, 'users');
|
20
20
|
describe('request', () => {
|
@@ -119,7 +119,7 @@ describe('query', () => {
|
|
119
119
|
expectRequest(expected, () => users.getMany(), { records: [] });
|
120
120
|
}));
|
121
121
|
test('query with one filter', () => __awaiter(void 0, void 0, void 0, function* () {
|
122
|
-
const expected = { method: 'POST', path: '/tables/users/query', body: {
|
122
|
+
const expected = { method: 'POST', path: '/tables/users/query', body: { filter: { $all: [{ name: 'foo' }] } } };
|
123
123
|
expectRequest(expected, () => users.filter('name', 'foo').getMany(), { records: [] });
|
124
124
|
}));
|
125
125
|
});
|
package/package.json
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "@xata.io/client",
|
3
|
-
"version": "0.1.
|
4
|
-
"description": "Xata.io SDK for
|
5
|
-
"main": "index.js",
|
3
|
+
"version": "0.1.4",
|
4
|
+
"description": "Xata.io SDK for TypeScript and JavaScript",
|
5
|
+
"main": "./dist/index.js",
|
6
|
+
"types": "./dist/index.d.ts",
|
6
7
|
"scripts": {
|
7
8
|
"test": "echo \"Error: no test specified\" && exit 1",
|
8
9
|
"build": "tsc",
|
package/src/index.test.ts
CHANGED
@@ -4,8 +4,8 @@ const fetch = jest.fn();
|
|
4
4
|
const client = new BaseClient(
|
5
5
|
{
|
6
6
|
fetch,
|
7
|
-
|
8
|
-
|
7
|
+
apiKey: '1234',
|
8
|
+
databaseURL: 'https://my-workspace-5df34do.staging.xatabase.co/db/xata:main'
|
9
9
|
},
|
10
10
|
{}
|
11
11
|
);
|
@@ -138,7 +138,7 @@ describe('query', () => {
|
|
138
138
|
});
|
139
139
|
|
140
140
|
test('query with one filter', async () => {
|
141
|
-
const expected = { method: 'POST', path: '/tables/users/query', body: {
|
141
|
+
const expected = { method: 'POST', path: '/tables/users/query', body: { filter: { $all: [{ name: 'foo' }] } } };
|
142
142
|
expectRequest(expected, () => users.filter('name', 'foo').getMany(), { records: [] });
|
143
143
|
});
|
144
144
|
});
|
package/src/index.ts
CHANGED
@@ -34,46 +34,58 @@ export type Include<T> = {
|
|
34
34
|
type SortDirection = 'asc' | 'desc';
|
35
35
|
|
36
36
|
type Operator =
|
37
|
-
| '
|
38
|
-
| '
|
39
|
-
| '
|
40
|
-
| '
|
41
|
-
| '
|
42
|
-
| '
|
43
|
-
| '
|
44
|
-
| '
|
45
|
-
| '
|
46
|
-
| '
|
47
|
-
| '
|
48
|
-
| '
|
49
|
-
| '
|
50
|
-
| '
|
37
|
+
| '$gt'
|
38
|
+
| '$lt'
|
39
|
+
| '$ge'
|
40
|
+
| '$le'
|
41
|
+
| '$exists'
|
42
|
+
| '$notExists'
|
43
|
+
| '$endsWith'
|
44
|
+
| '$startsWith'
|
45
|
+
| '$pattern'
|
46
|
+
| '$is'
|
47
|
+
| '$isNot'
|
48
|
+
| '$contains'
|
49
|
+
| '$includes'
|
50
|
+
| '$includesSubstring'
|
51
|
+
| '$includesPattern'
|
52
|
+
| '$includesAll';
|
51
53
|
|
52
54
|
// TODO: restrict constraints depending on type?
|
53
55
|
// E.g. startsWith cannot be used with numbers
|
54
56
|
type Constraint<T> = Partial<Record<Operator, T>>;
|
55
57
|
|
58
|
+
type DeepConstraint<T> = T extends Record<string, any>
|
59
|
+
? {
|
60
|
+
[key in keyof T]?: T[key] | DeepConstraint<T[key]>;
|
61
|
+
}
|
62
|
+
: Constraint<T>;
|
63
|
+
|
56
64
|
type ComparableType = number | Date;
|
57
65
|
|
58
|
-
export const gt = <T extends ComparableType>(value: T): Constraint<T> => ({
|
59
|
-
export const
|
60
|
-
export const
|
61
|
-
export const
|
62
|
-
export const
|
63
|
-
export const
|
64
|
-
export const
|
65
|
-
export const
|
66
|
-
export const
|
67
|
-
export const
|
66
|
+
export const gt = <T extends ComparableType>(value: T): Constraint<T> => ({ $gt: value });
|
67
|
+
export const ge = <T extends ComparableType>(value: T): Constraint<T> => ({ $ge: value });
|
68
|
+
export const gte = <T extends ComparableType>(value: T): Constraint<T> => ({ $ge: value });
|
69
|
+
export const lt = <T extends ComparableType>(value: T): Constraint<T> => ({ $lt: value });
|
70
|
+
export const lte = <T extends ComparableType>(value: T): Constraint<T> => ({ $le: value });
|
71
|
+
export const le = <T extends ComparableType>(value: T): Constraint<T> => ({ $le: value });
|
72
|
+
export const exists = (column: string): Constraint<string> => ({ $exists: column });
|
73
|
+
export const notExists = (column: string): Constraint<string> => ({ $notExists: column });
|
74
|
+
export const startsWith = (value: string): Constraint<string> => ({ $startsWith: value });
|
75
|
+
export const endsWith = (value: string): Constraint<string> => ({ $endsWith: value });
|
76
|
+
export const pattern = (value: string): Constraint<string> => ({ $pattern: value });
|
77
|
+
export const is = <T>(value: T): Constraint<T> => ({ $is: value });
|
78
|
+
export const isNot = <T>(value: T): Constraint<T> => ({ $isNot: value });
|
79
|
+
export const contains = <T>(value: T): Constraint<T> => ({ $contains: value });
|
68
80
|
|
69
81
|
// TODO: these can only be applied to columns of type "multiple"
|
70
|
-
export const includes = (value: string): Constraint<string> => ({
|
71
|
-
export const includesSubstring = (value: string): Constraint<string> => ({
|
72
|
-
export const includesPattern = (value: string): Constraint<string> => ({
|
73
|
-
export const includesAll = (value: string): Constraint<string> => ({
|
82
|
+
export const includes = (value: string): Constraint<string> => ({ $includes: value });
|
83
|
+
export const includesSubstring = (value: string): Constraint<string> => ({ $includesSubstring: value });
|
84
|
+
export const includesPattern = (value: string): Constraint<string> => ({ $includesPattern: value });
|
85
|
+
export const includesAll = (value: string): Constraint<string> => ({ $includesAll: value });
|
74
86
|
|
75
87
|
type FilterConstraints<T> = {
|
76
|
-
[key in keyof T]?: T[key] extends Record<string, any> ? FilterConstraints<T[key]> : T[key] |
|
88
|
+
[key in keyof T]?: T[key] extends Record<string, any> ? FilterConstraints<T[key]> : T[key] | DeepConstraint<T[key]>;
|
77
89
|
};
|
78
90
|
|
79
91
|
type BulkQueryOptions<T> = {
|
@@ -92,11 +104,11 @@ export class Query<T, R = T> {
|
|
92
104
|
table: string;
|
93
105
|
repository: Repository<T>;
|
94
106
|
|
95
|
-
readonly
|
96
|
-
readonly
|
97
|
-
readonly
|
98
|
-
readonly
|
99
|
-
readonly
|
107
|
+
readonly $any?: QueryOrConstraint<T, R>[];
|
108
|
+
readonly $all?: QueryOrConstraint<T, R>[];
|
109
|
+
readonly $not?: QueryOrConstraint<T, R>[];
|
110
|
+
readonly $none?: QueryOrConstraint<T, R>[];
|
111
|
+
readonly $sort?: Record<string, SortDirection>;
|
100
112
|
|
101
113
|
constructor(repository: Repository<T> | null, table: string, data: Partial<Query<T, R>>, parent?: Query<T, R>) {
|
102
114
|
if (repository) {
|
@@ -108,11 +120,11 @@ export class Query<T, R = T> {
|
|
108
120
|
|
109
121
|
// For some reason Object.assign(this, parent) didn't work in this case
|
110
122
|
// so doing all this manually:
|
111
|
-
this
|
112
|
-
this
|
113
|
-
this
|
114
|
-
this
|
115
|
-
this
|
123
|
+
this.$any = parent?.$any;
|
124
|
+
this.$all = parent?.$all;
|
125
|
+
this.$not = parent?.$not;
|
126
|
+
this.$none = parent?.$none;
|
127
|
+
this.$sort = parent?.$sort;
|
116
128
|
|
117
129
|
Object.assign(this, data);
|
118
130
|
// These bindings are used to support deconstructing
|
@@ -123,6 +135,9 @@ export class Query<T, R = T> {
|
|
123
135
|
this.filter = this.filter.bind(this);
|
124
136
|
this.sort = this.sort.bind(this);
|
125
137
|
this.none = this.none.bind(this);
|
138
|
+
|
139
|
+
Object.defineProperty(this, 'table', { enumerable: false });
|
140
|
+
Object.defineProperty(this, 'repository', { enumerable: false });
|
126
141
|
}
|
127
142
|
|
128
143
|
any(...queries: Query<T, R>[]): Query<T, R> {
|
@@ -130,7 +145,7 @@ export class Query<T, R = T> {
|
|
130
145
|
this.repository,
|
131
146
|
this.table,
|
132
147
|
{
|
133
|
-
|
148
|
+
$any: (this.$any || []).concat(queries)
|
134
149
|
},
|
135
150
|
this
|
136
151
|
);
|
@@ -141,7 +156,7 @@ export class Query<T, R = T> {
|
|
141
156
|
this.repository,
|
142
157
|
this.table,
|
143
158
|
{
|
144
|
-
|
159
|
+
$all: (this.$all || []).concat(queries)
|
145
160
|
},
|
146
161
|
this
|
147
162
|
);
|
@@ -152,7 +167,7 @@ export class Query<T, R = T> {
|
|
152
167
|
this.repository,
|
153
168
|
this.table,
|
154
169
|
{
|
155
|
-
|
170
|
+
$not: (this.$not || []).concat(queries)
|
156
171
|
},
|
157
172
|
this
|
158
173
|
);
|
@@ -163,14 +178,14 @@ export class Query<T, R = T> {
|
|
163
178
|
this.repository,
|
164
179
|
this.table,
|
165
180
|
{
|
166
|
-
|
181
|
+
$none: (this.$none || []).concat(queries)
|
167
182
|
},
|
168
183
|
this
|
169
184
|
);
|
170
185
|
}
|
171
186
|
|
172
187
|
filter(constraints: FilterConstraints<T>): Query<T, R>;
|
173
|
-
filter<F extends keyof T>(column: F, value: FilterConstraints<T[F]> |
|
188
|
+
filter<F extends keyof T>(column: F, value: FilterConstraints<T[F]> | DeepConstraint<T[F]>): Query<T, R>;
|
174
189
|
filter(a: any, b?: any): Query<T, R> {
|
175
190
|
if (arguments.length === 1) {
|
176
191
|
const constraints = a as FilterConstraints<T>;
|
@@ -182,7 +197,7 @@ export class Query<T, R = T> {
|
|
182
197
|
this.repository,
|
183
198
|
this.table,
|
184
199
|
{
|
185
|
-
|
200
|
+
$all: (this.$all || []).concat(queries)
|
186
201
|
},
|
187
202
|
this
|
188
203
|
);
|
@@ -193,7 +208,7 @@ export class Query<T, R = T> {
|
|
193
208
|
this.repository,
|
194
209
|
this.table,
|
195
210
|
{
|
196
|
-
|
211
|
+
$all: (this.$all || []).concat({ [column]: value })
|
197
212
|
},
|
198
213
|
this
|
199
214
|
);
|
@@ -201,12 +216,12 @@ export class Query<T, R = T> {
|
|
201
216
|
}
|
202
217
|
|
203
218
|
sort<F extends keyof T>(column: F, direction: SortDirection): Query<T, R> {
|
204
|
-
const sort = { ...this
|
219
|
+
const sort = { ...this.$sort, [column]: direction };
|
205
220
|
const q = new Query<T, R>(
|
206
221
|
this.repository,
|
207
222
|
this.table,
|
208
223
|
{
|
209
|
-
|
224
|
+
$sort: sort
|
210
225
|
},
|
211
226
|
this
|
212
227
|
);
|
@@ -236,19 +251,6 @@ export class Query<T, R = T> {
|
|
236
251
|
// TODO
|
237
252
|
return this;
|
238
253
|
}
|
239
|
-
|
240
|
-
toJSON() {
|
241
|
-
const _filter = {
|
242
|
-
_any: this._any,
|
243
|
-
_all: this._all,
|
244
|
-
_not: this._not,
|
245
|
-
_none: this._none
|
246
|
-
};
|
247
|
-
return {
|
248
|
-
_filter: Object.values(_filter).some(Boolean) ? _filter : undefined,
|
249
|
-
_sort: this._sort
|
250
|
-
};
|
251
|
-
}
|
252
254
|
}
|
253
255
|
|
254
256
|
export abstract class Repository<T> extends Query<T, Selectable<T>> {
|
@@ -300,13 +302,13 @@ export class RestRepository<T> extends Repository<T> {
|
|
300
302
|
}
|
301
303
|
|
302
304
|
async request(method: string, path: string, body?: unknown) {
|
303
|
-
const {
|
304
|
-
const resp: Response = await this.fetch(`${
|
305
|
+
const { databaseURL } = this.client.options;
|
306
|
+
const resp: Response = await this.fetch(`${databaseURL}${path}`, {
|
305
307
|
method,
|
306
308
|
headers: {
|
307
309
|
Accept: '*/*',
|
308
310
|
'Content-Type': 'application/json',
|
309
|
-
Authorization: `Bearer ${this.client.options.
|
311
|
+
Authorization: `Bearer ${this.client.options.apiKey}`
|
310
312
|
},
|
311
313
|
body: JSON.stringify(body)
|
312
314
|
});
|
@@ -333,7 +335,14 @@ export class RestRepository<T> extends Repository<T> {
|
|
333
335
|
}
|
334
336
|
|
335
337
|
async create(object: T): Promise<T> {
|
336
|
-
const
|
338
|
+
const body = { ...object } as Record<string, unknown>;
|
339
|
+
for (const key of Object.keys(body)) {
|
340
|
+
const value = body[key];
|
341
|
+
if (value && typeof value === 'object' && typeof (value as Record<string, unknown>)._id === 'string') {
|
342
|
+
body[key] = (value as XataRecord)._id;
|
343
|
+
}
|
344
|
+
}
|
345
|
+
const obj = await this.request('POST', `/tables/${this.table}/data`, body);
|
337
346
|
return this.client.initObject(this.table, obj);
|
338
347
|
}
|
339
348
|
|
@@ -357,7 +366,17 @@ export class RestRepository<T> extends Repository<T> {
|
|
357
366
|
}
|
358
367
|
|
359
368
|
async query<R>(query: Query<T, R>): Promise<R[]> {
|
360
|
-
const
|
369
|
+
const filter = {
|
370
|
+
$any: query.$any,
|
371
|
+
$all: query.$all,
|
372
|
+
$not: query.$not,
|
373
|
+
$none: query.$none
|
374
|
+
};
|
375
|
+
const body = {
|
376
|
+
filter: Object.values(filter).some(Boolean) ? filter : undefined,
|
377
|
+
sort: query.$sort
|
378
|
+
};
|
379
|
+
const result = await this.request('POST', `/tables/${this.table}/query`, body);
|
361
380
|
return result.records.map((record: object) => this.client.initObject(this.table, record));
|
362
381
|
}
|
363
382
|
}
|
@@ -374,8 +393,8 @@ export class RestRespositoryFactory implements RepositoryFactory {
|
|
374
393
|
|
375
394
|
export type XataClientOptions = {
|
376
395
|
fetch?: unknown;
|
377
|
-
|
378
|
-
|
396
|
+
databaseURL: string;
|
397
|
+
apiKey: string;
|
379
398
|
repositoryFactory?: RepositoryFactory;
|
380
399
|
};
|
381
400
|
|