@raphiniert/ra-data-postgrest 2.0.0-alpha.3 → 2.0.0
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 +22 -0
- package/esm/index.js +21 -27
- package/esm/urlBuilder.d.ts +4 -4
- package/esm/urlBuilder.js +61 -25
- package/lib/index.js +20 -26
- package/lib/urlBuilder.d.ts +4 -4
- package/lib/urlBuilder.js +68 -32
- package/package.json +9 -10
- package/src/index.ts +35 -42
- package/src/urlBuilder.ts +60 -27
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
Find all notable changes of this project in this file.
|
|
4
4
|
|
|
5
|
+
## v2.0.0 - 2023-12-29
|
|
6
|
+
### Improvements
|
|
7
|
+
- updated dependencies
|
|
8
|
+
|
|
9
|
+
### Fixes
|
|
10
|
+
- [#113](https://github.com/raphiniert-com/ra-data-postgrest/pull/113) remove {} value wrapping for cs/cd @[ruslantalpa](https://github.com/ruslantalpa)
|
|
11
|
+
|
|
12
|
+
### Breaking changes
|
|
13
|
+
- the fix in this version might break old versions, as the {} are removed. Thus, one needs to manually add the {} for cs/cd.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## v2.0.0-alpha.4 - 2023-10-23
|
|
17
|
+
### Improvements
|
|
18
|
+
- updated dependencies
|
|
19
|
+
|
|
20
|
+
### New feature
|
|
21
|
+
- [#100](https://github.com/raphiniert-com/ra-data-postgrest/pull/100) support "meta.columns" on all code paths (useful when the user does not have permissions on all the columns in which case doing select=* gives permissions errors) - @[ruslantalpa](https://github.com/ruslantalpa)
|
|
22
|
+
|
|
23
|
+
### Fixes
|
|
24
|
+
- [#50](https://github.com/raphiniert-com/ra-data-postgrest/issues/50) and [#88](https://github.com/raphiniert-com/ra-data-postgrest/issues/88) solved by [#100](https://github.com/raphiniert-com/ra-data-postgrest/pull/100) including other fixes - @[ruslantalpa](https://github.com/ruslantalpa)
|
|
25
|
+
|
|
26
|
+
|
|
5
27
|
## v2.0.0-alpha.3 - 2023-06-16
|
|
6
28
|
### Improvements
|
|
7
29
|
- updated dependencies
|
package/esm/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var __assign = (this && this.__assign) || function () {
|
|
|
9
9
|
};
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
|
-
import { getPrimaryKey, parseFilters, getOrderBy,
|
|
12
|
+
import { getPrimaryKey, parseFilters, getOrderBy, dataWithVirtualId, dataWithoutVirtualId, removePrimaryKey, getQuery, encodeId, } from './urlBuilder';
|
|
13
13
|
import qs from 'qs';
|
|
14
14
|
export var defaultPrimaryKeys = new Map();
|
|
15
15
|
export var defaultSchema = function () { return ''; };
|
|
@@ -61,7 +61,7 @@ export default (function (config) { return ({
|
|
|
61
61
|
throw new Error("The Content-Range header is missing in the HTTP Response. The postgREST data provider expects \n responses for lists of resources to contain this header with the total number of results to build \n the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?");
|
|
62
62
|
}
|
|
63
63
|
return {
|
|
64
|
-
data: json.map(function (obj) { return
|
|
64
|
+
data: json.map(function (obj) { return dataWithVirtualId(obj, primaryKey); }),
|
|
65
65
|
total: parseInt(headers.get('content-range').split('/').pop(), 10),
|
|
66
66
|
};
|
|
67
67
|
});
|
|
@@ -81,7 +81,7 @@ export default (function (config) { return ({
|
|
|
81
81
|
.then(function (_a) {
|
|
82
82
|
var json = _a.json;
|
|
83
83
|
return ({
|
|
84
|
-
data:
|
|
84
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
87
|
},
|
|
@@ -100,7 +100,7 @@ export default (function (config) { return ({
|
|
|
100
100
|
.then(function (_a) {
|
|
101
101
|
var json = _a.json;
|
|
102
102
|
return ({
|
|
103
|
-
data: json.map(function (data) { return
|
|
103
|
+
data: json.map(function (data) { return dataWithVirtualId(data, primaryKey); }),
|
|
104
104
|
});
|
|
105
105
|
});
|
|
106
106
|
},
|
|
@@ -129,7 +129,7 @@ export default (function (config) { return ({
|
|
|
129
129
|
throw new Error("The Content-Range header is missing in the HTTP Response. The postgREST data provider expects \n responses for lists of resources to contain this header with the total number of results to build \n the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?");
|
|
130
130
|
}
|
|
131
131
|
return {
|
|
132
|
-
data: json.map(function (data) { return
|
|
132
|
+
data: json.map(function (data) { return dataWithVirtualId(data, primaryKey); }),
|
|
133
133
|
total: parseInt(headers.get('content-range').split('/').pop(), 10),
|
|
134
134
|
};
|
|
135
135
|
});
|
|
@@ -140,10 +140,9 @@ export default (function (config) { return ({
|
|
|
140
140
|
var id = params.id, data = params.data, meta = params.meta;
|
|
141
141
|
var primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
142
142
|
var query = getQuery(primaryKey, id, resource, meta);
|
|
143
|
-
var primaryKeyData = getKeyData(primaryKey, data);
|
|
144
143
|
var url = "".concat(config.apiUrl, "/").concat(resource, "?").concat(qs.stringify(query));
|
|
145
144
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
146
|
-
var body = JSON.stringify(__assign(
|
|
145
|
+
var body = JSON.stringify(__assign({}, dataWithoutVirtualId(removePrimaryKey(data, primaryKey), primaryKey)));
|
|
147
146
|
return config
|
|
148
147
|
.httpClient(url, {
|
|
149
148
|
method: 'PATCH',
|
|
@@ -152,29 +151,19 @@ export default (function (config) { return ({
|
|
|
152
151
|
})
|
|
153
152
|
.then(function (_a) {
|
|
154
153
|
var json = _a.json;
|
|
155
|
-
return ({
|
|
154
|
+
return ({
|
|
155
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
156
|
+
});
|
|
156
157
|
});
|
|
157
158
|
},
|
|
158
159
|
updateMany: function (resource, params) {
|
|
159
160
|
var _a, _b;
|
|
160
161
|
if (params === void 0) { params = {}; }
|
|
161
|
-
var ids = params.ids;
|
|
162
|
+
var ids = params.ids, meta = params.meta, data = params.data;
|
|
162
163
|
var primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
163
|
-
var
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
var primaryKeyData = {};
|
|
167
|
-
if (isCompoundKey(primaryKey)) {
|
|
168
|
-
primaryKey.forEach(function (key, index) {
|
|
169
|
-
primaryKeyData[key] = primaryKeyParams[index];
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
primaryKeyData[primaryKey[0]] = primaryKeyParams[0];
|
|
174
|
-
}
|
|
175
|
-
return __assign(__assign({}, data), primaryKeyData);
|
|
176
|
-
}));
|
|
177
|
-
var url = "".concat(config.apiUrl, "/").concat(resource);
|
|
164
|
+
var query = getQuery(primaryKey, ids, resource, meta);
|
|
165
|
+
var url = "".concat(config.apiUrl, "/").concat(resource, "?").concat(qs.stringify(query));
|
|
166
|
+
var body = JSON.stringify(__assign({}, dataWithoutVirtualId(removePrimaryKey(data, primaryKey), primaryKey)));
|
|
178
167
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
179
168
|
return config
|
|
180
169
|
.httpClient(url, {
|
|
@@ -192,14 +181,17 @@ export default (function (config) { return ({
|
|
|
192
181
|
create: function (resource, params) {
|
|
193
182
|
var _a, _b;
|
|
194
183
|
if (params === void 0) { params = {}; }
|
|
184
|
+
var meta = params.meta;
|
|
195
185
|
var primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
196
|
-
var
|
|
186
|
+
var query = getQuery(primaryKey, undefined, resource, meta);
|
|
187
|
+
var queryStr = qs.stringify(query);
|
|
188
|
+
var url = "".concat(config.apiUrl, "/").concat(resource).concat(queryStr.length > 0 ? '?' : '').concat(queryStr);
|
|
197
189
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
198
190
|
return config
|
|
199
191
|
.httpClient(url, {
|
|
200
192
|
method: 'POST',
|
|
201
193
|
headers: new Headers(__assign(__assign({ Accept: 'application/vnd.pgrst.object+json', Prefer: 'return=representation', 'Content-Type': 'application/json' }, (((_b = params.meta) === null || _b === void 0 ? void 0 : _b.headers) || {})), useCustomSchema(config.schema, metaSchema, 'POST'))),
|
|
202
|
-
body: JSON.stringify(params.data),
|
|
194
|
+
body: JSON.stringify(dataWithoutVirtualId(params.data, primaryKey)),
|
|
203
195
|
})
|
|
204
196
|
.then(function (_a) {
|
|
205
197
|
var json = _a.json;
|
|
@@ -223,7 +215,9 @@ export default (function (config) { return ({
|
|
|
223
215
|
})
|
|
224
216
|
.then(function (_a) {
|
|
225
217
|
var json = _a.json;
|
|
226
|
-
return ({
|
|
218
|
+
return ({
|
|
219
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
220
|
+
});
|
|
227
221
|
});
|
|
228
222
|
},
|
|
229
223
|
deleteMany: function (resource, params) {
|
package/esm/urlBuilder.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export type PrimaryKey = Array<string>;
|
|
|
14
14
|
export declare const getPrimaryKey: (resource: string, primaryKeys: Map<string, PrimaryKey>) => PrimaryKey;
|
|
15
15
|
export declare const decodeId: (id: Identifier, primaryKey: PrimaryKey) => string[] | number[];
|
|
16
16
|
export declare const encodeId: (data: any, primaryKey: PrimaryKey) => Identifier;
|
|
17
|
-
export declare const
|
|
18
|
-
export declare const
|
|
19
|
-
export declare const
|
|
20
|
-
export declare const
|
|
17
|
+
export declare const removePrimaryKey: (data: any, primaryKey: PrimaryKey) => any;
|
|
18
|
+
export declare const dataWithVirtualId: (data: any, primaryKey: PrimaryKey) => any;
|
|
19
|
+
export declare const dataWithoutVirtualId: (data: any, primaryKey: PrimaryKey) => any;
|
|
20
|
+
export declare const getQuery: (primaryKey: PrimaryKey, ids: Identifier | Array<Identifier> | undefined, resource: string, meta?: any) => any;
|
|
21
21
|
export declare const getOrderBy: (field: string, order: string, primaryKey: PrimaryKey) => string;
|
|
22
22
|
export {};
|
package/esm/urlBuilder.js
CHANGED
|
@@ -9,6 +9,17 @@ var __assign = (this && this.__assign) || function () {
|
|
|
9
9
|
};
|
|
10
10
|
return __assign.apply(this, arguments);
|
|
11
11
|
};
|
|
12
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
13
|
+
var t = {};
|
|
14
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
15
|
+
t[p] = s[p];
|
|
16
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
17
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
18
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
19
|
+
t[p[i]] = s[p[i]];
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
};
|
|
12
23
|
/**
|
|
13
24
|
* List of all possible operators in PostgRest
|
|
14
25
|
* (https://postgrest.org/en/stable/api.html#operators)
|
|
@@ -42,25 +53,53 @@ var postgrestOperators = [
|
|
|
42
53
|
'or',
|
|
43
54
|
'and',
|
|
44
55
|
];
|
|
56
|
+
var isObject = function (obj) {
|
|
57
|
+
return typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
|
|
58
|
+
};
|
|
59
|
+
var resolveKeys = function (filter, keys) {
|
|
60
|
+
var result = filter[keys[0]];
|
|
61
|
+
for (var i = 1; i < keys.length; ++i) {
|
|
62
|
+
result = result[keys[i]];
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
45
66
|
export var parseFilters = function (params, defaultListOp) {
|
|
46
67
|
var filter = params.filter, _a = params.meta, meta = _a === void 0 ? {} : _a;
|
|
47
68
|
var result = {};
|
|
48
69
|
result.filter = {};
|
|
49
70
|
Object.keys(filter).forEach(function (key) {
|
|
50
71
|
// key: the name of the object key
|
|
72
|
+
var keyArray = [key];
|
|
73
|
+
var values;
|
|
74
|
+
// in case of a nested object selection in a text field
|
|
75
|
+
// RA returns object{ object } structure which is resolved here
|
|
76
|
+
// see issue https://github.com/raphiniert-com/ra-data-postgrest/issues/58
|
|
77
|
+
if (key.split('@')[0] !== '' && isObject(filter[key])) {
|
|
78
|
+
var innerVal = filter[key];
|
|
79
|
+
do {
|
|
80
|
+
var inner = resolveKeys(filter, keyArray);
|
|
81
|
+
var innerKey = Object.keys(inner)[0];
|
|
82
|
+
keyArray.push(innerKey);
|
|
83
|
+
innerVal = inner[innerKey];
|
|
84
|
+
} while (isObject(innerVal));
|
|
85
|
+
key = keyArray.join('.');
|
|
86
|
+
values = [innerVal];
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
values = [filter[key]];
|
|
90
|
+
}
|
|
51
91
|
var splitKey = key.split('@');
|
|
52
92
|
var operation = splitKey.length == 2
|
|
53
93
|
? splitKey[1]
|
|
54
94
|
: defaultListOp;
|
|
55
|
-
var values;
|
|
56
95
|
if (['like', 'ilike'].includes(operation)) {
|
|
57
96
|
// we split the search term in words
|
|
58
|
-
values = filter
|
|
97
|
+
values = resolveKeys(filter, keyArray).trim().split(/\s+/);
|
|
59
98
|
}
|
|
60
99
|
// CASE: Logical operator
|
|
61
100
|
else if (['or', 'and'].includes(operation)) {
|
|
62
101
|
// we extract each value entries and make it dot separated string.
|
|
63
|
-
var subFilter = parseFilters({ filter: filter
|
|
102
|
+
var subFilter = parseFilters({ filter: resolveKeys(filter, keyArray) }, defaultListOp).filter;
|
|
64
103
|
// something like { "age@lt": 18 } and { "age@gt": 21 }
|
|
65
104
|
var filterExpressions_1 = [];
|
|
66
105
|
Object.entries(subFilter).forEach(function (_a) {
|
|
@@ -73,9 +112,6 @@ export var parseFilters = function (params, defaultListOp) {
|
|
|
73
112
|
// finally we flatten all as single string and enclose with bracket.
|
|
74
113
|
values = ["(".concat(filterExpressions_1.join(','), ")")];
|
|
75
114
|
}
|
|
76
|
-
else {
|
|
77
|
-
values = [filter[key]];
|
|
78
|
-
}
|
|
79
115
|
values.forEach(function (value) {
|
|
80
116
|
var op = (function () {
|
|
81
117
|
// if operator is intentionally blank, rpc syntax
|
|
@@ -85,11 +121,9 @@ export var parseFilters = function (params, defaultListOp) {
|
|
|
85
121
|
return "".concat(operation, ".*").concat(value, "*");
|
|
86
122
|
if (['and', 'or'].includes(operation))
|
|
87
123
|
return "".concat(value);
|
|
88
|
-
if (['cs', 'cd'].includes(operation))
|
|
89
|
-
return "".concat(operation, ".{").concat(value, "}");
|
|
90
124
|
return "".concat(operation, ".").concat(value);
|
|
91
125
|
})();
|
|
92
|
-
// If resulting filter
|
|
126
|
+
// If resulting filter doesn't contain the fieldname, then add it.
|
|
93
127
|
if (result.filter[splitKey[0]] === undefined) {
|
|
94
128
|
// first operator for the key,
|
|
95
129
|
if (['and', 'or'].includes(operation)) {
|
|
@@ -141,15 +175,29 @@ export var encodeId = function (data, primaryKey) {
|
|
|
141
175
|
return data[primaryKey[0]];
|
|
142
176
|
}
|
|
143
177
|
};
|
|
144
|
-
export var
|
|
145
|
-
|
|
178
|
+
export var removePrimaryKey = function (data, primaryKey) {
|
|
179
|
+
var newData = __assign({}, data);
|
|
180
|
+
primaryKey.forEach(function (key) {
|
|
181
|
+
delete newData[key];
|
|
182
|
+
});
|
|
183
|
+
return newData;
|
|
184
|
+
};
|
|
185
|
+
export var dataWithVirtualId = function (data, primaryKey) {
|
|
186
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
146
187
|
return data;
|
|
147
188
|
}
|
|
148
189
|
return Object.assign(data, {
|
|
149
190
|
id: encodeId(data, primaryKey),
|
|
150
191
|
});
|
|
151
192
|
};
|
|
152
|
-
export var
|
|
193
|
+
export var dataWithoutVirtualId = function (data, primaryKey) {
|
|
194
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
195
|
+
return data;
|
|
196
|
+
}
|
|
197
|
+
var id = data.id, dataWithoutId = __rest(data, ["id"]);
|
|
198
|
+
return dataWithoutId;
|
|
199
|
+
};
|
|
200
|
+
var isCompoundKey = function (primaryKey) {
|
|
153
201
|
return primaryKey.length > 1;
|
|
154
202
|
};
|
|
155
203
|
export var getQuery = function (primaryKey, ids, resource, meta) {
|
|
@@ -178,7 +226,7 @@ export var getQuery = function (primaryKey, ids, resource, meta) {
|
|
|
178
226
|
_a);
|
|
179
227
|
}
|
|
180
228
|
}
|
|
181
|
-
else {
|
|
229
|
+
else if (ids) {
|
|
182
230
|
// if ids is one Identifier
|
|
183
231
|
var id = ids.toString();
|
|
184
232
|
var primaryKeyParams_1 = decodeId(id, primaryKey);
|
|
@@ -210,18 +258,6 @@ export var getQuery = function (primaryKey, ids, resource, meta) {
|
|
|
210
258
|
}
|
|
211
259
|
return result;
|
|
212
260
|
};
|
|
213
|
-
export var getKeyData = function (primaryKey, data) {
|
|
214
|
-
var _a;
|
|
215
|
-
if (isCompoundKey(primaryKey)) {
|
|
216
|
-
return primaryKey.reduce(function (keyData, key) {
|
|
217
|
-
var _a;
|
|
218
|
-
return (__assign(__assign({}, keyData), (_a = {}, _a[key] = data[key], _a)));
|
|
219
|
-
}, {});
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
return _a = {}, _a[primaryKey[0]] = data[primaryKey[0]], _a;
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
261
|
export var getOrderBy = function (field, order, primaryKey) {
|
|
226
262
|
if (field == 'id') {
|
|
227
263
|
return primaryKey.map(function (key) { return "".concat(key, ".").concat(order.toLowerCase()); }).join(',');
|
package/lib/index.js
CHANGED
|
@@ -68,7 +68,7 @@ exports.default = (function (config) { return ({
|
|
|
68
68
|
throw new Error("The Content-Range header is missing in the HTTP Response. The postgREST data provider expects \n responses for lists of resources to contain this header with the total number of results to build \n the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?");
|
|
69
69
|
}
|
|
70
70
|
return {
|
|
71
|
-
data: json.map(function (obj) { return (0, urlBuilder_1.
|
|
71
|
+
data: json.map(function (obj) { return (0, urlBuilder_1.dataWithVirtualId)(obj, primaryKey); }),
|
|
72
72
|
total: parseInt(headers.get('content-range').split('/').pop(), 10),
|
|
73
73
|
};
|
|
74
74
|
});
|
|
@@ -88,7 +88,7 @@ exports.default = (function (config) { return ({
|
|
|
88
88
|
.then(function (_a) {
|
|
89
89
|
var json = _a.json;
|
|
90
90
|
return ({
|
|
91
|
-
data: (0, urlBuilder_1.
|
|
91
|
+
data: (0, urlBuilder_1.dataWithVirtualId)(json, primaryKey),
|
|
92
92
|
});
|
|
93
93
|
});
|
|
94
94
|
},
|
|
@@ -107,7 +107,7 @@ exports.default = (function (config) { return ({
|
|
|
107
107
|
.then(function (_a) {
|
|
108
108
|
var json = _a.json;
|
|
109
109
|
return ({
|
|
110
|
-
data: json.map(function (data) { return (0, urlBuilder_1.
|
|
110
|
+
data: json.map(function (data) { return (0, urlBuilder_1.dataWithVirtualId)(data, primaryKey); }),
|
|
111
111
|
});
|
|
112
112
|
});
|
|
113
113
|
},
|
|
@@ -136,7 +136,7 @@ exports.default = (function (config) { return ({
|
|
|
136
136
|
throw new Error("The Content-Range header is missing in the HTTP Response. The postgREST data provider expects \n responses for lists of resources to contain this header with the total number of results to build \n the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?");
|
|
137
137
|
}
|
|
138
138
|
return {
|
|
139
|
-
data: json.map(function (data) { return (0, urlBuilder_1.
|
|
139
|
+
data: json.map(function (data) { return (0, urlBuilder_1.dataWithVirtualId)(data, primaryKey); }),
|
|
140
140
|
total: parseInt(headers.get('content-range').split('/').pop(), 10),
|
|
141
141
|
};
|
|
142
142
|
});
|
|
@@ -147,10 +147,9 @@ exports.default = (function (config) { return ({
|
|
|
147
147
|
var id = params.id, data = params.data, meta = params.meta;
|
|
148
148
|
var primaryKey = (0, urlBuilder_1.getPrimaryKey)(resource, config.primaryKeys);
|
|
149
149
|
var query = (0, urlBuilder_1.getQuery)(primaryKey, id, resource, meta);
|
|
150
|
-
var primaryKeyData = (0, urlBuilder_1.getKeyData)(primaryKey, data);
|
|
151
150
|
var url = "".concat(config.apiUrl, "/").concat(resource, "?").concat(qs_1.default.stringify(query));
|
|
152
151
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
153
|
-
var body = JSON.stringify(__assign(
|
|
152
|
+
var body = JSON.stringify(__assign({}, (0, urlBuilder_1.dataWithoutVirtualId)((0, urlBuilder_1.removePrimaryKey)(data, primaryKey), primaryKey)));
|
|
154
153
|
return config
|
|
155
154
|
.httpClient(url, {
|
|
156
155
|
method: 'PATCH',
|
|
@@ -159,29 +158,19 @@ exports.default = (function (config) { return ({
|
|
|
159
158
|
})
|
|
160
159
|
.then(function (_a) {
|
|
161
160
|
var json = _a.json;
|
|
162
|
-
return ({
|
|
161
|
+
return ({
|
|
162
|
+
data: (0, urlBuilder_1.dataWithVirtualId)(json, primaryKey),
|
|
163
|
+
});
|
|
163
164
|
});
|
|
164
165
|
},
|
|
165
166
|
updateMany: function (resource, params) {
|
|
166
167
|
var _a, _b;
|
|
167
168
|
if (params === void 0) { params = {}; }
|
|
168
|
-
var ids = params.ids;
|
|
169
|
+
var ids = params.ids, meta = params.meta, data = params.data;
|
|
169
170
|
var primaryKey = (0, urlBuilder_1.getPrimaryKey)(resource, config.primaryKeys);
|
|
170
|
-
var
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
var primaryKeyData = {};
|
|
174
|
-
if ((0, urlBuilder_1.isCompoundKey)(primaryKey)) {
|
|
175
|
-
primaryKey.forEach(function (key, index) {
|
|
176
|
-
primaryKeyData[key] = primaryKeyParams[index];
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
primaryKeyData[primaryKey[0]] = primaryKeyParams[0];
|
|
181
|
-
}
|
|
182
|
-
return __assign(__assign({}, data), primaryKeyData);
|
|
183
|
-
}));
|
|
184
|
-
var url = "".concat(config.apiUrl, "/").concat(resource);
|
|
171
|
+
var query = (0, urlBuilder_1.getQuery)(primaryKey, ids, resource, meta);
|
|
172
|
+
var url = "".concat(config.apiUrl, "/").concat(resource, "?").concat(qs_1.default.stringify(query));
|
|
173
|
+
var body = JSON.stringify(__assign({}, (0, urlBuilder_1.dataWithoutVirtualId)((0, urlBuilder_1.removePrimaryKey)(data, primaryKey), primaryKey)));
|
|
185
174
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
186
175
|
return config
|
|
187
176
|
.httpClient(url, {
|
|
@@ -199,14 +188,17 @@ exports.default = (function (config) { return ({
|
|
|
199
188
|
create: function (resource, params) {
|
|
200
189
|
var _a, _b;
|
|
201
190
|
if (params === void 0) { params = {}; }
|
|
191
|
+
var meta = params.meta;
|
|
202
192
|
var primaryKey = (0, urlBuilder_1.getPrimaryKey)(resource, config.primaryKeys);
|
|
203
|
-
var
|
|
193
|
+
var query = (0, urlBuilder_1.getQuery)(primaryKey, undefined, resource, meta);
|
|
194
|
+
var queryStr = qs_1.default.stringify(query);
|
|
195
|
+
var url = "".concat(config.apiUrl, "/").concat(resource).concat(queryStr.length > 0 ? '?' : '').concat(queryStr);
|
|
204
196
|
var metaSchema = (_a = params.meta) === null || _a === void 0 ? void 0 : _a.schema;
|
|
205
197
|
return config
|
|
206
198
|
.httpClient(url, {
|
|
207
199
|
method: 'POST',
|
|
208
200
|
headers: new Headers(__assign(__assign({ Accept: 'application/vnd.pgrst.object+json', Prefer: 'return=representation', 'Content-Type': 'application/json' }, (((_b = params.meta) === null || _b === void 0 ? void 0 : _b.headers) || {})), useCustomSchema(config.schema, metaSchema, 'POST'))),
|
|
209
|
-
body: JSON.stringify(params.data),
|
|
201
|
+
body: JSON.stringify((0, urlBuilder_1.dataWithoutVirtualId)(params.data, primaryKey)),
|
|
210
202
|
})
|
|
211
203
|
.then(function (_a) {
|
|
212
204
|
var json = _a.json;
|
|
@@ -230,7 +222,9 @@ exports.default = (function (config) { return ({
|
|
|
230
222
|
})
|
|
231
223
|
.then(function (_a) {
|
|
232
224
|
var json = _a.json;
|
|
233
|
-
return ({
|
|
225
|
+
return ({
|
|
226
|
+
data: (0, urlBuilder_1.dataWithVirtualId)(json, primaryKey),
|
|
227
|
+
});
|
|
234
228
|
});
|
|
235
229
|
},
|
|
236
230
|
deleteMany: function (resource, params) {
|
package/lib/urlBuilder.d.ts
CHANGED
|
@@ -14,9 +14,9 @@ export type PrimaryKey = Array<string>;
|
|
|
14
14
|
export declare const getPrimaryKey: (resource: string, primaryKeys: Map<string, PrimaryKey>) => PrimaryKey;
|
|
15
15
|
export declare const decodeId: (id: Identifier, primaryKey: PrimaryKey) => string[] | number[];
|
|
16
16
|
export declare const encodeId: (data: any, primaryKey: PrimaryKey) => Identifier;
|
|
17
|
-
export declare const
|
|
18
|
-
export declare const
|
|
19
|
-
export declare const
|
|
20
|
-
export declare const
|
|
17
|
+
export declare const removePrimaryKey: (data: any, primaryKey: PrimaryKey) => any;
|
|
18
|
+
export declare const dataWithVirtualId: (data: any, primaryKey: PrimaryKey) => any;
|
|
19
|
+
export declare const dataWithoutVirtualId: (data: any, primaryKey: PrimaryKey) => any;
|
|
20
|
+
export declare const getQuery: (primaryKey: PrimaryKey, ids: Identifier | Array<Identifier> | undefined, resource: string, meta?: any) => any;
|
|
21
21
|
export declare const getOrderBy: (field: string, order: string, primaryKey: PrimaryKey) => string;
|
|
22
22
|
export {};
|
package/lib/urlBuilder.js
CHANGED
|
@@ -10,8 +10,19 @@ var __assign = (this && this.__assign) || function () {
|
|
|
10
10
|
};
|
|
11
11
|
return __assign.apply(this, arguments);
|
|
12
12
|
};
|
|
13
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
14
|
+
var t = {};
|
|
15
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
16
|
+
t[p] = s[p];
|
|
17
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
18
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
19
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
20
|
+
t[p[i]] = s[p[i]];
|
|
21
|
+
}
|
|
22
|
+
return t;
|
|
23
|
+
};
|
|
13
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.getOrderBy = exports.
|
|
25
|
+
exports.getOrderBy = exports.getQuery = exports.dataWithoutVirtualId = exports.dataWithVirtualId = exports.removePrimaryKey = exports.encodeId = exports.decodeId = exports.getPrimaryKey = exports.parseFilters = void 0;
|
|
15
26
|
/**
|
|
16
27
|
* List of all possible operators in PostgRest
|
|
17
28
|
* (https://postgrest.org/en/stable/api.html#operators)
|
|
@@ -45,25 +56,53 @@ var postgrestOperators = [
|
|
|
45
56
|
'or',
|
|
46
57
|
'and',
|
|
47
58
|
];
|
|
59
|
+
var isObject = function (obj) {
|
|
60
|
+
return typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
|
|
61
|
+
};
|
|
62
|
+
var resolveKeys = function (filter, keys) {
|
|
63
|
+
var result = filter[keys[0]];
|
|
64
|
+
for (var i = 1; i < keys.length; ++i) {
|
|
65
|
+
result = result[keys[i]];
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
48
69
|
var parseFilters = function (params, defaultListOp) {
|
|
49
70
|
var filter = params.filter, _a = params.meta, meta = _a === void 0 ? {} : _a;
|
|
50
71
|
var result = {};
|
|
51
72
|
result.filter = {};
|
|
52
73
|
Object.keys(filter).forEach(function (key) {
|
|
53
74
|
// key: the name of the object key
|
|
75
|
+
var keyArray = [key];
|
|
76
|
+
var values;
|
|
77
|
+
// in case of a nested object selection in a text field
|
|
78
|
+
// RA returns object{ object } structure which is resolved here
|
|
79
|
+
// see issue https://github.com/raphiniert-com/ra-data-postgrest/issues/58
|
|
80
|
+
if (key.split('@')[0] !== '' && isObject(filter[key])) {
|
|
81
|
+
var innerVal = filter[key];
|
|
82
|
+
do {
|
|
83
|
+
var inner = resolveKeys(filter, keyArray);
|
|
84
|
+
var innerKey = Object.keys(inner)[0];
|
|
85
|
+
keyArray.push(innerKey);
|
|
86
|
+
innerVal = inner[innerKey];
|
|
87
|
+
} while (isObject(innerVal));
|
|
88
|
+
key = keyArray.join('.');
|
|
89
|
+
values = [innerVal];
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
values = [filter[key]];
|
|
93
|
+
}
|
|
54
94
|
var splitKey = key.split('@');
|
|
55
95
|
var operation = splitKey.length == 2
|
|
56
96
|
? splitKey[1]
|
|
57
97
|
: defaultListOp;
|
|
58
|
-
var values;
|
|
59
98
|
if (['like', 'ilike'].includes(operation)) {
|
|
60
99
|
// we split the search term in words
|
|
61
|
-
values = filter
|
|
100
|
+
values = resolveKeys(filter, keyArray).trim().split(/\s+/);
|
|
62
101
|
}
|
|
63
102
|
// CASE: Logical operator
|
|
64
103
|
else if (['or', 'and'].includes(operation)) {
|
|
65
104
|
// we extract each value entries and make it dot separated string.
|
|
66
|
-
var subFilter = (0, exports.parseFilters)({ filter: filter
|
|
105
|
+
var subFilter = (0, exports.parseFilters)({ filter: resolveKeys(filter, keyArray) }, defaultListOp).filter;
|
|
67
106
|
// something like { "age@lt": 18 } and { "age@gt": 21 }
|
|
68
107
|
var filterExpressions_1 = [];
|
|
69
108
|
Object.entries(subFilter).forEach(function (_a) {
|
|
@@ -76,9 +115,6 @@ var parseFilters = function (params, defaultListOp) {
|
|
|
76
115
|
// finally we flatten all as single string and enclose with bracket.
|
|
77
116
|
values = ["(".concat(filterExpressions_1.join(','), ")")];
|
|
78
117
|
}
|
|
79
|
-
else {
|
|
80
|
-
values = [filter[key]];
|
|
81
|
-
}
|
|
82
118
|
values.forEach(function (value) {
|
|
83
119
|
var op = (function () {
|
|
84
120
|
// if operator is intentionally blank, rpc syntax
|
|
@@ -88,11 +124,9 @@ var parseFilters = function (params, defaultListOp) {
|
|
|
88
124
|
return "".concat(operation, ".*").concat(value, "*");
|
|
89
125
|
if (['and', 'or'].includes(operation))
|
|
90
126
|
return "".concat(value);
|
|
91
|
-
if (['cs', 'cd'].includes(operation))
|
|
92
|
-
return "".concat(operation, ".{").concat(value, "}");
|
|
93
127
|
return "".concat(operation, ".").concat(value);
|
|
94
128
|
})();
|
|
95
|
-
// If resulting filter
|
|
129
|
+
// If resulting filter doesn't contain the fieldname, then add it.
|
|
96
130
|
if (result.filter[splitKey[0]] === undefined) {
|
|
97
131
|
// first operator for the key,
|
|
98
132
|
if (['and', 'or'].includes(operation)) {
|
|
@@ -131,7 +165,7 @@ var getPrimaryKey = function (resource, primaryKeys) {
|
|
|
131
165
|
};
|
|
132
166
|
exports.getPrimaryKey = getPrimaryKey;
|
|
133
167
|
var decodeId = function (id, primaryKey) {
|
|
134
|
-
if (
|
|
168
|
+
if (isCompoundKey(primaryKey)) {
|
|
135
169
|
return JSON.parse(id.toString());
|
|
136
170
|
}
|
|
137
171
|
else {
|
|
@@ -140,7 +174,7 @@ var decodeId = function (id, primaryKey) {
|
|
|
140
174
|
};
|
|
141
175
|
exports.decodeId = decodeId;
|
|
142
176
|
var encodeId = function (data, primaryKey) {
|
|
143
|
-
if (
|
|
177
|
+
if (isCompoundKey(primaryKey)) {
|
|
144
178
|
return JSON.stringify(primaryKey.map(function (key) { return data[key]; }));
|
|
145
179
|
}
|
|
146
180
|
else {
|
|
@@ -148,19 +182,34 @@ var encodeId = function (data, primaryKey) {
|
|
|
148
182
|
}
|
|
149
183
|
};
|
|
150
184
|
exports.encodeId = encodeId;
|
|
151
|
-
var
|
|
152
|
-
|
|
185
|
+
var removePrimaryKey = function (data, primaryKey) {
|
|
186
|
+
var newData = __assign({}, data);
|
|
187
|
+
primaryKey.forEach(function (key) {
|
|
188
|
+
delete newData[key];
|
|
189
|
+
});
|
|
190
|
+
return newData;
|
|
191
|
+
};
|
|
192
|
+
exports.removePrimaryKey = removePrimaryKey;
|
|
193
|
+
var dataWithVirtualId = function (data, primaryKey) {
|
|
194
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
153
195
|
return data;
|
|
154
196
|
}
|
|
155
197
|
return Object.assign(data, {
|
|
156
198
|
id: (0, exports.encodeId)(data, primaryKey),
|
|
157
199
|
});
|
|
158
200
|
};
|
|
159
|
-
exports.
|
|
201
|
+
exports.dataWithVirtualId = dataWithVirtualId;
|
|
202
|
+
var dataWithoutVirtualId = function (data, primaryKey) {
|
|
203
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
var id = data.id, dataWithoutId = __rest(data, ["id"]);
|
|
207
|
+
return dataWithoutId;
|
|
208
|
+
};
|
|
209
|
+
exports.dataWithoutVirtualId = dataWithoutVirtualId;
|
|
160
210
|
var isCompoundKey = function (primaryKey) {
|
|
161
211
|
return primaryKey.length > 1;
|
|
162
212
|
};
|
|
163
|
-
exports.isCompoundKey = isCompoundKey;
|
|
164
213
|
var getQuery = function (primaryKey, ids, resource, meta) {
|
|
165
214
|
var _a, _b;
|
|
166
215
|
if (meta === void 0) { meta = null; }
|
|
@@ -171,7 +220,7 @@ var getQuery = function (primaryKey, ids, resource, meta) {
|
|
|
171
220
|
console.error("PostgREST's rpc endpoints are not intended to be handled as views. Therefore, no query generation for multiple key values implemented!");
|
|
172
221
|
return;
|
|
173
222
|
}
|
|
174
|
-
if (
|
|
223
|
+
if (isCompoundKey(primaryKey)) {
|
|
175
224
|
result = {
|
|
176
225
|
or: "(".concat(ids.map(function (id) {
|
|
177
226
|
var primaryKeyParams = (0, exports.decodeId)(id, primaryKey);
|
|
@@ -187,11 +236,11 @@ var getQuery = function (primaryKey, ids, resource, meta) {
|
|
|
187
236
|
_a);
|
|
188
237
|
}
|
|
189
238
|
}
|
|
190
|
-
else {
|
|
239
|
+
else if (ids) {
|
|
191
240
|
// if ids is one Identifier
|
|
192
241
|
var id = ids.toString();
|
|
193
242
|
var primaryKeyParams_1 = (0, exports.decodeId)(id, primaryKey);
|
|
194
|
-
if (
|
|
243
|
+
if (isCompoundKey(primaryKey)) {
|
|
195
244
|
if (resource.startsWith('rpc/')) {
|
|
196
245
|
result = {};
|
|
197
246
|
primaryKey.map(function (key, i) {
|
|
@@ -220,19 +269,6 @@ var getQuery = function (primaryKey, ids, resource, meta) {
|
|
|
220
269
|
return result;
|
|
221
270
|
};
|
|
222
271
|
exports.getQuery = getQuery;
|
|
223
|
-
var getKeyData = function (primaryKey, data) {
|
|
224
|
-
var _a;
|
|
225
|
-
if ((0, exports.isCompoundKey)(primaryKey)) {
|
|
226
|
-
return primaryKey.reduce(function (keyData, key) {
|
|
227
|
-
var _a;
|
|
228
|
-
return (__assign(__assign({}, keyData), (_a = {}, _a[key] = data[key], _a)));
|
|
229
|
-
}, {});
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
return _a = {}, _a[primaryKey[0]] = data[primaryKey[0]], _a;
|
|
233
|
-
}
|
|
234
|
-
};
|
|
235
|
-
exports.getKeyData = getKeyData;
|
|
236
272
|
var getOrderBy = function (field, order, primaryKey) {
|
|
237
273
|
if (field == 'id') {
|
|
238
274
|
return primaryKey.map(function (key) { return "".concat(key, ".").concat(order.toLowerCase()); }).join(',');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raphiniert/ra-data-postgrest",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "postgREST data provider for react-admin",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "esm/index.js",
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"src"
|
|
13
13
|
],
|
|
14
14
|
"authors": [
|
|
15
|
-
"François Zaninotto",
|
|
16
15
|
"Raphael Scheible"
|
|
17
16
|
],
|
|
18
17
|
"repository": "raphiniert-com/ra-data-postgrest",
|
|
@@ -30,17 +29,17 @@
|
|
|
30
29
|
"prettier": "prettier --config ./.prettierrc.js --write --list-different \"src/**/*.{js,json,ts,tsx,css,md}\""
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@types/jest": "^
|
|
34
|
-
"@types/qs": "^6.9.
|
|
32
|
+
"@types/jest": "^29.5.11",
|
|
33
|
+
"@types/qs": "^6.9.11",
|
|
35
34
|
"cross-env": "^7.0.3",
|
|
36
|
-
"eslint-config-prettier": "^
|
|
37
|
-
"eslint-plugin-prettier": "^
|
|
35
|
+
"eslint-config-prettier": "^9.1.0",
|
|
36
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
38
37
|
"install-peers-cli": "^2.2.0",
|
|
39
|
-
"jest": "^
|
|
40
|
-
"prettier": "
|
|
38
|
+
"jest": "^29.7.0",
|
|
39
|
+
"prettier": "^3.1.1",
|
|
41
40
|
"rimraf": "^5.0.0",
|
|
42
|
-
"ts-jest": "^
|
|
43
|
-
"typescript": "^5.
|
|
41
|
+
"ts-jest": "^29.1.1",
|
|
42
|
+
"typescript": "^5.3.3"
|
|
44
43
|
},
|
|
45
44
|
"peerDependencies": {
|
|
46
45
|
"ra-core": "^4.1.0"
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
fetchUtils,
|
|
3
2
|
DataProvider,
|
|
4
3
|
GetListParams,
|
|
5
4
|
GetOneParams,
|
|
@@ -17,12 +16,11 @@ import {
|
|
|
17
16
|
getPrimaryKey,
|
|
18
17
|
parseFilters,
|
|
19
18
|
getOrderBy,
|
|
20
|
-
|
|
19
|
+
dataWithVirtualId,
|
|
20
|
+
dataWithoutVirtualId,
|
|
21
|
+
removePrimaryKey,
|
|
21
22
|
getQuery,
|
|
22
|
-
getKeyData,
|
|
23
23
|
encodeId,
|
|
24
|
-
decodeId,
|
|
25
|
-
isCompoundKey,
|
|
26
24
|
} from './urlBuilder';
|
|
27
25
|
import qs from 'qs';
|
|
28
26
|
|
|
@@ -154,7 +152,7 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
154
152
|
);
|
|
155
153
|
}
|
|
156
154
|
return {
|
|
157
|
-
data: json.map(obj =>
|
|
155
|
+
data: json.map(obj => dataWithVirtualId(obj, primaryKey)),
|
|
158
156
|
total: parseInt(
|
|
159
157
|
headers.get('content-range').split('/').pop(),
|
|
160
158
|
10
|
|
@@ -181,7 +179,7 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
181
179
|
}),
|
|
182
180
|
})
|
|
183
181
|
.then(({ json }) => ({
|
|
184
|
-
data:
|
|
182
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
185
183
|
}));
|
|
186
184
|
},
|
|
187
185
|
|
|
@@ -201,7 +199,7 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
201
199
|
}),
|
|
202
200
|
})
|
|
203
201
|
.then(({ json }) => ({
|
|
204
|
-
data: json.map(data =>
|
|
202
|
+
data: json.map(data => dataWithVirtualId(data, primaryKey)),
|
|
205
203
|
}));
|
|
206
204
|
},
|
|
207
205
|
|
|
@@ -257,7 +255,7 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
257
255
|
);
|
|
258
256
|
}
|
|
259
257
|
return {
|
|
260
|
-
data: json.map(data =>
|
|
258
|
+
data: json.map(data => dataWithVirtualId(data, primaryKey)),
|
|
261
259
|
total: parseInt(
|
|
262
260
|
headers.get('content-range').split('/').pop(),
|
|
263
261
|
10
|
|
@@ -269,17 +267,15 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
269
267
|
update: (resource, params: Partial<UpdateParams> = {}) => {
|
|
270
268
|
const { id, data, meta } = params;
|
|
271
269
|
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
272
|
-
|
|
273
270
|
const query = getQuery(primaryKey, id, resource, meta);
|
|
274
|
-
|
|
275
|
-
const primaryKeyData = getKeyData(primaryKey, data);
|
|
276
|
-
|
|
277
271
|
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
278
272
|
const metaSchema = params.meta?.schema;
|
|
279
273
|
|
|
280
274
|
const body = JSON.stringify({
|
|
281
|
-
...
|
|
282
|
-
|
|
275
|
+
...dataWithoutVirtualId(
|
|
276
|
+
removePrimaryKey(data, primaryKey),
|
|
277
|
+
primaryKey
|
|
278
|
+
),
|
|
283
279
|
});
|
|
284
280
|
|
|
285
281
|
return config
|
|
@@ -294,35 +290,23 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
294
290
|
}),
|
|
295
291
|
body,
|
|
296
292
|
})
|
|
297
|
-
.then(({ json }) => ({
|
|
293
|
+
.then(({ json }) => ({
|
|
294
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
295
|
+
}));
|
|
298
296
|
},
|
|
299
297
|
|
|
300
298
|
updateMany: (resource, params: Partial<UpdateManyParams> = {}) => {
|
|
301
|
-
const ids = params
|
|
299
|
+
const { ids, meta, data } = params;
|
|
302
300
|
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
301
|
+
const query = getQuery(primaryKey, ids, resource, meta);
|
|
302
|
+
const url = `${config.apiUrl}/${resource}?${qs.stringify(query)}`;
|
|
303
|
+
const body = JSON.stringify({
|
|
304
|
+
...dataWithoutVirtualId(
|
|
305
|
+
removePrimaryKey(data, primaryKey),
|
|
306
|
+
primaryKey
|
|
307
|
+
),
|
|
308
|
+
});
|
|
303
309
|
|
|
304
|
-
const body = JSON.stringify(
|
|
305
|
-
params.ids.map(id => {
|
|
306
|
-
const { data } = params;
|
|
307
|
-
const primaryKeyParams = decodeId(id, primaryKey);
|
|
308
|
-
|
|
309
|
-
const primaryKeyData = {};
|
|
310
|
-
if (isCompoundKey(primaryKey)) {
|
|
311
|
-
primaryKey.forEach((key, index) => {
|
|
312
|
-
primaryKeyData[key] = primaryKeyParams[index];
|
|
313
|
-
});
|
|
314
|
-
} else {
|
|
315
|
-
primaryKeyData[primaryKey[0]] = primaryKeyParams[0];
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
return {
|
|
319
|
-
...data,
|
|
320
|
-
...primaryKeyData,
|
|
321
|
-
};
|
|
322
|
-
})
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
const url = `${config.apiUrl}/${resource}`;
|
|
326
310
|
const metaSchema = params.meta?.schema;
|
|
327
311
|
|
|
328
312
|
return config
|
|
@@ -342,8 +326,13 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
342
326
|
},
|
|
343
327
|
|
|
344
328
|
create: (resource, params: Partial<CreateParams> = {}) => {
|
|
329
|
+
const { meta } = params;
|
|
345
330
|
const primaryKey = getPrimaryKey(resource, config.primaryKeys);
|
|
346
|
-
const
|
|
331
|
+
const query = getQuery(primaryKey, undefined, resource, meta);
|
|
332
|
+
const queryStr = qs.stringify(query);
|
|
333
|
+
const url = `${config.apiUrl}/${resource}${
|
|
334
|
+
queryStr.length > 0 ? '?' : ''
|
|
335
|
+
}${queryStr}`;
|
|
347
336
|
const metaSchema = params.meta?.schema;
|
|
348
337
|
|
|
349
338
|
return config
|
|
@@ -356,7 +345,9 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
356
345
|
...(params.meta?.headers || {}),
|
|
357
346
|
...useCustomSchema(config.schema, metaSchema, 'POST'),
|
|
358
347
|
}),
|
|
359
|
-
body: JSON.stringify(
|
|
348
|
+
body: JSON.stringify(
|
|
349
|
+
dataWithoutVirtualId(params.data, primaryKey)
|
|
350
|
+
),
|
|
360
351
|
})
|
|
361
352
|
.then(({ json }) => ({
|
|
362
353
|
data: {
|
|
@@ -386,7 +377,9 @@ export default (config: IDataProviderConfig): DataProvider => ({
|
|
|
386
377
|
...useCustomSchema(config.schema, metaSchema, 'DELETE'),
|
|
387
378
|
}),
|
|
388
379
|
})
|
|
389
|
-
.then(({ json }) => ({
|
|
380
|
+
.then(({ json }) => ({
|
|
381
|
+
data: dataWithVirtualId(json, primaryKey),
|
|
382
|
+
}));
|
|
390
383
|
},
|
|
391
384
|
|
|
392
385
|
deleteMany: (resource, params: Partial<DeleteManyParams> = {}) => {
|
package/src/urlBuilder.ts
CHANGED
|
@@ -49,6 +49,18 @@ type ParsedFiltersResult = {
|
|
|
49
49
|
select: any;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
const isObject = obj =>
|
|
53
|
+
typeof obj === 'object' && !Array.isArray(obj) && obj !== null;
|
|
54
|
+
|
|
55
|
+
const resolveKeys = (filter: any, keys: Array<any>) => {
|
|
56
|
+
let result = filter[keys[0]];
|
|
57
|
+
for (let i = 1; i < keys.length; ++i) {
|
|
58
|
+
result = result[keys[i]];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
|
|
52
64
|
export type PostgRestOperator = (typeof postgrestOperators)[number];
|
|
53
65
|
|
|
54
66
|
export const parseFilters = (
|
|
@@ -62,22 +74,44 @@ export const parseFilters = (
|
|
|
62
74
|
Object.keys(filter).forEach(function (key) {
|
|
63
75
|
// key: the name of the object key
|
|
64
76
|
|
|
77
|
+
let keyArray = [key];
|
|
78
|
+
let values: Array<string>;
|
|
79
|
+
|
|
80
|
+
// in case of a nested object selection in a text field
|
|
81
|
+
// RA returns object{ object } structure which is resolved here
|
|
82
|
+
// see issue https://github.com/raphiniert-com/ra-data-postgrest/issues/58
|
|
83
|
+
if (key.split('@')[0] !== '' && isObject(filter[key])) {
|
|
84
|
+
let innerVal = filter[key];
|
|
85
|
+
|
|
86
|
+
do {
|
|
87
|
+
const inner = resolveKeys(filter, keyArray);
|
|
88
|
+
const [innerKey] = Object.keys(inner);
|
|
89
|
+
|
|
90
|
+
keyArray.push(innerKey);
|
|
91
|
+
innerVal = inner[innerKey];
|
|
92
|
+
} while (isObject(innerVal));
|
|
93
|
+
|
|
94
|
+
key = keyArray.join('.');
|
|
95
|
+
values = [innerVal];
|
|
96
|
+
} else {
|
|
97
|
+
values = [filter[key]];
|
|
98
|
+
}
|
|
99
|
+
|
|
65
100
|
const splitKey = key.split('@');
|
|
66
101
|
const operation: PostgRestOperator =
|
|
67
102
|
splitKey.length == 2
|
|
68
103
|
? (splitKey[1] as PostgRestOperator)
|
|
69
104
|
: defaultListOp;
|
|
70
105
|
|
|
71
|
-
let values: Array<string>;
|
|
72
106
|
if (['like', 'ilike'].includes(operation)) {
|
|
73
107
|
// we split the search term in words
|
|
74
|
-
values = filter
|
|
108
|
+
values = resolveKeys(filter, keyArray).trim().split(/\s+/);
|
|
75
109
|
}
|
|
76
110
|
// CASE: Logical operator
|
|
77
111
|
else if (['or', 'and'].includes(operation)) {
|
|
78
112
|
// we extract each value entries and make it dot separated string.
|
|
79
113
|
const { filter: subFilter } = parseFilters(
|
|
80
|
-
{ filter: filter
|
|
114
|
+
{ filter: resolveKeys(filter, keyArray) },
|
|
81
115
|
defaultListOp
|
|
82
116
|
);
|
|
83
117
|
|
|
@@ -91,8 +125,6 @@ export const parseFilters = (
|
|
|
91
125
|
|
|
92
126
|
// finally we flatten all as single string and enclose with bracket.
|
|
93
127
|
values = [`(${filterExpressions.join(',')})`];
|
|
94
|
-
} else {
|
|
95
|
-
values = [filter[key]];
|
|
96
128
|
}
|
|
97
129
|
|
|
98
130
|
values.forEach(value => {
|
|
@@ -103,12 +135,10 @@ export const parseFilters = (
|
|
|
103
135
|
if (operation.includes('like'))
|
|
104
136
|
return `${operation}.*${value}*`;
|
|
105
137
|
if (['and', 'or'].includes(operation)) return `${value}`;
|
|
106
|
-
if (['cs', 'cd'].includes(operation))
|
|
107
|
-
return `${operation}.{${value}}`;
|
|
108
138
|
return `${operation}.${value}`;
|
|
109
139
|
})();
|
|
110
140
|
|
|
111
|
-
// If resulting filter
|
|
141
|
+
// If resulting filter doesn't contain the fieldname, then add it.
|
|
112
142
|
if (result.filter[splitKey[0]] === undefined) {
|
|
113
143
|
// first operator for the key,
|
|
114
144
|
if (['and', 'or'].includes(operation)) {
|
|
@@ -170,8 +200,16 @@ export const encodeId = (data: any, primaryKey: PrimaryKey): Identifier => {
|
|
|
170
200
|
}
|
|
171
201
|
};
|
|
172
202
|
|
|
173
|
-
export const
|
|
174
|
-
|
|
203
|
+
export const removePrimaryKey = (data: any, primaryKey: PrimaryKey) => {
|
|
204
|
+
const newData = { ...data };
|
|
205
|
+
primaryKey.forEach(key => {
|
|
206
|
+
delete newData[key];
|
|
207
|
+
});
|
|
208
|
+
return newData;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export const dataWithVirtualId = (data: any, primaryKey: PrimaryKey) => {
|
|
212
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
175
213
|
return data;
|
|
176
214
|
}
|
|
177
215
|
|
|
@@ -180,13 +218,22 @@ export const dataWithId = (data: any, primaryKey: PrimaryKey) => {
|
|
|
180
218
|
});
|
|
181
219
|
};
|
|
182
220
|
|
|
183
|
-
export const
|
|
221
|
+
export const dataWithoutVirtualId = (data: any, primaryKey: PrimaryKey) => {
|
|
222
|
+
if (primaryKey.length === 1 && primaryKey[0] === 'id') {
|
|
223
|
+
return data;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const { id, ...dataWithoutId } = data;
|
|
227
|
+
return dataWithoutId;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const isCompoundKey = (primaryKey: PrimaryKey): Boolean => {
|
|
184
231
|
return primaryKey.length > 1;
|
|
185
232
|
};
|
|
186
233
|
|
|
187
234
|
export const getQuery = (
|
|
188
235
|
primaryKey: PrimaryKey,
|
|
189
|
-
ids: Identifier | Array<Identifier
|
|
236
|
+
ids: Identifier | Array<Identifier> | undefined,
|
|
190
237
|
resource: string,
|
|
191
238
|
meta: any = null
|
|
192
239
|
): any => {
|
|
@@ -215,7 +262,7 @@ export const getQuery = (
|
|
|
215
262
|
[primaryKey[0]]: `in.(${ids.join(',')})`,
|
|
216
263
|
};
|
|
217
264
|
}
|
|
218
|
-
} else {
|
|
265
|
+
} else if (ids) {
|
|
219
266
|
// if ids is one Identifier
|
|
220
267
|
const id: Identifier = ids.toString();
|
|
221
268
|
const primaryKeyParams = decodeId(id, primaryKey);
|
|
@@ -251,20 +298,6 @@ export const getQuery = (
|
|
|
251
298
|
return result;
|
|
252
299
|
};
|
|
253
300
|
|
|
254
|
-
export const getKeyData = (primaryKey: PrimaryKey, data: object): object => {
|
|
255
|
-
if (isCompoundKey(primaryKey)) {
|
|
256
|
-
return primaryKey.reduce(
|
|
257
|
-
(keyData, key) => ({
|
|
258
|
-
...keyData,
|
|
259
|
-
[key]: data[key],
|
|
260
|
-
}),
|
|
261
|
-
{}
|
|
262
|
-
);
|
|
263
|
-
} else {
|
|
264
|
-
return { [primaryKey[0]]: data[primaryKey[0]] };
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
|
|
268
301
|
export const getOrderBy = (
|
|
269
302
|
field: string,
|
|
270
303
|
order: string,
|