@budibase/server 2.4.40 → 2.4.41

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/server",
3
3
  "email": "hi@budibase.com",
4
- "version": "2.4.40",
4
+ "version": "2.4.41",
5
5
  "description": "Budibase Web Server",
6
6
  "main": "src/index.ts",
7
7
  "repository": {
@@ -43,12 +43,12 @@
43
43
  "license": "GPL-3.0",
44
44
  "dependencies": {
45
45
  "@apidevtools/swagger-parser": "10.0.3",
46
- "@budibase/backend-core": "^2.4.40",
47
- "@budibase/client": "^2.4.40",
48
- "@budibase/pro": "2.4.39",
49
- "@budibase/shared-core": "^2.4.40",
50
- "@budibase/string-templates": "^2.4.40",
51
- "@budibase/types": "^2.4.40",
46
+ "@budibase/backend-core": "^2.4.41",
47
+ "@budibase/client": "^2.4.41",
48
+ "@budibase/pro": "2.4.40",
49
+ "@budibase/shared-core": "^2.4.41",
50
+ "@budibase/string-templates": "^2.4.41",
51
+ "@budibase/types": "^2.4.41",
52
52
  "@bull-board/api": "3.7.0",
53
53
  "@bull-board/koa": "3.9.4",
54
54
  "@elastic/elasticsearch": "7.10.0",
@@ -175,5 +175,5 @@
175
175
  "optionalDependencies": {
176
176
  "oracledb": "5.3.0"
177
177
  },
178
- "gitHead": "8d1f12dfbecf020366571d81c5dc8db9f968afc7"
178
+ "gitHead": "70af1866b81511c67e5f3b407507fc6f416d8786"
179
179
  }
@@ -84,8 +84,9 @@ export async function buildSchemaFromDb(ctx: UserCtx) {
84
84
  setDefaultDisplayColumns(datasource)
85
85
  const dbResp = await db.put(datasource)
86
86
  datasource._rev = dbResp.rev
87
+ const cleanedDatasource = await sdk.datasources.removeSecretSingle(datasource)
87
88
 
88
- const response: any = { datasource }
89
+ const response: any = { datasource: cleanedDatasource }
89
90
  if (error) {
90
91
  response.error = error
91
92
  }
@@ -12,7 +12,7 @@ import * as exporters from "../view/exporters"
12
12
  import { apiFileReturn } from "../../../utilities/fileSystem"
13
13
  import {
14
14
  Operation,
15
- BBContext,
15
+ UserCtx,
16
16
  Row,
17
17
  PaginationJson,
18
18
  Table,
@@ -21,6 +21,7 @@ import {
21
21
  SortJson,
22
22
  } from "@budibase/types"
23
23
  import sdk from "../../../sdk"
24
+ import * as utils from "./utils"
24
25
 
25
26
  const { cleanExportRows } = require("./utils")
26
27
 
@@ -49,7 +50,7 @@ export async function handleRequest(
49
50
  )
50
51
  }
51
52
 
52
- export async function patch(ctx: BBContext) {
53
+ export async function patch(ctx: UserCtx) {
53
54
  const inputs = ctx.request.body
54
55
  const tableId = ctx.params.tableId
55
56
  const id = inputs._id
@@ -62,7 +63,7 @@ export async function patch(ctx: BBContext) {
62
63
  })
63
64
  }
64
65
 
65
- export async function save(ctx: BBContext) {
66
+ export async function save(ctx: UserCtx) {
66
67
  const inputs = ctx.request.body
67
68
  const tableId = ctx.params.tableId
68
69
  return handleRequest(Operation.CREATE, tableId, {
@@ -71,7 +72,7 @@ export async function save(ctx: BBContext) {
71
72
  })
72
73
  }
73
74
 
74
- export async function fetchView(ctx: BBContext) {
75
+ export async function fetchView(ctx: UserCtx) {
75
76
  // there are no views in external datasources, shouldn't ever be called
76
77
  // for now just fetch
77
78
  const split = ctx.params.viewName.split("all_")
@@ -79,14 +80,14 @@ export async function fetchView(ctx: BBContext) {
79
80
  return fetch(ctx)
80
81
  }
81
82
 
82
- export async function fetch(ctx: BBContext) {
83
+ export async function fetch(ctx: UserCtx) {
83
84
  const tableId = ctx.params.tableId
84
85
  return handleRequest(Operation.READ, tableId, {
85
86
  includeSqlRelationships: IncludeRelationship.INCLUDE,
86
87
  })
87
88
  }
88
89
 
89
- export async function find(ctx: BBContext) {
90
+ export async function find(ctx: UserCtx) {
90
91
  const id = ctx.params.rowId
91
92
  const tableId = ctx.params.tableId
92
93
  const response = (await handleRequest(Operation.READ, tableId, {
@@ -96,7 +97,7 @@ export async function find(ctx: BBContext) {
96
97
  return response ? response[0] : response
97
98
  }
98
99
 
99
- export async function destroy(ctx: BBContext) {
100
+ export async function destroy(ctx: UserCtx) {
100
101
  const tableId = ctx.params.tableId
101
102
  const id = ctx.request.body._id
102
103
  const { row } = (await handleRequest(Operation.DELETE, tableId, {
@@ -106,7 +107,7 @@ export async function destroy(ctx: BBContext) {
106
107
  return { response: { ok: true }, row }
107
108
  }
108
109
 
109
- export async function bulkDestroy(ctx: BBContext) {
110
+ export async function bulkDestroy(ctx: UserCtx) {
110
111
  const { rows } = ctx.request.body
111
112
  const tableId = ctx.params.tableId
112
113
  let promises: Promise<Row[] | { row: Row; table: Table }>[] = []
@@ -122,7 +123,7 @@ export async function bulkDestroy(ctx: BBContext) {
122
123
  return { response: { ok: true }, rows: responses.map(resp => resp.row) }
123
124
  }
124
125
 
125
- export async function search(ctx: BBContext) {
126
+ export async function search(ctx: UserCtx) {
126
127
  const tableId = ctx.params.tableId
127
128
  const { paginate, query, ...params } = ctx.request.body
128
129
  let { bookmark, limit } = params
@@ -185,12 +186,7 @@ export async function search(ctx: BBContext) {
185
186
  }
186
187
  }
187
188
 
188
- export async function validate(ctx: BBContext) {
189
- // can't validate external right now - maybe in future
190
- return { valid: true }
191
- }
192
-
193
- export async function exportRows(ctx: BBContext) {
189
+ export async function exportRows(ctx: UserCtx) {
194
190
  const { datasourceId, tableName } = breakExternalTableId(ctx.params.tableId)
195
191
  const format = ctx.query.format
196
192
  const { columns } = ctx.request.body
@@ -244,7 +240,7 @@ export async function exportRows(ctx: BBContext) {
244
240
  return apiFileReturn(exporter(headers, exportRows))
245
241
  }
246
242
 
247
- export async function fetchEnrichedRow(ctx: BBContext) {
243
+ export async function fetchEnrichedRow(ctx: UserCtx) {
248
244
  const id = ctx.params.rowId
249
245
  const tableId = ctx.params.tableId
250
246
  const { datasourceId, tableName } = breakExternalTableId(tableId)
@@ -2,6 +2,8 @@ import { quotas } from "@budibase/pro"
2
2
  import * as internal from "./internal"
3
3
  import * as external from "./external"
4
4
  import { isExternalTable } from "../../../integrations/utils"
5
+ import { Ctx } from "@budibase/types"
6
+ import * as utils from "./utils"
5
7
 
6
8
  function pickApi(tableId: any) {
7
9
  if (isExternalTable(tableId)) {
@@ -129,9 +131,17 @@ export async function search(ctx: any) {
129
131
  })
130
132
  }
131
133
 
132
- export async function validate(ctx: any) {
134
+ export async function validate(ctx: Ctx) {
133
135
  const tableId = getTableId(ctx)
134
- ctx.body = await pickApi(tableId).validate(ctx)
136
+ // external tables are hard to validate currently
137
+ if (isExternalTable(tableId)) {
138
+ ctx.body = { valid: true }
139
+ } else {
140
+ ctx.body = await utils.validate({
141
+ row: ctx.request.body,
142
+ tableId,
143
+ })
144
+ }
135
145
  }
136
146
 
137
147
  export async function fetchEnrichedRow(ctx: any) {
@@ -387,13 +387,6 @@ export async function search(ctx: Ctx) {
387
387
  return response
388
388
  }
389
389
 
390
- export async function validate(ctx: Ctx) {
391
- return utils.validate({
392
- tableId: ctx.params.tableId,
393
- row: ctx.request.body,
394
- })
395
- }
396
-
397
390
  export async function exportRows(ctx: Ctx) {
398
391
  const db = context.getAppDB()
399
392
  const table = await db.get(ctx.params.tableId)
@@ -4,11 +4,11 @@ import { FieldTypes } from "../../../constants"
4
4
  import { context } from "@budibase/backend-core"
5
5
  import { makeExternalQuery } from "../../../integrations/base/query"
6
6
  import { Row, Table } from "@budibase/types"
7
- const validateJs = require("validate.js")
8
- const { cloneDeep } = require("lodash/fp")
9
7
  import { Format } from "../view/exporters"
10
8
  import { Ctx } from "@budibase/types"
11
9
  import sdk from "../../../sdk"
10
+ const validateJs = require("validate.js")
11
+ const { cloneDeep } = require("lodash/fp")
12
12
 
13
13
  validateJs.extend(validateJs.validators.datetime, {
14
14
  parse: function (value: string) {
@@ -56,8 +56,7 @@ export async function validate({
56
56
  }) {
57
57
  let fetchedTable: Table
58
58
  if (!table) {
59
- const db = context.getAppDB()
60
- fetchedTable = await db.get(tableId)
59
+ fetchedTable = await sdk.tables.getTable(tableId)
61
60
  } else {
62
61
  fetchedTable = table
63
62
  }
@@ -7,6 +7,7 @@ import {
7
7
  generateJunctionTableName,
8
8
  foreignKeyStructure,
9
9
  hasTypeChanged,
10
+ setStaticSchemas,
10
11
  } from "./utils"
11
12
  import { FieldTypes } from "../../../constants"
12
13
  import { makeExternalQuery } from "../../../integrations/base/query"
@@ -20,7 +21,7 @@ import {
20
21
  Operation,
21
22
  RenameColumn,
22
23
  FieldSchema,
23
- BBContext,
24
+ UserCtx,
24
25
  TableRequest,
25
26
  RelationshipTypes,
26
27
  } from "@budibase/types"
@@ -194,20 +195,20 @@ function isRelationshipSetup(column: FieldSchema) {
194
195
  return column.foreignKey || column.through
195
196
  }
196
197
 
197
- export async function save(ctx: BBContext) {
198
- const table: TableRequest = ctx.request.body
199
- const renamed = table?._rename
198
+ export async function save(ctx: UserCtx) {
199
+ const inputs: TableRequest = ctx.request.body
200
+ const renamed = inputs?._rename
200
201
  // can't do this right now
201
- delete table.rows
202
+ delete inputs.rows
202
203
  const datasourceId = getDatasourceId(ctx.request.body)!
203
204
  // table doesn't exist already, note that it is created
204
- if (!table._id) {
205
- table.created = true
205
+ if (!inputs._id) {
206
+ inputs.created = true
206
207
  }
207
208
  let tableToSave: TableRequest = {
208
209
  type: "table",
209
- _id: buildExternalTableId(datasourceId, table.name),
210
- ...table,
210
+ _id: buildExternalTableId(datasourceId, inputs.name),
211
+ ...inputs,
211
212
  }
212
213
 
213
214
  let oldTable
@@ -224,6 +225,10 @@ export async function save(ctx: BBContext) {
224
225
  if (!datasource.entities) {
225
226
  datasource.entities = {}
226
227
  }
228
+
229
+ // GSheets is a specific case - only ever has a static primary key
230
+ tableToSave = setStaticSchemas(datasource, tableToSave)
231
+
227
232
  const oldTables = cloneDeep(datasource.entities)
228
233
  const tables: Record<string, Table> = datasource.entities
229
234
 
@@ -246,7 +251,7 @@ export async function save(ctx: BBContext) {
246
251
  const junctionTable = generateManyLinkSchema(
247
252
  datasource,
248
253
  schema,
249
- table,
254
+ tableToSave,
250
255
  relatedTable
251
256
  )
252
257
  if (tables[junctionTable.name]) {
@@ -256,10 +261,12 @@ export async function save(ctx: BBContext) {
256
261
  extraTablesToUpdate.push(junctionTable)
257
262
  } else {
258
263
  const fkTable =
259
- relationType === RelationshipTypes.ONE_TO_MANY ? table : relatedTable
264
+ relationType === RelationshipTypes.ONE_TO_MANY
265
+ ? tableToSave
266
+ : relatedTable
260
267
  const foreignKey = generateLinkSchema(
261
268
  schema,
262
- table,
269
+ tableToSave,
263
270
  relatedTable,
264
271
  relationType
265
272
  )
@@ -271,11 +278,11 @@ export async function save(ctx: BBContext) {
271
278
  fkTable.constrained.push(foreignKey)
272
279
  }
273
280
  // foreign key is in other table, need to save it to external
274
- if (fkTable._id !== table._id) {
281
+ if (fkTable._id !== tableToSave._id) {
275
282
  extraTablesToUpdate.push(fkTable)
276
283
  }
277
284
  }
278
- generateRelatedSchema(schema, relatedTable, table, relatedColumnName)
285
+ generateRelatedSchema(schema, relatedTable, tableToSave, relatedColumnName)
279
286
  schema.main = true
280
287
  }
281
288
 
@@ -313,7 +320,7 @@ export async function save(ctx: BBContext) {
313
320
  return tableToSave
314
321
  }
315
322
 
316
- export async function destroy(ctx: BBContext) {
323
+ export async function destroy(ctx: UserCtx) {
317
324
  const tableToDelete: TableRequest = await sdk.tables.getTable(
318
325
  ctx.params.tableId
319
326
  )
@@ -339,7 +346,7 @@ export async function destroy(ctx: BBContext) {
339
346
  return tableToDelete
340
347
  }
341
348
 
342
- export async function bulkImport(ctx: BBContext) {
349
+ export async function bulkImport(ctx: UserCtx) {
343
350
  const table = await sdk.tables.getTable(ctx.params.tableId)
344
351
  const { rows }: { rows: unknown } = ctx.request.body
345
352
  const schema: unknown = table.schema
@@ -348,7 +355,7 @@ export async function bulkImport(ctx: BBContext) {
348
355
  ctx.throw(400, "Provided data import information is invalid.")
349
356
  }
350
357
 
351
- const parsedRows = await parse(rows, schema)
358
+ const parsedRows = parse(rows, schema)
352
359
  await handleRequest(Operation.BULK_CREATE, table._id!, {
353
360
  rows: parsedRows,
354
361
  })
@@ -8,7 +8,7 @@ import {
8
8
  import { isExternalTable, isSQL } from "../../../integrations/utils"
9
9
  import { getDatasourceParams } from "../../../db/utils"
10
10
  import { context, events } from "@budibase/backend-core"
11
- import { Table, BBContext } from "@budibase/types"
11
+ import { Table, UserCtx } from "@budibase/types"
12
12
  import sdk from "../../../sdk"
13
13
  import csv from "csvtojson"
14
14
 
@@ -25,7 +25,7 @@ function pickApi({ tableId, table }: { tableId?: string; table?: Table }) {
25
25
  }
26
26
 
27
27
  // covers both internal and external
28
- export async function fetch(ctx: BBContext) {
28
+ export async function fetch(ctx: UserCtx) {
29
29
  const db = context.getAppDB()
30
30
 
31
31
  const internal = await sdk.tables.getAllInternalTables()
@@ -53,12 +53,12 @@ export async function fetch(ctx: BBContext) {
53
53
  ctx.body = [...internal, ...external]
54
54
  }
55
55
 
56
- export async function find(ctx: BBContext) {
56
+ export async function find(ctx: UserCtx) {
57
57
  const tableId = ctx.params.tableId
58
58
  ctx.body = await sdk.tables.getTable(tableId)
59
59
  }
60
60
 
61
- export async function save(ctx: BBContext) {
61
+ export async function save(ctx: UserCtx) {
62
62
  const appId = ctx.appId
63
63
  const table = ctx.request.body
64
64
  const isImport = table.rows
@@ -79,7 +79,7 @@ export async function save(ctx: BBContext) {
79
79
  ctx.body = savedTable
80
80
  }
81
81
 
82
- export async function destroy(ctx: BBContext) {
82
+ export async function destroy(ctx: UserCtx) {
83
83
  const appId = ctx.appId
84
84
  const tableId = ctx.params.tableId
85
85
  const deletedTable = await pickApi({ tableId }).destroy(ctx)
@@ -91,7 +91,7 @@ export async function destroy(ctx: BBContext) {
91
91
  ctx.body = { message: `Table ${tableId} deleted.` }
92
92
  }
93
93
 
94
- export async function bulkImport(ctx: BBContext) {
94
+ export async function bulkImport(ctx: UserCtx) {
95
95
  const tableId = ctx.params.tableId
96
96
  await pickApi({ tableId }).bulkImport(ctx)
97
97
  // right now we don't trigger anything for bulk import because it
@@ -101,7 +101,7 @@ export async function bulkImport(ctx: BBContext) {
101
101
  ctx.body = { message: `Bulk rows created.` }
102
102
  }
103
103
 
104
- export async function csvToJson(ctx: BBContext) {
104
+ export async function csvToJson(ctx: UserCtx) {
105
105
  const { csvString } = ctx.request.body
106
106
 
107
107
  const result = await csv().fromString(csvString)
@@ -110,7 +110,7 @@ export async function csvToJson(ctx: BBContext) {
110
110
  ctx.body = result
111
111
  }
112
112
 
113
- export async function validateNewTableImport(ctx: BBContext) {
113
+ export async function validateNewTableImport(ctx: UserCtx) {
114
114
  const { rows, schema }: { rows: unknown; schema: unknown } = ctx.request.body
115
115
 
116
116
  if (isRows(rows) && isSchema(schema)) {
@@ -121,7 +121,7 @@ export async function validateNewTableImport(ctx: BBContext) {
121
121
  }
122
122
  }
123
123
 
124
- export async function validateExistingTableImport(ctx: BBContext) {
124
+ export async function validateExistingTableImport(ctx: UserCtx) {
125
125
  const { rows, tableId }: { rows: unknown; tableId: unknown } =
126
126
  ctx.request.body
127
127
 
@@ -1,7 +1,11 @@
1
1
  import { parse, isSchema, isRows } from "../../../utilities/schema"
2
2
  import { getRowParams, generateRowID, InternalTables } from "../../../db/utils"
3
3
  import { isEqual } from "lodash"
4
- import { AutoFieldSubTypes, FieldTypes } from "../../../constants"
4
+ import {
5
+ AutoFieldSubTypes,
6
+ FieldTypes,
7
+ GOOGLE_SHEETS_PRIMARY_KEY,
8
+ } from "../../../constants"
5
9
  import {
6
10
  inputProcessing,
7
11
  cleanupAttachments,
@@ -16,7 +20,7 @@ import viewTemplate from "../view/viewBuilder"
16
20
  import { cloneDeep } from "lodash/fp"
17
21
  import { quotas } from "@budibase/pro"
18
22
  import { events, context } from "@budibase/backend-core"
19
- import { Database } from "@budibase/types"
23
+ import { Database, Datasource, SourceName, Table } from "@budibase/types"
20
24
 
21
25
  export async function clearColumns(table: any, columnNames: any) {
22
26
  const db: Database = context.getAppDB()
@@ -392,5 +396,17 @@ export function hasTypeChanged(table: any, oldTable: any) {
392
396
  return false
393
397
  }
394
398
 
399
+ // used for external tables, some of them will have static schemas that need
400
+ // to be hard set
401
+ export function setStaticSchemas(datasource: Datasource, table: Table) {
402
+ // GSheets is a specific case - only ever has a static primary key
403
+ if (table && datasource.source === SourceName.GOOGLE_SHEETS) {
404
+ table.primary = [GOOGLE_SHEETS_PRIMARY_KEY]
405
+ // if there is an id column, remove it, should never exist in GSheets
406
+ delete table.schema?.id
407
+ }
408
+ return table
409
+ }
410
+
395
411
  const _TableSaveFunctions = TableSaveFunctions
396
412
  export { _TableSaveFunctions as TableSaveFunctions }
@@ -180,3 +180,4 @@ export enum AutomationErrors {
180
180
  // pass through the list from the auth/core lib
181
181
  export const ObjectStoreBuckets = objectStore.ObjectStoreBuckets
182
182
  export const MAX_AUTOMATION_RECURRING_ERRORS = 5
183
+ export const GOOGLE_SHEETS_PRIMARY_KEY = "rowNumber"