@raphiniert/ra-data-postgrest 2.0.0-alpha.0 → 2.0.0-alpha.3
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/CHANGELOG.md +137 -41
- package/IDEAS.md +46 -0
- package/README.md +120 -55
- package/esm/index.d.ts +58 -7
- package/esm/index.js +229 -221
- package/esm/urlBuilder.d.ts +7 -3
- package/esm/urlBuilder.js +87 -38
- package/lib/index.d.ts +58 -7
- package/lib/index.js +234 -221
- package/lib/urlBuilder.d.ts +7 -3
- package/lib/urlBuilder.js +87 -38
- package/package.json +11 -6
- package/src/index.ts +237 -125
- package/src/urlBuilder.ts +100 -43
package/src/index.ts
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
fetchUtils,
|
|
3
|
+
DataProvider,
|
|
4
|
+
GetListParams,
|
|
5
|
+
GetOneParams,
|
|
6
|
+
GetManyParams,
|
|
7
|
+
GetManyReferenceParams,
|
|
8
|
+
UpdateParams,
|
|
9
|
+
UpdateManyParams,
|
|
10
|
+
CreateParams,
|
|
11
|
+
DeleteParams,
|
|
12
|
+
DeleteManyParams,
|
|
13
|
+
} from 'ra-core';
|
|
2
14
|
import {
|
|
3
15
|
PrimaryKey,
|
|
4
16
|
PostgRestOperator,
|
|
@@ -12,6 +24,8 @@ import {
|
|
|
12
24
|
decodeId,
|
|
13
25
|
isCompoundKey,
|
|
14
26
|
} from './urlBuilder';
|
|
27
|
+
import qs from 'qs';
|
|
28
|
+
|
|
15
29
|
/**
|
|
16
30
|
* Maps react-admin queries to a postgrest REST API
|
|
17
31
|
*
|
|
@@ -34,13 +48,24 @@ import {
|
|
|
34
48
|
* @example
|
|
35
49
|
*
|
|
36
50
|
* import * as React from 'react';
|
|
37
|
-
* import { Admin, Resource } from 'react-admin';
|
|
38
|
-
* import postgrestRestProvider
|
|
51
|
+
* import { Admin, Resource, fetchUtils } from 'react-admin';
|
|
52
|
+
* import postgrestRestProvider,
|
|
53
|
+
* { IDataProviderConfig,
|
|
54
|
+
* defaultPrimaryKeys,
|
|
55
|
+
* defaultSchema } from '@raphiniert/ra-data-postgrest';
|
|
39
56
|
*
|
|
40
57
|
* import { PostList } from './posts';
|
|
41
58
|
*
|
|
59
|
+
* const config: IDataProviderConfig = {
|
|
60
|
+
* apiUrl: 'http://path.to.my.api/',
|
|
61
|
+
* httpClient: fetchUtils.fetchJson,
|
|
62
|
+
* defaultListOp: 'eq',
|
|
63
|
+
* primaryKeys: defaultPrimaryKeys,
|
|
64
|
+
* schema: defaultSchema
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
42
67
|
* const App = () => (
|
|
43
|
-
* <Admin dataProvider={postgrestRestProvider(
|
|
68
|
+
* <Admin dataProvider={postgrestRestProvider(config)}>
|
|
44
69
|
* <Resource name="posts" list={PostList} />
|
|
45
70
|
* </Admin>
|
|
46
71
|
* );
|
|
@@ -48,40 +73,79 @@ import {
|
|
|
48
73
|
* export default App;
|
|
49
74
|
*/
|
|
50
75
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
export
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
76
|
+
export type MetaOption = string | undefined;
|
|
77
|
+
|
|
78
|
+
export const defaultPrimaryKeys = new Map<string, PrimaryKey>();
|
|
79
|
+
|
|
80
|
+
export const defaultSchema = () => '';
|
|
81
|
+
|
|
82
|
+
export interface IDataProviderConfig {
|
|
83
|
+
apiUrl: string;
|
|
84
|
+
httpClient: (string, Options) => Promise<any>;
|
|
85
|
+
defaultListOp: PostgRestOperator;
|
|
86
|
+
primaryKeys: Map<string, PrimaryKey>;
|
|
87
|
+
schema: () => string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const useCustomSchema = (
|
|
91
|
+
schema: () => string,
|
|
92
|
+
metaSchema: MetaOption,
|
|
93
|
+
method: string
|
|
94
|
+
) => {
|
|
95
|
+
let funcHeaderSchema = schema;
|
|
96
|
+
if (metaSchema !== undefined) {
|
|
97
|
+
funcHeaderSchema = () => metaSchema;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (funcHeaderSchema().length > 0) {
|
|
101
|
+
let schemaHeader = '';
|
|
102
|
+
if (['GET', 'HEAD'].includes(method)) {
|
|
103
|
+
schemaHeader = 'Accept-Profile';
|
|
104
|
+
} else if (['POST', 'PATCH', 'PUT', 'DELETE'].includes(method)) {
|
|
105
|
+
schemaHeader = 'Content-Profile';
|
|
106
|
+
} else return {};
|
|
107
|
+
|
|
108
|
+
return { [schemaHeader]: funcHeaderSchema() };
|
|
109
|
+
} else return {};
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export default (config: IDataProviderConfig): DataProvider => ({
|
|
113
|
+
getList: (resource, params: Partial<GetListParams> = {}) => {
|
|
114
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
61
115
|
|
|
62
116
|
const { page, perPage } = params.pagination;
|
|
63
|
-
const { field, order } = params.sort;
|
|
64
|
-
const
|
|
117
|
+
const { field, order } = params.sort || {};
|
|
118
|
+
const { filter, select } = parseFilters(params, config.defaultListOp);
|
|
119
|
+
const metaSchema = params.meta?.schema;
|
|
65
120
|
|
|
66
|
-
|
|
67
|
-
order: getOrderBy(field, order, primaryKey),
|
|
121
|
+
let query = {
|
|
68
122
|
offset: String((page - 1) * perPage),
|
|
69
123
|
limit: String(perPage),
|
|
70
124
|
// append filters
|
|
71
|
-
...
|
|
125
|
+
...filter,
|
|
72
126
|
};
|
|
73
127
|
|
|
128
|
+
if (field) {
|
|
129
|
+
query.order = getOrderBy(field, order, primaryKey);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (select) {
|
|
133
|
+
query.select = select;
|
|
134
|
+
}
|
|
135
|
+
|
|
74
136
|
// add header that Content-Range is in returned header
|
|
75
137
|
const options = {
|
|
76
138
|
headers: new Headers({
|
|
77
139
|
Accept: 'application/json',
|
|
78
140
|
Prefer: 'count=exact',
|
|
141
|
+
...(params.meta?.headers || {}),
|
|
142
|
+
...useCustomSchema(config.schema, metaSchema, 'GET'),
|
|
79
143
|
}),
|
|
80
144
|
};
|
|
81
145
|
|
|
82
|
-
const url = `${apiUrl}/${resource}?${
|
|
146
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
83
147
|
|
|
84
|
-
return httpClient(url, options).then(({ headers, json }) => {
|
|
148
|
+
return config.httpClient(url, options).then(({ headers, json }) => {
|
|
85
149
|
if (!headers.has('content-range')) {
|
|
86
150
|
throw new Error(
|
|
87
151
|
`The Content-Range header is missing in the HTTP Response. The postgREST data provider expects
|
|
@@ -99,68 +163,92 @@ export default (
|
|
|
99
163
|
});
|
|
100
164
|
},
|
|
101
165
|
|
|
102
|
-
getOne: (resource, params) => {
|
|
103
|
-
const id = params
|
|
104
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
166
|
+
getOne: (resource, params: Partial<GetOneParams> = {}) => {
|
|
167
|
+
const { id, meta } = params;
|
|
168
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
105
169
|
|
|
106
|
-
const query = getQuery(primaryKey, id, resource);
|
|
170
|
+
const query = getQuery(primaryKey, id, resource, meta);
|
|
107
171
|
|
|
108
|
-
const url = `${apiUrl}/${resource}?${query}`;
|
|
172
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
173
|
+
const metaSchema = params.meta?.schema;
|
|
109
174
|
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
175
|
+
return config
|
|
176
|
+
.httpClient(url, {
|
|
177
|
+
headers: new Headers({
|
|
178
|
+
accept: 'application/vnd.pgrst.object+json',
|
|
179
|
+
...(params.meta?.headers || {}),
|
|
180
|
+
...useCustomSchema(config.schema, metaSchema, 'GET'),
|
|
181
|
+
}),
|
|
182
|
+
})
|
|
183
|
+
.then(({ json }) => ({
|
|
184
|
+
data: dataWithId(json, primaryKey),
|
|
185
|
+
}));
|
|
117
186
|
},
|
|
118
187
|
|
|
119
|
-
getMany: (resource, params) => {
|
|
188
|
+
getMany: (resource, params: Partial<GetManyParams> = {}) => {
|
|
120
189
|
const ids = params.ids;
|
|
121
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
190
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
122
191
|
|
|
123
|
-
const query = getQuery(primaryKey, ids, resource);
|
|
192
|
+
const query = getQuery(primaryKey, ids, resource, params.meta);
|
|
124
193
|
|
|
125
|
-
const url = `${apiUrl}/${resource}?${query}`;
|
|
194
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
195
|
+
const metaSchema = params.meta?.schema;
|
|
126
196
|
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
|
|
197
|
+
return config
|
|
198
|
+
.httpClient(url, {
|
|
199
|
+
headers: new Headers({
|
|
200
|
+
...useCustomSchema(config.schema, metaSchema, 'GET'),
|
|
201
|
+
}),
|
|
202
|
+
})
|
|
203
|
+
.then(({ json }) => ({
|
|
204
|
+
data: json.map(data => dataWithId(data, primaryKey)),
|
|
205
|
+
}));
|
|
130
206
|
},
|
|
131
207
|
|
|
132
|
-
getManyReference: (
|
|
208
|
+
getManyReference: (
|
|
209
|
+
resource,
|
|
210
|
+
params: Partial<GetManyReferenceParams> = {}
|
|
211
|
+
) => {
|
|
133
212
|
const { page, perPage } = params.pagination;
|
|
134
213
|
const { field, order } = params.sort;
|
|
135
|
-
const parsedFilter = parseFilters(params.filter, defaultListOp);
|
|
136
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
137
214
|
|
|
138
|
-
const
|
|
215
|
+
const { filter, select } = parseFilters(params, config.defaultListOp);
|
|
216
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
217
|
+
|
|
218
|
+
const metaSchema = params.meta?.schema;
|
|
219
|
+
|
|
220
|
+
let query = params.target
|
|
139
221
|
? {
|
|
140
222
|
[params.target]: `eq.${params.id}`,
|
|
141
223
|
order: getOrderBy(field, order, primaryKey),
|
|
142
224
|
offset: String((page - 1) * perPage),
|
|
143
225
|
limit: String(perPage),
|
|
144
|
-
...
|
|
226
|
+
...filter,
|
|
145
227
|
}
|
|
146
228
|
: {
|
|
147
229
|
order: getOrderBy(field, order, primaryKey),
|
|
148
230
|
offset: String((page - 1) * perPage),
|
|
149
231
|
limit: String(perPage),
|
|
150
|
-
...
|
|
232
|
+
...filter,
|
|
151
233
|
};
|
|
152
234
|
|
|
235
|
+
if (select) {
|
|
236
|
+
query.select = select;
|
|
237
|
+
}
|
|
238
|
+
|
|
153
239
|
// add header that Content-Range is in returned header
|
|
154
240
|
const options = {
|
|
155
241
|
headers: new Headers({
|
|
156
242
|
Accept: 'application/json',
|
|
157
243
|
Prefer: 'count=exact',
|
|
244
|
+
...(params.meta?.headers || {}),
|
|
245
|
+
...useCustomSchema(config.schema, metaSchema, 'GET'),
|
|
158
246
|
}),
|
|
159
247
|
};
|
|
160
248
|
|
|
161
|
-
const url = `${apiUrl}/${resource}?${
|
|
249
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
162
250
|
|
|
163
|
-
return httpClient(url, options).then(({ headers, json }) => {
|
|
251
|
+
return config.httpClient(url, options).then(({ headers, json }) => {
|
|
164
252
|
if (!headers.has('content-range')) {
|
|
165
253
|
throw new Error(
|
|
166
254
|
`The Content-Range header is missing in the HTTP Response. The postgREST data provider expects
|
|
@@ -178,35 +266,40 @@ export default (
|
|
|
178
266
|
});
|
|
179
267
|
},
|
|
180
268
|
|
|
181
|
-
update: (resource, params) => {
|
|
182
|
-
const { id, data } = params;
|
|
183
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
269
|
+
update: (resource, params: Partial<UpdateParams> = {}) => {
|
|
270
|
+
const { id, data, meta } = params;
|
|
271
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
184
272
|
|
|
185
|
-
const query = getQuery(primaryKey, id, resource);
|
|
273
|
+
const query = getQuery(primaryKey, id, resource, meta);
|
|
186
274
|
|
|
187
275
|
const primaryKeyData = getKeyData(primaryKey, data);
|
|
188
276
|
|
|
189
|
-
const url = `${apiUrl}/${resource}?${query}`;
|
|
277
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
278
|
+
const metaSchema = params.meta?.schema;
|
|
190
279
|
|
|
191
280
|
const body = JSON.stringify({
|
|
192
281
|
...data,
|
|
193
282
|
...primaryKeyData,
|
|
194
283
|
});
|
|
195
284
|
|
|
196
|
-
return
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
285
|
+
return config
|
|
286
|
+
.httpClient(url, {
|
|
287
|
+
method: 'PATCH',
|
|
288
|
+
headers: new Headers({
|
|
289
|
+
Accept: 'application/vnd.pgrst.object+json',
|
|
290
|
+
Prefer: 'return=representation',
|
|
291
|
+
'Content-Type': 'application/json',
|
|
292
|
+
...(params.meta?.headers || {}),
|
|
293
|
+
...useCustomSchema(config.schema, metaSchema, 'PATCH'),
|
|
294
|
+
}),
|
|
295
|
+
body,
|
|
296
|
+
})
|
|
297
|
+
.then(({ json }) => ({ data: dataWithId(json, primaryKey) }));
|
|
205
298
|
},
|
|
206
299
|
|
|
207
|
-
updateMany: (resource, params) => {
|
|
300
|
+
updateMany: (resource, params: Partial<UpdateManyParams> = {}) => {
|
|
208
301
|
const ids = params.ids;
|
|
209
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
302
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
210
303
|
|
|
211
304
|
const body = JSON.stringify(
|
|
212
305
|
params.ids.map(id => {
|
|
@@ -229,75 +322,94 @@ export default (
|
|
|
229
322
|
})
|
|
230
323
|
);
|
|
231
324
|
|
|
232
|
-
const url = `${apiUrl}/${resource}`;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
325
|
+
const url = `${config.apiUrl}/${resource}`;
|
|
326
|
+
const metaSchema = params.meta?.schema;
|
|
327
|
+
|
|
328
|
+
return config
|
|
329
|
+
.httpClient(url, {
|
|
330
|
+
method: 'PATCH',
|
|
331
|
+
headers: new Headers({
|
|
332
|
+
Prefer: 'return=representation',
|
|
333
|
+
'Content-Type': 'application/json',
|
|
334
|
+
...(params.meta?.headers || {}),
|
|
335
|
+
...useCustomSchema(config.schema, metaSchema, 'PATCH'),
|
|
336
|
+
}),
|
|
337
|
+
body,
|
|
338
|
+
})
|
|
339
|
+
.then(({ json }) => ({
|
|
340
|
+
data: json.map(data => encodeId(data, primaryKey)),
|
|
341
|
+
}));
|
|
244
342
|
},
|
|
245
343
|
|
|
246
|
-
create: (resource, params) => {
|
|
247
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
return
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
|
|
344
|
+
create: (resource, params: Partial<CreateParams> = {}) => {
|
|
345
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
346
|
+
const url = `${config.apiUrl}/${resource}`;
|
|
347
|
+
const metaSchema = params.meta?.schema;
|
|
348
|
+
|
|
349
|
+
return config
|
|
350
|
+
.httpClient(url, {
|
|
351
|
+
method: 'POST',
|
|
352
|
+
headers: new Headers({
|
|
353
|
+
Accept: 'application/vnd.pgrst.object+json',
|
|
354
|
+
Prefer: 'return=representation',
|
|
355
|
+
'Content-Type': 'application/json',
|
|
356
|
+
...(params.meta?.headers || {}),
|
|
357
|
+
...useCustomSchema(config.schema, metaSchema, 'POST'),
|
|
358
|
+
}),
|
|
359
|
+
body: JSON.stringify(params.data),
|
|
360
|
+
})
|
|
361
|
+
.then(({ json }) => ({
|
|
362
|
+
data: {
|
|
363
|
+
...json,
|
|
364
|
+
id: encodeId(json, primaryKey),
|
|
365
|
+
},
|
|
366
|
+
}));
|
|
265
367
|
},
|
|
266
368
|
|
|
267
|
-
delete: (resource, params) => {
|
|
268
|
-
const id = params
|
|
269
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
270
|
-
|
|
271
|
-
const query = getQuery(primaryKey, id, resource);
|
|
272
|
-
|
|
273
|
-
const url = `${apiUrl}/${resource}?${query}`;
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
369
|
+
delete: (resource, params: Partial<DeleteParams> = {}) => {
|
|
370
|
+
const { id, meta } = params;
|
|
371
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
372
|
+
|
|
373
|
+
const query = getQuery(primaryKey, id, resource, meta);
|
|
374
|
+
|
|
375
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
376
|
+
const metaSchema = params.meta?.schema;
|
|
377
|
+
|
|
378
|
+
return config
|
|
379
|
+
.httpClient(url, {
|
|
380
|
+
method: 'DELETE',
|
|
381
|
+
headers: new Headers({
|
|
382
|
+
Accept: 'application/vnd.pgrst.object+json',
|
|
383
|
+
Prefer: 'return=representation',
|
|
384
|
+
'Content-Type': 'application/json',
|
|
385
|
+
...(params.meta?.headers || {}),
|
|
386
|
+
...useCustomSchema(config.schema, metaSchema, 'DELETE'),
|
|
387
|
+
}),
|
|
388
|
+
})
|
|
389
|
+
.then(({ json }) => ({ data: dataWithId(json, primaryKey) }));
|
|
283
390
|
},
|
|
284
391
|
|
|
285
|
-
deleteMany: (resource, params) => {
|
|
286
|
-
const ids = params
|
|
287
|
-
const primaryKey = getPrimaryKey(resource, primaryKeys);
|
|
392
|
+
deleteMany: (resource, params: Partial<DeleteManyParams> = {}) => {
|
|
393
|
+
const { ids, meta } = params;
|
|
394
|
+
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
288
395
|
|
|
289
|
-
const query = getQuery(primaryKey, ids, resource);
|
|
396
|
+
const query = getQuery(primaryKey, ids, resource, meta);
|
|
290
397
|
|
|
291
|
-
const url = `${apiUrl}/${resource}?${query}`;
|
|
398
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
399
|
+
const metaSchema = params.meta?.schema;
|
|
292
400
|
|
|
293
|
-
return
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
401
|
+
return config
|
|
402
|
+
.httpClient(url, {
|
|
403
|
+
method: 'DELETE',
|
|
404
|
+
headers: new Headers({
|
|
405
|
+
Prefer: 'return=representation',
|
|
406
|
+
'Content-Type': 'application/json',
|
|
407
|
+
...(params.meta?.headers || {}),
|
|
408
|
+
...useCustomSchema(config.schema, metaSchema, 'DELETE'),
|
|
409
|
+
}),
|
|
410
|
+
})
|
|
411
|
+
.then(({ json }) => ({
|
|
412
|
+
data: json.map(data => encodeId(data, primaryKey)),
|
|
413
|
+
}));
|
|
302
414
|
},
|
|
303
415
|
});
|