@budibase/shared-core 2.3.21-alpha.2 → 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 CHANGED
@@ -1,19 +1,23 @@
1
1
  {
2
2
  "name": "@budibase/shared-core",
3
- "version": "2.3.21-alpha.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
- "build": "tsc",
11
- "dev:builder": "tsc --watch"
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"
12
15
  },
13
16
  "dependencies": {
14
- "@budibase/types": "2.3.21-alpha.2"
17
+ "@budibase/types": "2.4.5-alpha.0"
15
18
  },
16
19
  "devDependencies": {
17
- "typescript": "4.7.3"
20
+ "typescript": "4.7.3",
21
+ "rimraf": "3.0.2"
18
22
  }
19
23
  }
package/src/filters.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { SortDirection } from "@budibase/types"
1
+ import { Datasource, FieldType, SortDirection, SortType } from "@budibase/types"
2
2
  import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
3
+ import { deepGet } from "./helpers"
3
4
 
4
5
  const HBS_REGEX = /{{([^{].*?)}}/g
5
6
 
@@ -8,9 +9,9 @@ const HBS_REGEX = /{{([^{].*?)}}/g
8
9
  * @param type the data type
9
10
  */
10
11
  export const getValidOperatorsForType = (
11
- type: string,
12
+ type: FieldType,
12
13
  field: string,
13
- datasource: { tableId: string | string[]; type: string }
14
+ datasource: Datasource & { tableId: any } // TODO: is this table id ever populated?
14
15
  ) => {
15
16
  const Op = OperatorOptions
16
17
  const stringOps = [
@@ -31,7 +32,10 @@ export const getValidOperatorsForType = (
31
32
  Op.NotEmpty,
32
33
  Op.In,
33
34
  ]
34
- let ops: any[] = []
35
+ let ops: {
36
+ value: string
37
+ label: string
38
+ }[] = []
35
39
  if (type === "string") {
36
40
  ops = stringOps
37
41
  } else if (type === "number") {
@@ -74,13 +78,13 @@ export const NoEmptyFilterStrings = [
74
78
  OperatorOptions.NotEquals.value,
75
79
  OperatorOptions.Contains.value,
76
80
  OperatorOptions.NotContains.value,
77
- ]
81
+ ] as (keyof QueryFields)[]
78
82
 
79
83
  /**
80
84
  * Removes any fields that contain empty strings that would cause inconsistent
81
85
  * behaviour with how backend tables are filtered (no value means no filter).
82
86
  */
83
- const cleanupQuery = (query: { [x: string]: { [x: string]: any } }) => {
87
+ const cleanupQuery = (query: Query) => {
84
88
  if (!query) {
85
89
  return query
86
90
  }
@@ -88,9 +92,10 @@ const cleanupQuery = (query: { [x: string]: { [x: string]: any } }) => {
88
92
  if (!query[filterField]) {
89
93
  continue
90
94
  }
91
- for (let [key, value] of Object.entries(query[filterField])) {
95
+
96
+ for (let [key, value] of Object.entries(query[filterField]!)) {
92
97
  if (value == null || value === "") {
93
- delete query[filterField][key]
98
+ delete query[filterField]![key]
94
99
  }
95
100
  }
96
101
  }
@@ -118,21 +123,52 @@ type Filter = {
118
123
  externalType: keyof typeof SqlNumberTypeRangeMap
119
124
  }
120
125
 
121
- type Query = {
122
- string: Record<string, any>
123
- fuzzy: Record<string, any>
124
- range: Record<string, { low: string | number; high: string | number }>
125
- equal: Record<string, true>
126
- notEqual: Record<string, true>
127
- empty: Record<string, any>
128
- notEmpty: Record<string, any>
129
- contains: Record<string, any>
130
- notContains: Record<string, any>
131
- oneOf: Record<string, any>
132
- containsAny: Record<string, any>
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 = {
133
167
  allOr?: boolean
134
168
  }
135
169
 
170
+ type QueryFieldsType = keyof QueryFields
171
+
136
172
  /**
137
173
  * Builds a lucene JSON query from the filter structure generated in the builder
138
174
  * @param filter the builder filter structure
@@ -194,7 +230,7 @@ export const buildLuceneQuery = (filter: Filter[]) => {
194
230
  ) {
195
231
  value = value.split(",")
196
232
  }
197
- if (operator.startsWith("range")) {
233
+ if (operator.startsWith("range") && query.range) {
198
234
  const minint =
199
235
  SqlNumberTypeRangeMap[externalType]?.min || Number.MIN_SAFE_INTEGER
200
236
  const maxint =
@@ -220,14 +256,18 @@ export const buildLuceneQuery = (filter: Filter[]) => {
220
256
  // "equals false" needs to be "not equals true"
221
257
  // "not equals false" needs to be "equals true"
222
258
  if (operator === "equal" && value === false) {
259
+ query.notEqual = query.notEqual || {}
223
260
  query.notEqual[field] = true
224
261
  } else if (operator === "notEqual" && value === false) {
262
+ query.equal = query.equal || {}
225
263
  query.equal[field] = true
226
264
  } else {
227
- query[operator][field] = value
265
+ query[operator] = query[operator] || {}
266
+ query[operator]![field] = value
228
267
  }
229
268
  } else {
230
- query[operator][field] = value
269
+ query[operator] = query[operator] || {}
270
+ query[operator]![field] = value
231
271
  }
232
272
  }
233
273
  })
@@ -235,29 +275,12 @@ export const buildLuceneQuery = (filter: Filter[]) => {
235
275
  return query
236
276
  }
237
277
 
238
- const deepGet = (obj: { [x: string]: any }, key: string) => {
239
- if (!obj || !key) {
240
- return null
241
- }
242
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
243
- return obj[key]
244
- }
245
- const split = key.split(".")
246
- for (let i = 0; i < split.length; i++) {
247
- obj = obj?.[split[i]]
248
- }
249
- return obj
250
- }
251
-
252
278
  /**
253
279
  * Performs a client-side lucene search on an array of data
254
280
  * @param docs the data
255
281
  * @param query the JSON lucene query
256
282
  */
257
- export const runLuceneQuery = (
258
- docs: any[],
259
- query?: { [x: string]: any; sheet?: string }
260
- ) => {
283
+ export const runLuceneQuery = (docs: any[], query?: Query) => {
261
284
  if (!docs || !Array.isArray(docs)) {
262
285
  return []
263
286
  }
@@ -270,7 +293,10 @@ export const runLuceneQuery = (
270
293
 
271
294
  // Iterates over a set of filters and evaluates a fail function against a doc
272
295
  const match =
273
- (type: string, failFn: (docValue: any, testValue: any) => boolean) =>
296
+ (
297
+ type: QueryFieldsType,
298
+ failFn: (docValue: any, testValue: any) => boolean
299
+ ) =>
274
300
  (doc: any) => {
275
301
  const filters = Object.entries(query![type] || {})
276
302
  for (let i = 0; i < filters.length; i++) {
@@ -399,9 +425,9 @@ export const runLuceneQuery = (
399
425
  */
400
426
  export const luceneSort = (
401
427
  docs: any[],
402
- sort: string | number,
428
+ sort: string,
403
429
  sortOrder: SortDirection,
404
- sortType = "string"
430
+ sortType = SortType.STRING
405
431
  ) => {
406
432
  if (!sort || !sortOrder || !sortType) {
407
433
  return docs
@@ -427,7 +453,7 @@ export const luceneSort = (
427
453
  * @param docs the data
428
454
  * @param limit the number of docs to limit to
429
455
  */
430
- export const luceneLimit = (docs: string | any[], limit: string) => {
456
+ export const luceneLimit = (docs: any[], limit: string) => {
431
457
  const numLimit = parseFloat(limit)
432
458
  if (isNaN(numLimit)) {
433
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
@@ -1,2 +1,4 @@
1
1
  export * from "./constants"
2
2
  export * as dataFilters from "./filters"
3
+ export * as helpers from "./helpers"
4
+ export * as utils from "./utils"
package/src/utils.ts ADDED
@@ -0,0 +1,6 @@
1
+ export function unreachable(
2
+ value: never,
3
+ message = `No such case in exhaustive switch: ${value}`
4
+ ) {
5
+ throw new Error(message)
6
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "es6",
4
- "module": "commonjs",
4
+ "moduleResolution": "node",
5
5
  "lib": ["es2020"],
6
6
  "strict": true,
7
7
  "noImplicitAny": true,
package/tsconfig.json CHANGED
@@ -1,6 +1,11 @@
1
1
  {
2
2
  "extends": "./tsconfig.build.json",
3
3
  "compilerOptions": {
4
- "composite": true
5
- }
4
+ "composite": true,
5
+ "baseUrl": ".",
6
+ "paths": {
7
+ "@budibase/types": ["../types/src"]
8
+ }
9
+ },
10
+ "references": [{ "path": "../types" }]
6
11
  }