@budibase/backend-core 2.28.7 → 2.29.1

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/dist/index.js CHANGED
@@ -54802,6 +54802,20 @@ var SWITCHABLE_TYPES = {
54802
54802
  ["number" /* NUMBER */]: ["number" /* NUMBER */, "boolean" /* BOOLEAN */]
54803
54803
  };
54804
54804
 
54805
+ // ../shared-core/src/constants/rows.ts
54806
+ var CONSTANT_INTERNAL_ROW_COLS = [
54807
+ "_id",
54808
+ "_rev",
54809
+ "type",
54810
+ "createdAt",
54811
+ "updatedAt",
54812
+ "tableId"
54813
+ ];
54814
+ var CONSTANT_EXTERNAL_ROW_COLS = ["_id", "_rev", "tableId"];
54815
+ function isInternalColumnName(name) {
54816
+ return CONSTANT_INTERNAL_ROW_COLS.includes(name);
54817
+ }
54818
+
54805
54819
  // ../shared-core/src/constants/index.ts
54806
54820
  var OperatorOptions = {
54807
54821
  Equals: {
@@ -55217,10 +55231,15 @@ var search = (docs, query) => {
55217
55231
  if (query.sort) {
55218
55232
  result = sort(result, query.sort, query.sortOrder || "ascending" /* ASCENDING */);
55219
55233
  }
55234
+ let totalRows = result.length;
55220
55235
  if (query.limit) {
55221
55236
  result = limit(result, query.limit.toString());
55222
55237
  }
55223
- return result;
55238
+ const response = { rows: result };
55239
+ if (query.countRows) {
55240
+ response.totalRows = totalRows;
55241
+ }
55242
+ return response;
55224
55243
  };
55225
55244
  var runQuery = (docs, query) => {
55226
55245
  if (!docs || !Array.isArray(docs)) {
@@ -56728,20 +56747,6 @@ var DatabaseImpl = class _DatabaseImpl {
56728
56747
  }
56729
56748
  };
56730
56749
 
56731
- // src/db/constants.ts
56732
- var CONSTANT_INTERNAL_ROW_COLS = [
56733
- "_id",
56734
- "_rev",
56735
- "type",
56736
- "createdAt",
56737
- "updatedAt",
56738
- "tableId"
56739
- ];
56740
- var CONSTANT_EXTERNAL_ROW_COLS = ["_id", "_rev", "tableId"];
56741
- function isInternalColumnName(name) {
56742
- return CONSTANT_INTERNAL_ROW_COLS.includes(name);
56743
- }
56744
-
56745
56750
  // src/db/db.ts
56746
56751
  function getDB(dbName, opts) {
56747
56752
  return new DDInstrumentedDatabase(new DatabaseImpl(dbName, opts));
@@ -60035,6 +60040,7 @@ __export(tenancy_exports, {
60035
60040
  addTenantToUrl: () => addTenantToUrl,
60036
60041
  getTenantDB: () => getTenantDB,
60037
60042
  getTenantIDFromCtx: () => getTenantIDFromCtx,
60043
+ getTenantInfo: () => getTenantInfo,
60038
60044
  isUserInAppTenant: () => isUserInAppTenant,
60039
60045
  saveTenantInfo: () => saveTenantInfo
60040
60046
  });
@@ -60045,11 +60051,15 @@ function getTenantDB(tenantId) {
60045
60051
  }
60046
60052
  async function saveTenantInfo(tenantInfo) {
60047
60053
  const db = getTenantDB(tenantInfo.tenantId);
60048
- return await db.put({
60054
+ return db.put({
60049
60055
  _id: "tenant_info",
60050
60056
  ...tenantInfo
60051
60057
  });
60052
60058
  }
60059
+ async function getTenantInfo(tenantId) {
60060
+ const db = getTenantDB(tenantId);
60061
+ return db.get("tenant_info");
60062
+ }
60053
60063
 
60054
60064
  // src/tenancy/tenancy.ts
60055
60065
  function addTenantToUrl(url) {
@@ -67491,7 +67501,7 @@ function parseFilters(filters) {
67491
67501
  }
67492
67502
  function generateSelectStatement(json, knex3) {
67493
67503
  const { resource, meta } = json;
67494
- if (!resource) {
67504
+ if (!resource || !resource.fields || resource.fields.length === 0) {
67495
67505
  return "*";
67496
67506
  }
67497
67507
  const schema = meta?.table?.schema;
@@ -67738,12 +67748,26 @@ var InternalBuilder = class {
67738
67748
  }
67739
67749
  return query;
67740
67750
  }
67751
+ addDistinctCount(query, json) {
67752
+ const table = json.meta.table;
67753
+ const primary = table.primary;
67754
+ const aliases = json.tableAliases;
67755
+ const aliased = table.name && aliases?.[table.name] ? aliases[table.name] : table.name;
67756
+ if (!primary) {
67757
+ throw new Error("SQL counting requires primary key to be supplied");
67758
+ }
67759
+ return query.countDistinct(`${aliased}.${primary[0]} as total`);
67760
+ }
67741
67761
  addSorting(query, json) {
67742
- let { sort: sort2, paginate } = json;
67762
+ let { sort: sort2 } = json;
67743
67763
  const table = json.meta.table;
67764
+ const primaryKey = table.primary;
67744
67765
  const tableName = getTableName(table);
67745
67766
  const aliases = json.tableAliases;
67746
67767
  const aliased = tableName && aliases?.[tableName] ? aliases[tableName] : table?.name;
67768
+ if (!Array.isArray(primaryKey)) {
67769
+ throw new Error("Sorting requires primary key to be specified for table");
67770
+ }
67747
67771
  if (sort2 && Object.keys(sort2 || {}).length > 0) {
67748
67772
  for (let [key, value] of Object.entries(sort2)) {
67749
67773
  const direction = value.direction === "ascending" /* ASCENDING */ ? "asc" : "desc";
@@ -67753,9 +67777,8 @@ var InternalBuilder = class {
67753
67777
  }
67754
67778
  query = query.orderBy(`${aliased}.${key}`, direction, nulls);
67755
67779
  }
67756
- } else if (this.client === "mssql" /* MS_SQL */ && paginate?.limit) {
67757
- query = query.orderBy(`${aliased}.${table?.primary[0]}`);
67758
67780
  }
67781
+ query = query.orderBy(`${aliased}.${primaryKey[0]}`);
67759
67782
  return query;
67760
67783
  }
67761
67784
  tableNameWithSchema(tableName, opts) {
@@ -67823,18 +67846,17 @@ var InternalBuilder = class {
67823
67846
  });
67824
67847
  }
67825
67848
  }
67826
- return query.limit(BASE_LIMIT);
67849
+ return query;
67827
67850
  }
67828
67851
  knexWithAlias(knex3, endpoint, aliases) {
67829
67852
  const tableName = endpoint.entityId;
67830
67853
  const tableAlias = aliases?.[tableName];
67831
- const query = knex3(
67854
+ return knex3(
67832
67855
  this.tableNameWithSchema(tableName, {
67833
67856
  alias: tableAlias,
67834
67857
  schema: endpoint.schema
67835
67858
  })
67836
67859
  );
67837
- return query;
67838
67860
  }
67839
67861
  create(knex3, json, opts) {
67840
67862
  const { endpoint, body: body2 } = json;
@@ -67860,40 +67882,65 @@ var InternalBuilder = class {
67860
67882
  const parsedBody = body2.map((row) => parseBody(row));
67861
67883
  return query.insert(parsedBody);
67862
67884
  }
67863
- read(knex3, json, limit2) {
67864
- let { endpoint, resource, filters, paginate, relationships, tableAliases } = json;
67865
- const tableName = endpoint.entityId;
67866
- if (!resource) {
67867
- resource = { fields: [] };
67885
+ bulkUpsert(knex3, json) {
67886
+ const { endpoint, body: body2 } = json;
67887
+ let query = this.knexWithAlias(knex3, endpoint);
67888
+ if (!Array.isArray(body2)) {
67889
+ return query;
67868
67890
  }
67869
- let selectStatement = "*";
67870
- if (resource.fields && resource.fields.length > 0) {
67871
- selectStatement = generateSelectStatement(json, knex3);
67891
+ const parsedBody = body2.map((row) => parseBody(row));
67892
+ if (this.client === "pg" /* POSTGRES */ || this.client === "sqlite3" /* SQL_LITE */ || this.client === "mysql2" /* MY_SQL */) {
67893
+ const primary = json.meta.table.primary;
67894
+ if (!primary) {
67895
+ throw new Error("Primary key is required for upsert");
67896
+ }
67897
+ return query.insert(parsedBody).onConflict(primary).merge();
67898
+ } else if (this.client === "mssql" /* MS_SQL */) {
67899
+ return query.insert(parsedBody);
67872
67900
  }
67873
- let foundLimit = limit2 || BASE_LIMIT;
67901
+ return query.upsert(parsedBody);
67902
+ }
67903
+ read(knex3, json, opts = {}) {
67904
+ let { endpoint, filters, paginate, relationships, tableAliases } = json;
67905
+ const { limits } = opts;
67906
+ const counting = endpoint.operation === "COUNT" /* COUNT */;
67907
+ const tableName = endpoint.entityId;
67908
+ let query = this.knexWithAlias(knex3, endpoint, tableAliases);
67874
67909
  let foundOffset = null;
67910
+ let foundLimit = limits?.query || limits?.base;
67875
67911
  if (paginate && paginate.page && paginate.limit) {
67876
67912
  const page = paginate.page <= 1 ? 0 : paginate.page - 1;
67877
67913
  const offset = page * paginate.limit;
67878
67914
  foundLimit = paginate.limit;
67879
67915
  foundOffset = offset;
67916
+ } else if (paginate && paginate.offset && paginate.limit) {
67917
+ foundLimit = paginate.limit;
67918
+ foundOffset = paginate.offset;
67880
67919
  } else if (paginate && paginate.limit) {
67881
67920
  foundLimit = paginate.limit;
67882
67921
  }
67883
- let query = this.knexWithAlias(knex3, endpoint, tableAliases);
67884
- query = query.limit(foundLimit);
67885
- if (foundOffset) {
67886
- query = query.offset(foundOffset);
67922
+ if (!counting) {
67923
+ if (foundLimit != null) {
67924
+ query = query.limit(foundLimit);
67925
+ }
67926
+ if (foundOffset != null) {
67927
+ query = query.offset(foundOffset);
67928
+ }
67929
+ query = this.addSorting(query, json);
67887
67930
  }
67888
67931
  query = this.addFilters(query, filters, json.meta.table, {
67889
67932
  aliases: tableAliases
67890
67933
  });
67891
- query = this.addSorting(query, json);
67892
67934
  const alias = tableAliases?.[tableName] || tableName;
67893
67935
  let preQuery = knex3({
67936
+ // the typescript definition for the knex constructor doesn't support this
67937
+ // syntax, but it is the only way to alias a pre-query result as part of
67938
+ // a query - there is an alias dictionary type, but it assumes it can only
67939
+ // be a table name, not a pre-query
67894
67940
  [alias]: query
67895
- }).select(selectStatement);
67896
- if (this.client !== "mssql" /* MS_SQL */) {
67941
+ });
67942
+ preQuery = !counting ? preQuery.select(generateSelectStatement(json, knex3)) : this.addDistinctCount(preQuery, json);
67943
+ if (this.client !== "mssql" /* MS_SQL */ && !counting) {
67897
67944
  preQuery = this.addSorting(preQuery, json);
67898
67945
  }
67899
67946
  query = this.addRelationships(
@@ -67903,6 +67950,9 @@ var InternalBuilder = class {
67903
67950
  endpoint.schema,
67904
67951
  tableAliases
67905
67952
  );
67953
+ if (limits?.base) {
67954
+ query = query.limit(limits.base);
67955
+ }
67906
67956
  return this.addFilters(query, filters, json.meta.table, {
67907
67957
  relationship: true,
67908
67958
  aliases: tableAliases
@@ -67940,6 +67990,18 @@ var SqlQueryBuilder = class extends sqlTable_default {
67940
67990
  super(client);
67941
67991
  this.limit = limit2;
67942
67992
  }
67993
+ convertToNative(query, opts = {}) {
67994
+ const sqlClient = this.getSqlClient();
67995
+ if (opts?.disableBindings) {
67996
+ return { sql: query.toString() };
67997
+ } else {
67998
+ let native = getNativeSql(query);
67999
+ if (sqlClient === "sqlite3" /* SQL_LITE */) {
68000
+ native = convertBooleans(native);
68001
+ }
68002
+ return native;
68003
+ }
68004
+ }
67943
68005
  /**
67944
68006
  * @param json The JSON query DSL which is to be converted to SQL.
67945
68007
  * @param opts extra options which are to be passed into the query builder, e.g. disableReturning
@@ -67962,7 +68024,15 @@ var SqlQueryBuilder = class extends sqlTable_default {
67962
68024
  query = builder.create(client, json, opts);
67963
68025
  break;
67964
68026
  case "READ" /* READ */:
67965
- query = builder.read(client, json, this.limit);
68027
+ query = builder.read(client, json, {
68028
+ limits: {
68029
+ query: this.limit,
68030
+ base: BASE_LIMIT
68031
+ }
68032
+ });
68033
+ break;
68034
+ case "COUNT" /* COUNT */:
68035
+ query = builder.read(client, json);
67966
68036
  break;
67967
68037
  case "UPDATE" /* UPDATE */:
67968
68038
  query = builder.update(client, json, opts);
@@ -67973,6 +68043,9 @@ var SqlQueryBuilder = class extends sqlTable_default {
67973
68043
  case "BULK_CREATE" /* BULK_CREATE */:
67974
68044
  query = builder.bulkCreate(client, json);
67975
68045
  break;
68046
+ case "BULK_UPSERT" /* BULK_UPSERT */:
68047
+ query = builder.bulkUpsert(client, json);
68048
+ break;
67976
68049
  case "CREATE_TABLE" /* CREATE_TABLE */:
67977
68050
  case "UPDATE_TABLE" /* UPDATE_TABLE */:
67978
68051
  case "DELETE_TABLE" /* DELETE_TABLE */:
@@ -67980,15 +68053,7 @@ var SqlQueryBuilder = class extends sqlTable_default {
67980
68053
  default:
67981
68054
  throw `Operation type is not supported by SQL query builder`;
67982
68055
  }
67983
- if (opts?.disableBindings) {
67984
- return { sql: query.toString() };
67985
- } else {
67986
- let native = getNativeSql(query);
67987
- if (sqlClient === "sqlite3" /* SQL_LITE */) {
67988
- native = convertBooleans(native);
67989
- }
67990
- return native;
67991
- }
68056
+ return this.convertToNative(query, opts);
67992
68057
  }
67993
68058
  async getReturningRow(queryFn, json) {
67994
68059
  if (!json.extra || !json.extra.idFilter) {
@@ -68055,6 +68120,9 @@ var SqlQueryBuilder = class extends sqlTable_default {
68055
68120
  await this.getReturningRow(queryFn, this.checkLookupKeys(id, json))
68056
68121
  );
68057
68122
  }
68123
+ if (operation === "COUNT" /* COUNT */) {
68124
+ return results;
68125
+ }
68058
68126
  if (operation !== "READ" /* READ */) {
68059
68127
  return row;
68060
68128
  }