@budibase/shared-core 2.3.21-alpha.1 → 2.4.8-alpha.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/package.json +11 -4
- package/src/filters.ts +73 -46
- package/src/helpers.ts +23 -0
- package/src/index.ts +2 -0
- package/src/utils.ts +6 -0
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +7 -2
- package/dist/src/index.js +0 -32
package/package.json
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/shared-core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.8-alpha.0",
|
|
4
4
|
"description": "Shared data utils",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
|
+
"module": "dist/src/index.js",
|
|
6
7
|
"types": "dist/src/index.d.ts",
|
|
7
8
|
"author": "Budibase",
|
|
8
9
|
"license": "GPL-3.0",
|
|
9
10
|
"scripts": {
|
|
10
|
-
"
|
|
11
|
-
"
|
|
11
|
+
"prebuild": "rimraf dist/",
|
|
12
|
+
"build": "tsc -p tsconfig.build.json",
|
|
13
|
+
"build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput",
|
|
14
|
+
"dev:builder": "tsc -p tsconfig.build.json --watch"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@budibase/types": "2.4.5-alpha.0"
|
|
12
18
|
},
|
|
13
19
|
"devDependencies": {
|
|
14
|
-
"typescript": "4.7.3"
|
|
20
|
+
"typescript": "4.7.3",
|
|
21
|
+
"rimraf": "3.0.2"
|
|
15
22
|
}
|
|
16
23
|
}
|
package/src/filters.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Datasource, FieldType, SortDirection, SortType } from "@budibase/types"
|
|
1
2
|
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
|
|
3
|
+
import { deepGet } from "./helpers"
|
|
2
4
|
|
|
3
5
|
const HBS_REGEX = /{{([^{].*?)}}/g
|
|
4
6
|
|
|
@@ -7,9 +9,9 @@ const HBS_REGEX = /{{([^{].*?)}}/g
|
|
|
7
9
|
* @param type the data type
|
|
8
10
|
*/
|
|
9
11
|
export const getValidOperatorsForType = (
|
|
10
|
-
type:
|
|
12
|
+
type: FieldType,
|
|
11
13
|
field: string,
|
|
12
|
-
datasource: { tableId:
|
|
14
|
+
datasource: Datasource & { tableId: any } // TODO: is this table id ever populated?
|
|
13
15
|
) => {
|
|
14
16
|
const Op = OperatorOptions
|
|
15
17
|
const stringOps = [
|
|
@@ -30,7 +32,10 @@ export const getValidOperatorsForType = (
|
|
|
30
32
|
Op.NotEmpty,
|
|
31
33
|
Op.In,
|
|
32
34
|
]
|
|
33
|
-
let ops:
|
|
35
|
+
let ops: {
|
|
36
|
+
value: string
|
|
37
|
+
label: string
|
|
38
|
+
}[] = []
|
|
34
39
|
if (type === "string") {
|
|
35
40
|
ops = stringOps
|
|
36
41
|
} else if (type === "number") {
|
|
@@ -73,13 +78,13 @@ export const NoEmptyFilterStrings = [
|
|
|
73
78
|
OperatorOptions.NotEquals.value,
|
|
74
79
|
OperatorOptions.Contains.value,
|
|
75
80
|
OperatorOptions.NotContains.value,
|
|
76
|
-
]
|
|
81
|
+
] as (keyof QueryFields)[]
|
|
77
82
|
|
|
78
83
|
/**
|
|
79
84
|
* Removes any fields that contain empty strings that would cause inconsistent
|
|
80
85
|
* behaviour with how backend tables are filtered (no value means no filter).
|
|
81
86
|
*/
|
|
82
|
-
const cleanupQuery = (query:
|
|
87
|
+
const cleanupQuery = (query: Query) => {
|
|
83
88
|
if (!query) {
|
|
84
89
|
return query
|
|
85
90
|
}
|
|
@@ -87,9 +92,10 @@ const cleanupQuery = (query: { [x: string]: { [x: string]: any } }) => {
|
|
|
87
92
|
if (!query[filterField]) {
|
|
88
93
|
continue
|
|
89
94
|
}
|
|
90
|
-
|
|
95
|
+
|
|
96
|
+
for (let [key, value] of Object.entries(query[filterField]!)) {
|
|
91
97
|
if (value == null || value === "") {
|
|
92
|
-
delete query[filterField][key]
|
|
98
|
+
delete query[filterField]![key]
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
}
|
|
@@ -117,21 +123,52 @@ type Filter = {
|
|
|
117
123
|
externalType: keyof typeof SqlNumberTypeRangeMap
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
type Query =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
type Query = QueryFields & QueryConfig
|
|
127
|
+
type QueryFields = {
|
|
128
|
+
string?: {
|
|
129
|
+
[key: string]: string
|
|
130
|
+
}
|
|
131
|
+
fuzzy?: {
|
|
132
|
+
[key: string]: string
|
|
133
|
+
}
|
|
134
|
+
range?: {
|
|
135
|
+
[key: string]: {
|
|
136
|
+
high: number | string
|
|
137
|
+
low: number | string
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
equal?: {
|
|
141
|
+
[key: string]: any
|
|
142
|
+
}
|
|
143
|
+
notEqual?: {
|
|
144
|
+
[key: string]: any
|
|
145
|
+
}
|
|
146
|
+
empty?: {
|
|
147
|
+
[key: string]: any
|
|
148
|
+
}
|
|
149
|
+
notEmpty?: {
|
|
150
|
+
[key: string]: any
|
|
151
|
+
}
|
|
152
|
+
oneOf?: {
|
|
153
|
+
[key: string]: any[]
|
|
154
|
+
}
|
|
155
|
+
contains?: {
|
|
156
|
+
[key: string]: any[]
|
|
157
|
+
}
|
|
158
|
+
notContains?: {
|
|
159
|
+
[key: string]: any[]
|
|
160
|
+
}
|
|
161
|
+
containsAny?: {
|
|
162
|
+
[key: string]: any[]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
type QueryConfig = {
|
|
132
167
|
allOr?: boolean
|
|
133
168
|
}
|
|
134
169
|
|
|
170
|
+
type QueryFieldsType = keyof QueryFields
|
|
171
|
+
|
|
135
172
|
/**
|
|
136
173
|
* Builds a lucene JSON query from the filter structure generated in the builder
|
|
137
174
|
* @param filter the builder filter structure
|
|
@@ -193,7 +230,7 @@ export const buildLuceneQuery = (filter: Filter[]) => {
|
|
|
193
230
|
) {
|
|
194
231
|
value = value.split(",")
|
|
195
232
|
}
|
|
196
|
-
if (operator.startsWith("range")) {
|
|
233
|
+
if (operator.startsWith("range") && query.range) {
|
|
197
234
|
const minint =
|
|
198
235
|
SqlNumberTypeRangeMap[externalType]?.min || Number.MIN_SAFE_INTEGER
|
|
199
236
|
const maxint =
|
|
@@ -219,14 +256,18 @@ export const buildLuceneQuery = (filter: Filter[]) => {
|
|
|
219
256
|
// "equals false" needs to be "not equals true"
|
|
220
257
|
// "not equals false" needs to be "equals true"
|
|
221
258
|
if (operator === "equal" && value === false) {
|
|
259
|
+
query.notEqual = query.notEqual || {}
|
|
222
260
|
query.notEqual[field] = true
|
|
223
261
|
} else if (operator === "notEqual" && value === false) {
|
|
262
|
+
query.equal = query.equal || {}
|
|
224
263
|
query.equal[field] = true
|
|
225
264
|
} else {
|
|
226
|
-
query[operator][
|
|
265
|
+
query[operator] = query[operator] || {}
|
|
266
|
+
query[operator]![field] = value
|
|
227
267
|
}
|
|
228
268
|
} else {
|
|
229
|
-
query[operator][
|
|
269
|
+
query[operator] = query[operator] || {}
|
|
270
|
+
query[operator]![field] = value
|
|
230
271
|
}
|
|
231
272
|
}
|
|
232
273
|
})
|
|
@@ -234,29 +275,12 @@ export const buildLuceneQuery = (filter: Filter[]) => {
|
|
|
234
275
|
return query
|
|
235
276
|
}
|
|
236
277
|
|
|
237
|
-
const deepGet = (obj: { [x: string]: any }, key: string) => {
|
|
238
|
-
if (!obj || !key) {
|
|
239
|
-
return null
|
|
240
|
-
}
|
|
241
|
-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
242
|
-
return obj[key]
|
|
243
|
-
}
|
|
244
|
-
const split = key.split(".")
|
|
245
|
-
for (let i = 0; i < split.length; i++) {
|
|
246
|
-
obj = obj?.[split[i]]
|
|
247
|
-
}
|
|
248
|
-
return obj
|
|
249
|
-
}
|
|
250
|
-
|
|
251
278
|
/**
|
|
252
279
|
* Performs a client-side lucene search on an array of data
|
|
253
280
|
* @param docs the data
|
|
254
281
|
* @param query the JSON lucene query
|
|
255
282
|
*/
|
|
256
|
-
export const runLuceneQuery = (
|
|
257
|
-
docs: any[],
|
|
258
|
-
query?: { [x: string]: any; sheet?: string }
|
|
259
|
-
) => {
|
|
283
|
+
export const runLuceneQuery = (docs: any[], query?: Query) => {
|
|
260
284
|
if (!docs || !Array.isArray(docs)) {
|
|
261
285
|
return []
|
|
262
286
|
}
|
|
@@ -269,7 +293,10 @@ export const runLuceneQuery = (
|
|
|
269
293
|
|
|
270
294
|
// Iterates over a set of filters and evaluates a fail function against a doc
|
|
271
295
|
const match =
|
|
272
|
-
(
|
|
296
|
+
(
|
|
297
|
+
type: QueryFieldsType,
|
|
298
|
+
failFn: (docValue: any, testValue: any) => boolean
|
|
299
|
+
) =>
|
|
273
300
|
(doc: any) => {
|
|
274
301
|
const filters = Object.entries(query![type] || {})
|
|
275
302
|
for (let i = 0; i < filters.length; i++) {
|
|
@@ -398,9 +425,9 @@ export const runLuceneQuery = (
|
|
|
398
425
|
*/
|
|
399
426
|
export const luceneSort = (
|
|
400
427
|
docs: any[],
|
|
401
|
-
sort: string
|
|
402
|
-
sortOrder:
|
|
403
|
-
sortType =
|
|
428
|
+
sort: string,
|
|
429
|
+
sortOrder: SortDirection,
|
|
430
|
+
sortType = SortType.STRING
|
|
404
431
|
) => {
|
|
405
432
|
if (!sort || !sortOrder || !sortType) {
|
|
406
433
|
return docs
|
|
@@ -412,7 +439,7 @@ export const luceneSort = (
|
|
|
412
439
|
.sort((a: { [x: string]: any }, b: { [x: string]: any }) => {
|
|
413
440
|
const colA = parse(a[sort])
|
|
414
441
|
const colB = parse(b[sort])
|
|
415
|
-
if (sortOrder === "
|
|
442
|
+
if (sortOrder.toLowerCase() === "descending") {
|
|
416
443
|
return colA > colB ? -1 : 1
|
|
417
444
|
} else {
|
|
418
445
|
return colA > colB ? 1 : -1
|
|
@@ -426,7 +453,7 @@ export const luceneSort = (
|
|
|
426
453
|
* @param docs the data
|
|
427
454
|
* @param limit the number of docs to limit to
|
|
428
455
|
*/
|
|
429
|
-
export const luceneLimit = (docs:
|
|
456
|
+
export const luceneLimit = (docs: any[], limit: string) => {
|
|
430
457
|
const numLimit = parseFloat(limit)
|
|
431
458
|
if (isNaN(numLimit)) {
|
|
432
459
|
return docs
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets a key within an object. The key supports dot syntax for retrieving deep
|
|
3
|
+
* fields - e.g. "a.b.c".
|
|
4
|
+
* Exact matches of keys with dots in them take precedence over nested keys of
|
|
5
|
+
* the same path - e.g. getting "a.b" from { "a.b": "foo", a: { b: "bar" } }
|
|
6
|
+
* will return "foo" over "bar".
|
|
7
|
+
* @param obj the object
|
|
8
|
+
* @param key the key
|
|
9
|
+
* @return {*|null} the value or null if a value was not found for this key
|
|
10
|
+
*/
|
|
11
|
+
export const deepGet = (obj: { [x: string]: any }, key: string) => {
|
|
12
|
+
if (!obj || !key) {
|
|
13
|
+
return null
|
|
14
|
+
}
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
16
|
+
return obj[key]
|
|
17
|
+
}
|
|
18
|
+
const split = key.split(".")
|
|
19
|
+
for (let i = 0; i < split.length; i++) {
|
|
20
|
+
obj = obj?.[split[i]]
|
|
21
|
+
}
|
|
22
|
+
return obj
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
package/src/utils.ts
ADDED
package/tsconfig.build.json
CHANGED
package/tsconfig.json
CHANGED
package/dist/src/index.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
-
};
|
|
21
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
22
|
-
if (mod && mod.__esModule) return mod;
|
|
23
|
-
var result = {};
|
|
24
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
25
|
-
__setModuleDefault(result, mod);
|
|
26
|
-
return result;
|
|
27
|
-
};
|
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.dataFilters = void 0;
|
|
30
|
-
__exportStar(require("./constants"), exports);
|
|
31
|
-
exports.dataFilters = __importStar(require("./filters"));
|
|
32
|
-
//# sourceMappingURL=index.js.map
|