@budibase/server 2.3.18-alpha.1 → 2.3.18-alpha.11
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/builder/assets/blankScreenPreview.72634dd1.png +0 -0
- package/builder/assets/index.22724f34.css +6 -0
- package/builder/assets/{index.7089444f.js → index.7503d634.js} +368 -361
- package/builder/assets/listScreenPreview.599c0aae.png +0 -0
- package/builder/index.html +2 -2
- package/dist/api/controllers/automation.js +11 -2
- package/dist/api/controllers/row/ExternalRequest.js +47 -22
- package/dist/api/controllers/row/external.js +1 -1
- package/dist/api/routes/automation.js +1 -1
- package/dist/integrations/base/sql.js +2 -6
- package/dist/middleware/authorized.js +5 -3
- package/dist/middleware/builder.js +6 -3
- package/dist/package.json +7 -7
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/scripts/test.sh +12 -0
- package/src/api/controllers/automation.ts +13 -2
- package/src/api/controllers/row/ExternalRequest.ts +93 -25
- package/src/api/controllers/row/external.ts +1 -1
- package/src/api/routes/automation.ts +1 -1
- package/src/integration-test/postgres.spec.ts +351 -81
- package/src/integrations/base/sql.ts +2 -6
- package/src/middleware/authorized.ts +6 -4
- package/src/middleware/builder.ts +8 -3
- package/builder/assets/index.7e76c039.css +0 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "2.3.18-alpha.
|
|
4
|
+
"version": "2.3.18-alpha.11",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"repository": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build:dev": "yarn prebuild && tsc --build --watch --preserveWatchOutput",
|
|
15
15
|
"debug": "yarn build && node --expose-gc --inspect=9222 dist/index.js",
|
|
16
16
|
"postbuild": "copyfiles -u 1 src/**/*.svelte dist/ && copyfiles -u 1 src/**/*.hbs dist/ && copyfiles -u 1 src/**/*.json dist/",
|
|
17
|
-
"test": "
|
|
17
|
+
"test": "bash scripts/test.sh",
|
|
18
18
|
"test:watch": "jest --watch",
|
|
19
19
|
"predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client",
|
|
20
20
|
"build:docker": "yarn run predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION",
|
|
@@ -43,11 +43,11 @@
|
|
|
43
43
|
"license": "GPL-3.0",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@apidevtools/swagger-parser": "10.0.3",
|
|
46
|
-
"@budibase/backend-core": "2.3.18-alpha.
|
|
47
|
-
"@budibase/client": "2.3.18-alpha.
|
|
48
|
-
"@budibase/pro": "2.3.18-alpha.
|
|
49
|
-
"@budibase/string-templates": "2.3.18-alpha.
|
|
50
|
-
"@budibase/types": "2.3.18-alpha.
|
|
46
|
+
"@budibase/backend-core": "2.3.18-alpha.11",
|
|
47
|
+
"@budibase/client": "2.3.18-alpha.11",
|
|
48
|
+
"@budibase/pro": "2.3.18-alpha.10",
|
|
49
|
+
"@budibase/string-templates": "2.3.18-alpha.11",
|
|
50
|
+
"@budibase/types": "2.3.18-alpha.11",
|
|
51
51
|
"@bull-board/api": "3.7.0",
|
|
52
52
|
"@bull-board/koa": "3.9.4",
|
|
53
53
|
"@elastic/elasticsearch": "7.10.0",
|
|
@@ -173,5 +173,5 @@
|
|
|
173
173
|
"optionalDependencies": {
|
|
174
174
|
"oracledb": "5.3.0"
|
|
175
175
|
},
|
|
176
|
-
"gitHead": "
|
|
176
|
+
"gitHead": "90c32a8e5c78d8861b52e1f99b4e632c70e05841"
|
|
177
177
|
}
|
package/scripts/test.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
if [[ -n $CI ]]
|
|
4
|
+
then
|
|
5
|
+
# --runInBand performs better in ci where resources are limited
|
|
6
|
+
echo "jest --coverage --runInBand"
|
|
7
|
+
jest --coverage --runInBand
|
|
8
|
+
else
|
|
9
|
+
# --maxWorkers performs better in development
|
|
10
|
+
echo "jest --coverage --maxWorkers=2"
|
|
11
|
+
jest --coverage --maxWorkers=2
|
|
12
|
+
fi
|
|
@@ -65,10 +65,14 @@ export async function create(ctx: BBContext) {
|
|
|
65
65
|
|
|
66
66
|
// call through to update if already exists
|
|
67
67
|
if (automation._id && automation._rev) {
|
|
68
|
-
|
|
68
|
+
await update(ctx)
|
|
69
|
+
return
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
// Respect existing IDs if recreating a deleted automation
|
|
73
|
+
if (!automation._id) {
|
|
74
|
+
automation._id = generateAutomationID()
|
|
75
|
+
}
|
|
72
76
|
|
|
73
77
|
automation.type = "automation"
|
|
74
78
|
automation = cleanAutomationInputs(automation)
|
|
@@ -126,6 +130,13 @@ export async function update(ctx: BBContext) {
|
|
|
126
130
|
const db = context.getAppDB()
|
|
127
131
|
let automation = ctx.request.body
|
|
128
132
|
automation.appId = ctx.appId
|
|
133
|
+
|
|
134
|
+
// Call through to create if it doesn't exist
|
|
135
|
+
if (!automation._id || !automation._rev) {
|
|
136
|
+
await create(ctx)
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
129
140
|
const oldAutomation = await db.get(automation._id)
|
|
130
141
|
automation = cleanAutomationInputs(automation)
|
|
131
142
|
automation = await checkForWebhooks({
|
|
@@ -142,7 +142,11 @@ function cleanupConfig(config: RunConfig, table: Table): RunConfig {
|
|
|
142
142
|
return config
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
function generateIdForRow(
|
|
145
|
+
function generateIdForRow(
|
|
146
|
+
row: Row | undefined,
|
|
147
|
+
table: Table,
|
|
148
|
+
isLinked: boolean = false
|
|
149
|
+
): string {
|
|
146
150
|
const primary = table.primary
|
|
147
151
|
if (!row || !primary) {
|
|
148
152
|
return ""
|
|
@@ -150,8 +154,12 @@ function generateIdForRow(row: Row | undefined, table: Table): string {
|
|
|
150
154
|
// build id array
|
|
151
155
|
let idParts = []
|
|
152
156
|
for (let field of primary) {
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
let fieldValue = extractFieldValue({
|
|
158
|
+
row,
|
|
159
|
+
tableName: table.name,
|
|
160
|
+
fieldName: field,
|
|
161
|
+
isLinked,
|
|
162
|
+
})
|
|
155
163
|
if (fieldValue) {
|
|
156
164
|
idParts.push(fieldValue)
|
|
157
165
|
}
|
|
@@ -174,18 +182,52 @@ function getEndpoint(tableId: string | undefined, operation: string) {
|
|
|
174
182
|
}
|
|
175
183
|
}
|
|
176
184
|
|
|
177
|
-
|
|
185
|
+
// need to handle table name + field or just field, depending on if relationships used
|
|
186
|
+
function extractFieldValue({
|
|
187
|
+
row,
|
|
188
|
+
tableName,
|
|
189
|
+
fieldName,
|
|
190
|
+
isLinked,
|
|
191
|
+
}: {
|
|
192
|
+
row: Row
|
|
193
|
+
tableName: string
|
|
194
|
+
fieldName: string
|
|
195
|
+
isLinked: boolean
|
|
196
|
+
}) {
|
|
197
|
+
let value = row[`${tableName}.${fieldName}`]
|
|
198
|
+
if (value == null && !isLinked) {
|
|
199
|
+
value = row[fieldName]
|
|
200
|
+
}
|
|
201
|
+
return value
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function basicProcessing({
|
|
205
|
+
row,
|
|
206
|
+
table,
|
|
207
|
+
isLinked,
|
|
208
|
+
}: {
|
|
209
|
+
row: Row
|
|
210
|
+
table: Table
|
|
211
|
+
isLinked: boolean
|
|
212
|
+
}): Row {
|
|
178
213
|
const thisRow: Row = {}
|
|
179
214
|
// filter the row down to what is actually the row (not joined)
|
|
180
|
-
for (let
|
|
181
|
-
const
|
|
182
|
-
|
|
215
|
+
for (let field of Object.values(table.schema)) {
|
|
216
|
+
const fieldName = field.name
|
|
217
|
+
|
|
218
|
+
const value = extractFieldValue({
|
|
219
|
+
row,
|
|
220
|
+
tableName: table.name,
|
|
221
|
+
fieldName,
|
|
222
|
+
isLinked,
|
|
223
|
+
})
|
|
224
|
+
|
|
183
225
|
// all responses include "select col as table.col" so that overlaps are handled
|
|
184
226
|
if (value != null) {
|
|
185
227
|
thisRow[fieldName] = value
|
|
186
228
|
}
|
|
187
229
|
}
|
|
188
|
-
thisRow._id = generateIdForRow(row, table)
|
|
230
|
+
thisRow._id = generateIdForRow(row, table, isLinked)
|
|
189
231
|
thisRow.tableId = table._id
|
|
190
232
|
thisRow._rev = "rev"
|
|
191
233
|
return processFormulas(table, thisRow)
|
|
@@ -293,7 +335,7 @@ export class ExternalRequest {
|
|
|
293
335
|
// we're not inserting a doc, will be a bunch of update calls
|
|
294
336
|
const otherKey: string = field.throughFrom || linkTablePrimary
|
|
295
337
|
const thisKey: string = field.throughTo || tablePrimary
|
|
296
|
-
row[key].
|
|
338
|
+
row[key].forEach((relationship: any) => {
|
|
297
339
|
manyRelationships.push({
|
|
298
340
|
tableId: field.through || field.tableId,
|
|
299
341
|
isUpdate: false,
|
|
@@ -309,7 +351,7 @@ export class ExternalRequest {
|
|
|
309
351
|
const thisKey: string = "id"
|
|
310
352
|
// @ts-ignore
|
|
311
353
|
const otherKey: string = field.fieldName
|
|
312
|
-
row[key].
|
|
354
|
+
row[key].forEach((relationship: any) => {
|
|
313
355
|
manyRelationships.push({
|
|
314
356
|
tableId: field.tableId,
|
|
315
357
|
isUpdate: true,
|
|
@@ -379,7 +421,8 @@ export class ExternalRequest {
|
|
|
379
421
|
) {
|
|
380
422
|
continue
|
|
381
423
|
}
|
|
382
|
-
|
|
424
|
+
|
|
425
|
+
let linked = basicProcessing({ row, table: linkedTable, isLinked: true })
|
|
383
426
|
if (!linked._id) {
|
|
384
427
|
continue
|
|
385
428
|
}
|
|
@@ -427,7 +470,10 @@ export class ExternalRequest {
|
|
|
427
470
|
)
|
|
428
471
|
continue
|
|
429
472
|
}
|
|
430
|
-
const thisRow = fixArrayTypes(
|
|
473
|
+
const thisRow = fixArrayTypes(
|
|
474
|
+
basicProcessing({ row, table, isLinked: false }),
|
|
475
|
+
table
|
|
476
|
+
)
|
|
431
477
|
if (thisRow._id == null) {
|
|
432
478
|
throw "Unable to generate row ID for SQL rows"
|
|
433
479
|
}
|
|
@@ -567,19 +613,41 @@ export class ExternalRequest {
|
|
|
567
613
|
const { key, tableId, isUpdate, id, ...rest } = relationship
|
|
568
614
|
const body: { [key: string]: any } = processObjectSync(rest, row, {})
|
|
569
615
|
const linkTable = this.getTable(tableId)
|
|
570
|
-
|
|
571
|
-
const linkPrimary =
|
|
616
|
+
const relationshipPrimary = linkTable?.primary || []
|
|
617
|
+
const linkPrimary = relationshipPrimary[0]
|
|
572
618
|
if (!linkTable || !linkPrimary) {
|
|
573
619
|
return
|
|
574
620
|
}
|
|
621
|
+
|
|
622
|
+
const linkSecondary = relationshipPrimary[1]
|
|
623
|
+
|
|
575
624
|
const rows = related[key]?.rows || []
|
|
576
|
-
|
|
577
|
-
|
|
625
|
+
|
|
626
|
+
function relationshipMatchPredicate({
|
|
627
|
+
row,
|
|
628
|
+
linkPrimary,
|
|
629
|
+
linkSecondary,
|
|
630
|
+
}: {
|
|
631
|
+
row: { [key: string]: any }
|
|
632
|
+
linkPrimary: string
|
|
633
|
+
linkSecondary?: string
|
|
634
|
+
}) {
|
|
635
|
+
const matchesPrimaryLink =
|
|
578
636
|
row[linkPrimary] === relationship.id ||
|
|
579
637
|
row[linkPrimary] === body?.[linkPrimary]
|
|
638
|
+
if (!matchesPrimaryLink || !linkSecondary) {
|
|
639
|
+
return matchesPrimaryLink
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const matchesSecondayLink = row[linkSecondary] === body?.[linkSecondary]
|
|
643
|
+
return matchesPrimaryLink && matchesSecondayLink
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const existingRelationship = rows.find((row: { [key: string]: any }) =>
|
|
647
|
+
relationshipMatchPredicate({ row, linkPrimary, linkSecondary })
|
|
580
648
|
)
|
|
581
649
|
const operation = isUpdate ? Operation.UPDATE : Operation.CREATE
|
|
582
|
-
if (!
|
|
650
|
+
if (!existingRelationship) {
|
|
583
651
|
promises.push(
|
|
584
652
|
getDatasourceAndQuery({
|
|
585
653
|
endpoint: getEndpoint(tableId, operation),
|
|
@@ -590,7 +658,7 @@ export class ExternalRequest {
|
|
|
590
658
|
)
|
|
591
659
|
} else {
|
|
592
660
|
// remove the relationship from cache so it isn't adjusted again
|
|
593
|
-
rows.splice(rows.indexOf(
|
|
661
|
+
rows.splice(rows.indexOf(existingRelationship), 1)
|
|
594
662
|
}
|
|
595
663
|
}
|
|
596
664
|
// finally cleanup anything that needs to be removed
|
|
@@ -629,10 +697,7 @@ export class ExternalRequest {
|
|
|
629
697
|
* Creating the specific list of fields that we desire, and excluding the ones that are no use to us
|
|
630
698
|
* is more performant and has the added benefit of protecting against this scenario.
|
|
631
699
|
*/
|
|
632
|
-
buildFields(
|
|
633
|
-
table: Table,
|
|
634
|
-
includeRelations: IncludeRelationship = IncludeRelationship.INCLUDE
|
|
635
|
-
) {
|
|
700
|
+
buildFields(table: Table, includeRelations: boolean) {
|
|
636
701
|
function extractRealFields(table: Table, existing: string[] = []) {
|
|
637
702
|
return Object.entries(table.schema)
|
|
638
703
|
.filter(
|
|
@@ -691,6 +756,10 @@ export class ExternalRequest {
|
|
|
691
756
|
}
|
|
692
757
|
filters = buildFilters(id, filters || {}, table)
|
|
693
758
|
const relationships = this.buildRelationships(table)
|
|
759
|
+
|
|
760
|
+
const includeSqlRelationships =
|
|
761
|
+
config.includeSqlRelationships === IncludeRelationship.INCLUDE
|
|
762
|
+
|
|
694
763
|
// clean up row on ingress using schema
|
|
695
764
|
const processed = this.inputProcessing(row, table)
|
|
696
765
|
row = processed.row
|
|
@@ -708,9 +777,7 @@ export class ExternalRequest {
|
|
|
708
777
|
},
|
|
709
778
|
resource: {
|
|
710
779
|
// have to specify the fields to avoid column overlap (for SQL)
|
|
711
|
-
fields: isSql
|
|
712
|
-
? this.buildFields(table, config.includeSqlRelationships)
|
|
713
|
-
: [],
|
|
780
|
+
fields: isSql ? this.buildFields(table, includeSqlRelationships) : [],
|
|
714
781
|
},
|
|
715
782
|
filters,
|
|
716
783
|
sort,
|
|
@@ -725,6 +792,7 @@ export class ExternalRequest {
|
|
|
725
792
|
table,
|
|
726
793
|
},
|
|
727
794
|
}
|
|
795
|
+
|
|
728
796
|
// can't really use response right now
|
|
729
797
|
const response = await getDatasourceAndQuery(json)
|
|
730
798
|
// handle many to many relationships now if we know the ID (could be auto increment)
|
|
@@ -58,7 +58,7 @@ export async function patch(ctx: BBContext) {
|
|
|
58
58
|
return handleRequest(Operation.UPDATE, tableId, {
|
|
59
59
|
id: breakRowIdField(id),
|
|
60
60
|
row: inputs,
|
|
61
|
-
includeSqlRelationships: IncludeRelationship.
|
|
61
|
+
includeSqlRelationships: IncludeRelationship.INCLUDE,
|
|
62
62
|
})
|
|
63
63
|
}
|
|
64
64
|
|