@budibase/backend-core 2.33.2 → 2.33.4

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.
Files changed (53) hide show
  1. package/dist/index.js +566 -309
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.js.meta.json +1 -1
  4. package/dist/package.json +4 -4
  5. package/dist/plugins.js.map +1 -1
  6. package/dist/plugins.js.meta.json +1 -1
  7. package/dist/src/context/identity.js +1 -1
  8. package/dist/src/context/identity.js.map +1 -1
  9. package/dist/src/db/couch/DatabaseImpl.js +1 -1
  10. package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
  11. package/dist/src/environment.js +28 -14
  12. package/dist/src/environment.js.map +1 -1
  13. package/dist/src/events/identification.js +7 -5
  14. package/dist/src/events/identification.js.map +1 -1
  15. package/dist/src/features/features.d.ts +1 -0
  16. package/dist/src/features/features.js +4 -3
  17. package/dist/src/features/features.js.map +1 -1
  18. package/dist/src/index.d.ts +0 -2
  19. package/dist/src/middleware/authenticated.js +16 -8
  20. package/dist/src/middleware/authenticated.js.map +1 -1
  21. package/dist/src/security/roles.d.ts +24 -3
  22. package/dist/src/security/roles.js +210 -51
  23. package/dist/src/security/roles.js.map +1 -1
  24. package/dist/src/sql/sql.js +243 -160
  25. package/dist/src/sql/sql.js.map +1 -1
  26. package/dist/src/sql/sqlTable.js +4 -1
  27. package/dist/src/sql/sqlTable.js.map +1 -1
  28. package/dist/src/tenancy/db.d.ts +0 -3
  29. package/dist/src/tenancy/db.js +0 -31
  30. package/dist/src/tenancy/db.js.map +1 -1
  31. package/dist/src/users/db.d.ts +2 -2
  32. package/dist/src/users/db.js +7 -7
  33. package/dist/src/users/db.js.map +1 -1
  34. package/dist/src/users/users.d.ts +1 -0
  35. package/dist/src/users/users.js +13 -0
  36. package/dist/src/users/users.js.map +1 -1
  37. package/dist/src/users/utils.d.ts +3 -3
  38. package/dist/src/users/utils.js +5 -14
  39. package/dist/src/users/utils.js.map +1 -1
  40. package/package.json +4 -4
  41. package/src/context/identity.ts +1 -1
  42. package/src/db/couch/DatabaseImpl.ts +2 -1
  43. package/src/environment.ts +33 -17
  44. package/src/events/identification.ts +7 -6
  45. package/src/features/features.ts +4 -3
  46. package/src/middleware/authenticated.ts +33 -17
  47. package/src/security/roles.ts +238 -56
  48. package/src/sql/sql.ts +290 -206
  49. package/src/sql/sqlTable.ts +4 -1
  50. package/src/tenancy/db.ts +0 -23
  51. package/src/users/db.ts +12 -9
  52. package/src/users/users.ts +11 -0
  53. package/src/users/utils.ts +12 -18
package/dist/index.js CHANGED
@@ -33554,14 +33554,14 @@ var require_putty = __commonJS({
33554
33554
  var buf = rfc4253.write(key);
33555
33555
  var comment = key.comment || "";
33556
33556
  var b64 = buf.toString("base64");
33557
- var lines = wrap(b64, 64);
33557
+ var lines = wrap2(b64, 64);
33558
33558
  lines.unshift("Public-Lines: " + lines.length);
33559
33559
  lines.unshift("Comment: " + comment);
33560
33560
  lines.unshift("Encryption: none");
33561
33561
  lines.unshift("PuTTY-User-Key-File-2: " + alg);
33562
33562
  return Buffer2.from(lines.join("\n") + "\n");
33563
33563
  }
33564
- function wrap(txt, len) {
33564
+ function wrap2(txt, len) {
33565
33565
  var lines = [];
33566
33566
  var pos = 0;
33567
33567
  while (pos < txt.length) {
@@ -49489,7 +49489,7 @@ var require_util2 = __commonJS({
49489
49489
  coerceToTypes,
49490
49490
  toHash,
49491
49491
  getProperty,
49492
- escapeQuotes,
49492
+ escapeQuotes: escapeQuotes2,
49493
49493
  equal: require_fast_deep_equal(),
49494
49494
  ucs2length: require_ucs2length(),
49495
49495
  varOccurences,
@@ -49578,9 +49578,9 @@ var require_util2 = __commonJS({
49578
49578
  var IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i;
49579
49579
  var SINGLE_QUOTE = /'|\\/g;
49580
49580
  function getProperty(key) {
49581
- return typeof key == "number" ? "[" + key + "]" : IDENTIFIER.test(key) ? "." + key : "['" + escapeQuotes(key) + "']";
49581
+ return typeof key == "number" ? "[" + key + "]" : IDENTIFIER.test(key) ? "." + key : "['" + escapeQuotes2(key) + "']";
49582
49582
  }
49583
- function escapeQuotes(str) {
49583
+ function escapeQuotes2(str) {
49584
49584
  return str.replace(SINGLE_QUOTE, "\\$&").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\f/g, "\\f").replace(/\t/g, "\\t");
49585
49585
  }
49586
49586
  function varOccurences(str, dataVar) {
@@ -49615,7 +49615,7 @@ var require_util2 = __commonJS({
49615
49615
  return key;
49616
49616
  }
49617
49617
  function toQuotedString(str) {
49618
- return "'" + escapeQuotes(str) + "'";
49618
+ return "'" + escapeQuotes2(str) + "'";
49619
49619
  }
49620
49620
  function getPathExpr(currentPath, expr, jsonPointers, isNumber) {
49621
49621
  var path3 = jsonPointers ? "'/' + " + expr + (isNumber ? "" : ".replace(/~/g, '~0').replace(/\\//g, '~1')") : isNumber ? "'[' + " + expr + " + ']'" : "'[\\'' + " + expr + " + '\\']'";
@@ -56189,8 +56189,8 @@ var require_oauth4 = __commonJS({
56189
56189
  var sha1 = shasum.digest("hex");
56190
56190
  return Buffer2.from(sha1, "hex").toString("base64");
56191
56191
  };
56192
- OAuth.prototype.concatParams = function(oa, sep, wrap) {
56193
- wrap = wrap || "";
56192
+ OAuth.prototype.concatParams = function(oa, sep, wrap2) {
56193
+ wrap2 = wrap2 || "";
56194
56194
  var params2 = Object.keys(oa).filter(function(i) {
56195
56195
  return i !== "realm" && i !== "oauth_signature";
56196
56196
  }).sort();
@@ -56199,7 +56199,7 @@ var require_oauth4 = __commonJS({
56199
56199
  }
56200
56200
  params2.push("oauth_signature");
56201
56201
  return params2.map(function(i) {
56202
- return i + "=" + wrap + oauth.rfc3986(oa[i]) + wrap;
56202
+ return i + "=" + wrap2 + oauth.rfc3986(oa[i]) + wrap2;
56203
56203
  }).join(sep);
56204
56204
  };
56205
56205
  OAuth.prototype.onRequest = function(_oauth) {
@@ -61253,7 +61253,7 @@ __export(src_exports, {
61253
61253
  plugins: () => plugin_exports,
61254
61254
  queue: () => queue_exports,
61255
61255
  redis: () => redis_exports,
61256
- roles: () => roles_exports,
61256
+ roles: () => roles_exports2,
61257
61257
  security: () => security_exports,
61258
61258
  sessions: () => sessions_exports,
61259
61259
  setEnv: () => setEnv,
@@ -62109,6 +62109,7 @@ __export(helpers_exports, {
62109
62109
  getUserLabel: () => getUserLabel,
62110
62110
  isGoogleSheets: () => isGoogleSheets,
62111
62111
  isSQL: () => isSQL,
62112
+ roles: () => roles_exports,
62112
62113
  schema: () => schema_exports,
62113
62114
  views: () => views_exports,
62114
62115
  withTimeout: () => withTimeout
@@ -62334,6 +62335,48 @@ function basicFields(view, opts) {
62334
62335
  });
62335
62336
  }
62336
62337
 
62338
+ // ../shared-core/src/helpers/roles.ts
62339
+ var roles_exports = {};
62340
+ __export(roles_exports, {
62341
+ checkForRoleInheritanceLoops: () => checkForRoleInheritanceLoops
62342
+ });
62343
+ function prefixForCheck(id) {
62344
+ return `${"role" /* ROLE */}${SEPARATOR}${id}`;
62345
+ }
62346
+ function checkForRoleInheritanceLoops(roles) {
62347
+ const roleMap = /* @__PURE__ */ new Map();
62348
+ roles.forEach((role) => {
62349
+ roleMap.set(role._id, role);
62350
+ });
62351
+ const checked = /* @__PURE__ */ new Set();
62352
+ const checking = /* @__PURE__ */ new Set();
62353
+ function hasLoop(roleId) {
62354
+ const prefixed2 = prefixForCheck(roleId);
62355
+ if (checking.has(roleId) || checking.has(prefixed2)) {
62356
+ return true;
62357
+ }
62358
+ if (checked.has(roleId) || checked.has(prefixed2)) {
62359
+ return false;
62360
+ }
62361
+ checking.add(roleId);
62362
+ const role = roleMap.get(prefixed2) || roleMap.get(roleId);
62363
+ if (!role) {
62364
+ checking.delete(roleId);
62365
+ return false;
62366
+ }
62367
+ const inherits = Array.isArray(role.inherits) ? role.inherits : [role.inherits];
62368
+ for (const inheritedId of inherits) {
62369
+ if (inheritedId && hasLoop(inheritedId)) {
62370
+ return true;
62371
+ }
62372
+ }
62373
+ checking.delete(roleId);
62374
+ checked.add(roleId);
62375
+ return false;
62376
+ }
62377
+ return !!roles.find((role) => hasLoop(role._id));
62378
+ }
62379
+
62337
62380
  // ../shared-core/src/filters.ts
62338
62381
  var import_lodash2 = require("lodash");
62339
62382
  var HBS_REGEX = /{{([^{].*?)}}/g;
@@ -63244,6 +63287,7 @@ var allowDisplayColumnByType = {
63244
63287
  ["number" /* NUMBER */]: true,
63245
63288
  ["datetime" /* DATETIME */]: true,
63246
63289
  ["formula" /* FORMULA */]: true,
63290
+ ["ai" /* AI */]: true,
63247
63291
  ["auto" /* AUTO */]: true,
63248
63292
  ["internal" /* INTERNAL */]: true,
63249
63293
  ["barcodeqr" /* BARCODEQR */]: true,
@@ -63271,6 +63315,7 @@ var allowSortColumnByType = {
63271
63315
  ["boolean" /* BOOLEAN */]: true,
63272
63316
  ["json" /* JSON */]: true,
63273
63317
  ["formula" /* FORMULA */]: false,
63318
+ ["ai" /* AI */]: false,
63274
63319
  ["attachment" /* ATTACHMENTS */]: false,
63275
63320
  ["attachment_single" /* ATTACHMENT_SINGLE */]: false,
63276
63321
  ["signature_single" /* SIGNATURE_SINGLE */]: false,
@@ -63293,6 +63338,7 @@ var allowDefaultColumnByType = {
63293
63338
  ["bigint" /* BIGINT */]: false,
63294
63339
  ["boolean" /* BOOLEAN */]: false,
63295
63340
  ["formula" /* FORMULA */]: false,
63341
+ ["ai" /* AI */]: false,
63296
63342
  ["attachment" /* ATTACHMENTS */]: false,
63297
63343
  ["attachment_single" /* ATTACHMENT_SINGLE */]: false,
63298
63344
  ["signature_single" /* SIGNATURE_SINGLE */]: false,
@@ -63498,7 +63544,7 @@ function doInUserContext(user, ctx, task) {
63498
63544
  hostInfo: {
63499
63545
  ipAddress: ctx.request.ip,
63500
63546
  // filled in by koa-useragent package
63501
- userAgent: ctx.userAgent._agent.source
63547
+ userAgent: ctx.userAgent.source
63502
63548
  }
63503
63549
  };
63504
63550
  return doInIdentityContext2(userContext, task);
@@ -63560,23 +63606,35 @@ function httpLogging() {
63560
63606
  return process.env.HTTP_LOGGING;
63561
63607
  }
63562
63608
  function getPackageJsonFields() {
63563
- function findFileInAncestors(fileName, currentDir) {
63564
- const filePath = `${currentDir}/${fileName}`;
63565
- if ((0, import_fs.existsSync)(filePath)) {
63566
- return filePath;
63609
+ function getParentFile(file) {
63610
+ function findFileInAncestors(fileName, currentDir) {
63611
+ const filePath = `${currentDir}/${fileName}`;
63612
+ if ((0, import_fs.existsSync)(filePath)) {
63613
+ return filePath;
63614
+ }
63615
+ const parentDir = `${currentDir}/..`;
63616
+ if (parentDir === currentDir) {
63617
+ return null;
63618
+ }
63619
+ return findFileInAncestors(fileName, parentDir);
63567
63620
  }
63568
- const parentDir = `${currentDir}/..`;
63569
- if (parentDir === currentDir) {
63570
- return null;
63621
+ const packageJsonFile = findFileInAncestors(file, process.cwd());
63622
+ const content = (0, import_fs.readFileSync)(packageJsonFile, "utf-8");
63623
+ const parsedContent = JSON.parse(content);
63624
+ return parsedContent;
63625
+ }
63626
+ let localVersion;
63627
+ if (isDev() && !isTest()) {
63628
+ try {
63629
+ const lerna = getParentFile("lerna.json");
63630
+ localVersion = `${lerna.version}+local`;
63631
+ } catch {
63571
63632
  }
63572
- return findFileInAncestors(fileName, parentDir);
63573
63633
  }
63574
63634
  try {
63575
- const packageJsonFile = findFileInAncestors("package.json", process.cwd());
63576
- const content = (0, import_fs.readFileSync)(packageJsonFile, "utf-8");
63577
- const parsedContent = JSON.parse(content);
63635
+ const parsedContent = getParentFile("package.json");
63578
63636
  return {
63579
- VERSION: process.env.BUDIBASE_VERSION || parsedContent.version,
63637
+ VERSION: localVersion || process.env.BUDIBASE_VERSION || parsedContent.version,
63580
63638
  SERVICE_NAME: parsedContent.name
63581
63639
  };
63582
63640
  } catch {
@@ -66555,7 +66613,7 @@ var QueryBuilder = class _QueryBuilder {
66555
66613
  preprocess(value, {
66556
66614
  escape,
66557
66615
  lowercase,
66558
- wrap,
66616
+ wrap: wrap2,
66559
66617
  type
66560
66618
  } = {}) {
66561
66619
  const hasVersion = !!this.#version;
@@ -66568,7 +66626,7 @@ var QueryBuilder = class _QueryBuilder {
66568
66626
  }
66569
66627
  if (originalType === "string" && !isNaN(value) && !type) {
66570
66628
  value = `"${value}"`;
66571
- } else if (hasVersion && wrap) {
66629
+ } else if (hasVersion && wrap2) {
66572
66630
  value = originalType === "number" ? value : `"${value}"`;
66573
66631
  }
66574
66632
  return value;
@@ -67209,32 +67267,13 @@ __export(tenancy_exports, {
67209
67267
  addTenantToUrl: () => addTenantToUrl,
67210
67268
  getTenantDB: () => getTenantDB,
67211
67269
  getTenantIDFromCtx: () => getTenantIDFromCtx,
67212
- getTenantInfo: () => getTenantInfo,
67213
- isUserInAppTenant: () => isUserInAppTenant,
67214
- saveTenantInfo: () => saveTenantInfo
67270
+ isUserInAppTenant: () => isUserInAppTenant
67215
67271
  });
67216
67272
 
67217
67273
  // src/tenancy/db.ts
67218
67274
  function getTenantDB(tenantId) {
67219
67275
  return getDB(getGlobalDBName(tenantId));
67220
67276
  }
67221
- async function saveTenantInfo(tenantInfo) {
67222
- const db = getTenantDB(tenantInfo.tenantId);
67223
- return db.put({
67224
- _id: "tenant_info",
67225
- ...tenantInfo
67226
- });
67227
- }
67228
- async function getTenantInfo(tenantId) {
67229
- try {
67230
- const db = getTenantDB(tenantId);
67231
- const tenantInfo = await db.get("tenant_info");
67232
- delete tenantInfo.owner.password;
67233
- return tenantInfo;
67234
- } catch {
67235
- return void 0;
67236
- }
67237
- }
67238
67277
 
67239
67278
  // src/tenancy/tenancy.ts
67240
67279
  function addTenantToUrl(url) {
@@ -67726,12 +67765,13 @@ var FlagSet = class {
67726
67765
  }
67727
67766
  };
67728
67767
  var flags = new FlagSet({
67729
- DEFAULT_VALUES: Flag.boolean(environment_default.isDev()),
67730
- AUTOMATION_BRANCHING: Flag.boolean(environment_default.isDev()),
67731
- SQS: Flag.boolean(true),
67768
+ ["DEFAULT_VALUES" /* DEFAULT_VALUES */]: Flag.boolean(environment_default.isDev()),
67769
+ ["AUTOMATION_BRANCHING" /* AUTOMATION_BRANCHING */]: Flag.boolean(environment_default.isDev()),
67770
+ ["SQS" /* SQS */]: Flag.boolean(true),
67732
67771
  ["AI_CUSTOM_CONFIGS" /* AI_CUSTOM_CONFIGS */]: Flag.boolean(environment_default.isDev()),
67733
67772
  ["ENRICHED_RELATIONSHIPS" /* ENRICHED_RELATIONSHIPS */]: Flag.boolean(environment_default.isDev()),
67734
- ["TABLES_DEFAULT_ADMIN" /* TABLES_DEFAULT_ADMIN */]: Flag.boolean(environment_default.isDev())
67773
+ ["TABLES_DEFAULT_ADMIN" /* TABLES_DEFAULT_ADMIN */]: Flag.boolean(environment_default.isDev()),
67774
+ ["BUDIBASE_AI" /* BUDIBASE_AI */]: Flag.boolean(environment_default.isDev())
67735
67775
  });
67736
67776
 
67737
67777
  // src/features/tests/utils.ts
@@ -68119,7 +68159,7 @@ var DatabaseImpl = class _DatabaseImpl {
68119
68159
  });
68120
68160
  }
68121
68161
  async destroy() {
68122
- if (await flags.isEnabled("SQS") && await this.exists(SQLITE_DESIGN_DOC_ID)) {
68162
+ if (await flags.isEnabled("SQS" /* SQS */) && await this.exists(SQLITE_DESIGN_DOC_ID)) {
68123
68163
  const definition = await this.get(SQLITE_DESIGN_DOC_ID);
68124
68164
  definition.sql.tables = {};
68125
68165
  await this.put(definition);
@@ -69065,8 +69105,9 @@ __export(users_exports3, {
69065
69105
  bulkUpdateGlobalUsers: () => bulkUpdateGlobalUsers,
69066
69106
  cleanseUserObject: () => cleanseUserObject,
69067
69107
  doesUserExist: () => doesUserExist,
69068
- getAccountHolderFromUserIds: () => getAccountHolderFromUserIds,
69108
+ getAccountHolderFromUsers: () => getAccountHolderFromUsers,
69069
69109
  getAllUserIds: () => getAllUserIds,
69110
+ getAllUsers: () => getAllUsers,
69070
69111
  getById: () => getById,
69071
69112
  getCreatorCount: () => getCreatorCount,
69072
69113
  getExistingAccounts: () => getExistingAccounts,
@@ -69098,7 +69139,7 @@ __export(users_exports3, {
69098
69139
  // src/users/utils.ts
69099
69140
  var utils_exports6 = {};
69100
69141
  __export(utils_exports6, {
69101
- getAccountHolderFromUserIds: () => getAccountHolderFromUserIds,
69142
+ getAccountHolderFromUsers: () => getAccountHolderFromUsers,
69102
69143
  hasAdminPermissions: () => hasAdminPermissions2,
69103
69144
  hasAppBuilderPermissions: () => hasAppBuilderPermissions2,
69104
69145
  hasBuilderPermissions: () => hasBuilderPermissions2,
@@ -69321,27 +69362,35 @@ var EmailUnavailableError = class extends Error {
69321
69362
  };
69322
69363
 
69323
69364
  // src/security/roles.ts
69324
- var roles_exports = {};
69325
- __export(roles_exports, {
69365
+ var roles_exports2 = {};
69366
+ __export(roles_exports2, {
69326
69367
  AccessController: () => AccessController,
69327
69368
  BUILTIN_ROLE_IDS: () => BUILTIN_ROLE_IDS,
69328
- Role: () => Role,
69369
+ Role: () => Role2,
69370
+ RoleHierarchyTraversal: () => RoleHierarchyTraversal,
69329
69371
  RoleIDVersion: () => RoleIDVersion,
69330
69372
  builtinRoleToNumber: () => builtinRoleToNumber,
69331
69373
  checkForRoleResourceArray: () => checkForRoleResourceArray,
69374
+ compareRoleIds: () => compareRoleIds,
69375
+ externalRole: () => externalRole,
69376
+ findRole: () => findRole,
69332
69377
  getAllRoleIds: () => getAllRoleIds,
69333
69378
  getAllRoles: () => getAllRoles,
69334
69379
  getBuiltinRole: () => getBuiltinRole,
69335
69380
  getBuiltinRoles: () => getBuiltinRoles,
69336
69381
  getDBRoleID: () => getDBRoleID,
69337
69382
  getExternalRoleID: () => getExternalRoleID,
69383
+ getExternalRoleIDs: () => getExternalRoleIDs,
69338
69384
  getRole: () => getRole,
69339
69385
  getUserRoleHierarchy: () => getUserRoleHierarchy,
69340
69386
  getUserRoleIdHierarchy: () => getUserRoleIdHierarchy,
69341
69387
  isBuiltin: () => isBuiltin,
69342
69388
  lowerBuiltinRoleID: () => lowerBuiltinRoleID,
69343
- roleToNumber: () => roleToNumber
69389
+ prefixRoleIDNoBuiltin: () => prefixRoleIDNoBuiltin,
69390
+ roleToNumber: () => roleToNumber,
69391
+ saveRoles: () => saveRoles
69344
69392
  });
69393
+ var import_semver = __toESM(require("semver"));
69345
69394
 
69346
69395
  // src/security/permissions.ts
69347
69396
  var permissions_exports = {};
@@ -69493,6 +69542,7 @@ var GLOBAL_BUILDER = "globalBuilder" /* GLOBAL_BUILDER */;
69493
69542
 
69494
69543
  // src/security/roles.ts
69495
69544
  var import_cloneDeep2 = __toESM(require("lodash/fp/cloneDeep"));
69545
+ var import_lodash4 = require("lodash");
69496
69546
  var BUILTIN_ROLE_IDS = {
69497
69547
  ADMIN: "ADMIN",
69498
69548
  POWER: "POWER",
@@ -69503,19 +69553,20 @@ var BUILTIN_IDS = {
69503
69553
  ...BUILTIN_ROLE_IDS,
69504
69554
  BUILDER: "BUILDER"
69505
69555
  };
69506
- var EXTERNAL_BUILTIN_ROLE_IDS = [
69507
- BUILTIN_IDS.ADMIN,
69508
- BUILTIN_IDS.POWER,
69509
- BUILTIN_IDS.BASIC,
69510
- BUILTIN_IDS.PUBLIC
69511
- ];
69512
69556
  var RoleIDVersion = {
69513
69557
  // original version, with a UUID based ID
69514
69558
  UUID: void 0,
69515
69559
  // new version - with name based ID
69516
69560
  NAME: "name"
69517
69561
  };
69518
- var Role = class {
69562
+ function rolesInList(roleIds, ids) {
69563
+ if (Array.isArray(ids)) {
69564
+ return ids.filter((id) => roleIds.includes(id)).length === ids.length;
69565
+ } else {
69566
+ return roleIds.includes(ids);
69567
+ }
69568
+ }
69569
+ var Role2 = class {
69519
69570
  constructor(id, name, permissionId, uiMetadata) {
69520
69571
  this.permissions = {};
69521
69572
  this._id = id;
@@ -69525,12 +69576,57 @@ var Role = class {
69525
69576
  this.version = RoleIDVersion.NAME;
69526
69577
  }
69527
69578
  addInheritance(inherits) {
69579
+ if (inherits && typeof inherits === "string") {
69580
+ inherits = prefixRoleIDNoBuiltin(inherits);
69581
+ } else if (inherits && Array.isArray(inherits)) {
69582
+ inherits = inherits.map(prefixRoleIDNoBuiltin);
69583
+ }
69528
69584
  this.inherits = inherits;
69529
69585
  return this;
69530
69586
  }
69531
69587
  };
69588
+ var RoleHierarchyTraversal = class {
69589
+ constructor(allRoles, opts) {
69590
+ this.allRoles = allRoles;
69591
+ this.opts = opts;
69592
+ }
69593
+ walk(role) {
69594
+ const opts = this.opts, allRoles = this.allRoles;
69595
+ let roleList = [];
69596
+ if (!role || !role._id) {
69597
+ return roleList;
69598
+ }
69599
+ roleList.push(role);
69600
+ if (Array.isArray(role.inherits)) {
69601
+ for (let roleId of role.inherits) {
69602
+ const foundRole = findRole(roleId, allRoles, opts);
69603
+ if (foundRole) {
69604
+ roleList = roleList.concat(this.walk(foundRole));
69605
+ }
69606
+ }
69607
+ } else {
69608
+ const foundRoleIds = [];
69609
+ let currentRole = role;
69610
+ while (currentRole && currentRole.inherits && !rolesInList(foundRoleIds, currentRole.inherits)) {
69611
+ if (Array.isArray(currentRole.inherits)) {
69612
+ return roleList.concat(this.walk(currentRole));
69613
+ } else {
69614
+ foundRoleIds.push(currentRole.inherits);
69615
+ currentRole = findRole(currentRole.inherits, allRoles, opts);
69616
+ if (currentRole) {
69617
+ roleList.push(currentRole);
69618
+ }
69619
+ }
69620
+ if (helpers_exports.roles.checkForRoleInheritanceLoops(roleList)) {
69621
+ break;
69622
+ }
69623
+ }
69624
+ }
69625
+ return (0, import_lodash4.uniqBy)(roleList, (role2) => role2._id);
69626
+ }
69627
+ };
69532
69628
  var BUILTIN_ROLES = {
69533
- ADMIN: new Role(
69629
+ ADMIN: new Role2(
69534
69630
  BUILTIN_IDS.ADMIN,
69535
69631
  BUILTIN_IDS.ADMIN,
69536
69632
  "admin" /* ADMIN */,
@@ -69540,7 +69636,7 @@ var BUILTIN_ROLES = {
69540
69636
  color: "var(--spectrum-global-color-static-red-400)" /* ADMIN */
69541
69637
  }
69542
69638
  ).addInheritance(BUILTIN_IDS.POWER),
69543
- POWER: new Role(
69639
+ POWER: new Role2(
69544
69640
  BUILTIN_IDS.POWER,
69545
69641
  BUILTIN_IDS.POWER,
69546
69642
  "power" /* POWER */,
@@ -69550,7 +69646,7 @@ var BUILTIN_ROLES = {
69550
69646
  color: "var(--spectrum-global-color-static-orange-400)" /* POWER */
69551
69647
  }
69552
69648
  ).addInheritance(BUILTIN_IDS.BASIC),
69553
- BASIC: new Role(
69649
+ BASIC: new Role2(
69554
69650
  BUILTIN_IDS.BASIC,
69555
69651
  BUILTIN_IDS.BASIC,
69556
69652
  "write" /* WRITE */,
@@ -69560,7 +69656,7 @@ var BUILTIN_ROLES = {
69560
69656
  color: "var(--spectrum-global-color-static-green-400)" /* BASIC */
69561
69657
  }
69562
69658
  ).addInheritance(BUILTIN_IDS.PUBLIC),
69563
- PUBLIC: new Role(
69659
+ PUBLIC: new Role2(
69564
69660
  BUILTIN_IDS.PUBLIC,
69565
69661
  BUILTIN_IDS.PUBLIC,
69566
69662
  "public" /* PUBLIC */,
@@ -69570,7 +69666,7 @@ var BUILTIN_ROLES = {
69570
69666
  color: "var(--spectrum-global-color-static-blue-400)" /* PUBLIC */
69571
69667
  }
69572
69668
  ),
69573
- BUILDER: new Role(
69669
+ BUILDER: new Role2(
69574
69670
  BUILTIN_IDS.BUILDER,
69575
69671
  BUILTIN_IDS.BUILDER,
69576
69672
  "admin" /* ADMIN */,
@@ -69585,7 +69681,14 @@ function getBuiltinRoles() {
69585
69681
  return (0, import_cloneDeep2.default)(BUILTIN_ROLES);
69586
69682
  }
69587
69683
  function isBuiltin(role) {
69588
- return getBuiltinRole(role) !== void 0;
69684
+ return Object.values(BUILTIN_ROLE_IDS).includes(role);
69685
+ }
69686
+ function prefixRoleIDNoBuiltin(roleId) {
69687
+ if (isBuiltin(roleId)) {
69688
+ return roleId;
69689
+ } else {
69690
+ return prefixRoleID(roleId);
69691
+ }
69589
69692
  }
69590
69693
  function getBuiltinRole(roleId) {
69591
69694
  const role = Object.values(BUILTIN_ROLES).find(
@@ -69607,7 +69710,11 @@ function builtinRoleToNumber(id) {
69607
69710
  if (!role) {
69608
69711
  break;
69609
69712
  }
69610
- role = builtins[role.inherits];
69713
+ if (Array.isArray(role.inherits)) {
69714
+ throw new Error("Built-in roles don't support multi-inheritance");
69715
+ } else {
69716
+ role = builtins[role.inherits];
69717
+ }
69611
69718
  count++;
69612
69719
  } while (role !== null);
69613
69720
  return count;
@@ -69619,12 +69726,26 @@ async function roleToNumber(id) {
69619
69726
  const hierarchy = await getUserRoleHierarchy(id, {
69620
69727
  defaultPublic: true
69621
69728
  });
69622
- for (let role of hierarchy) {
69623
- if (role?.inherits && isBuiltin(role.inherits)) {
69729
+ const findNumber = (role) => {
69730
+ if (!role.inherits) {
69731
+ return 0;
69732
+ }
69733
+ if (Array.isArray(role.inherits)) {
69734
+ const highestBuiltin = role.inherits.map((roleId) => {
69735
+ const foundRole = hierarchy.find((role2) => role2._id === roleId);
69736
+ if (foundRole) {
69737
+ return findNumber(foundRole) + 1;
69738
+ }
69739
+ }).filter((number) => number).sort().pop();
69740
+ if (highestBuiltin != void 0) {
69741
+ return highestBuiltin;
69742
+ }
69743
+ } else if (isBuiltin(role.inherits)) {
69624
69744
  return builtinRoleToNumber(role.inherits) + 1;
69625
69745
  }
69626
- }
69627
- return 0;
69746
+ return 0;
69747
+ };
69748
+ return Math.max(...hierarchy.map(findNumber));
69628
69749
  }
69629
69750
  function lowerBuiltinRoleID(roleId1, roleId2) {
69630
69751
  if (!roleId1) {
@@ -69635,39 +69756,67 @@ function lowerBuiltinRoleID(roleId1, roleId2) {
69635
69756
  }
69636
69757
  return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2) ? roleId2 : roleId1;
69637
69758
  }
69638
- async function getRole(roleId, opts) {
69759
+ function compareRoleIds(roleId1, roleId2) {
69760
+ return prefixRoleID(roleId1) === prefixRoleID(roleId2);
69761
+ }
69762
+ function externalRole(role) {
69763
+ let _id;
69764
+ if (role._id) {
69765
+ _id = getExternalRoleID(role._id);
69766
+ }
69767
+ return {
69768
+ ...role,
69769
+ _id,
69770
+ inherits: getExternalRoleIDs(role.inherits, role.version)
69771
+ };
69772
+ }
69773
+ function findRole(roleId, roles, opts) {
69639
69774
  let role = getBuiltinRole(roleId);
69640
69775
  if (!role) {
69641
69776
  roleId = prefixRoleID(roleId);
69642
69777
  }
69643
- try {
69644
- const db = getAppDB();
69645
- const dbRole = await db.get(getDBRoleID(roleId));
69646
- role = Object.assign(role || {}, dbRole);
69778
+ const dbRole = roles.find(
69779
+ (role2) => role2._id && compareRoleIds(role2._id, roleId)
69780
+ );
69781
+ if (!dbRole && !isBuiltin(roleId) && opts?.defaultPublic) {
69782
+ return (0, import_cloneDeep2.default)(BUILTIN_ROLES.PUBLIC);
69783
+ }
69784
+ role = Object.assign(role || {}, dbRole);
69785
+ if (role?._id) {
69647
69786
  role._id = getExternalRoleID(role._id, role.version);
69648
- } catch (err) {
69649
- if (!isBuiltin(roleId) && opts?.defaultPublic) {
69650
- return (0, import_cloneDeep2.default)(BUILTIN_ROLES.PUBLIC);
69651
- }
69652
- if (!role || Object.keys(role).length === 0) {
69653
- throw err;
69787
+ }
69788
+ return Object.keys(role).length === 0 ? void 0 : role;
69789
+ }
69790
+ async function getRole(roleId, opts) {
69791
+ const db = getAppDB();
69792
+ const roleList = [];
69793
+ if (!isBuiltin(roleId)) {
69794
+ const role = await db.tryGet(getDBRoleID(roleId));
69795
+ if (role) {
69796
+ roleList.push(role);
69654
69797
  }
69655
69798
  }
69656
- return role;
69799
+ return findRole(roleId, roleList, opts);
69800
+ }
69801
+ async function saveRoles(roles) {
69802
+ const db = getAppDB();
69803
+ await db.bulkDocs(
69804
+ roles.filter((role) => role._id).map((role) => ({
69805
+ ...role,
69806
+ _id: prefixRoleID(role._id)
69807
+ }))
69808
+ );
69657
69809
  }
69658
69810
  async function getAllUserRoles(userRoleId, opts) {
69811
+ const allRoles = await getAllRoles();
69659
69812
  if (userRoleId === BUILTIN_IDS.ADMIN) {
69660
- return getAllRoles();
69813
+ return allRoles;
69661
69814
  }
69662
- let currentRole = await getRole(userRoleId, opts);
69663
- let roles = currentRole ? [currentRole] : [];
69664
- let roleIds = [userRoleId];
69665
- while (currentRole && currentRole.inherits && roleIds.indexOf(currentRole.inherits) === -1) {
69666
- roleIds.push(currentRole.inherits);
69667
- currentRole = await getRole(currentRole.inherits);
69668
- if (currentRole) {
69669
- roles.push(currentRole);
69670
- }
69815
+ const foundRole = findRole(userRoleId, allRoles, opts);
69816
+ let roles = [];
69817
+ if (foundRole) {
69818
+ const traversal = new RoleHierarchyTraversal(allRoles, opts);
69819
+ roles = traversal.walk(foundRole);
69671
69820
  }
69672
69821
  return roles;
69673
69822
  }
@@ -69717,7 +69866,22 @@ async function getAllRoles(appId) {
69717
69866
  );
69718
69867
  }
69719
69868
  const builtinRoles = getBuiltinRoles();
69720
- for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
69869
+ let externalBuiltinRoles = [];
69870
+ if (!db || await shouldIncludePowerRole(db)) {
69871
+ externalBuiltinRoles = [
69872
+ BUILTIN_IDS.ADMIN,
69873
+ BUILTIN_IDS.POWER,
69874
+ BUILTIN_IDS.BASIC,
69875
+ BUILTIN_IDS.PUBLIC
69876
+ ];
69877
+ } else {
69878
+ externalBuiltinRoles = [
69879
+ BUILTIN_IDS.ADMIN,
69880
+ BUILTIN_IDS.BASIC,
69881
+ BUILTIN_IDS.PUBLIC
69882
+ ];
69883
+ }
69884
+ for (let builtinRoleId of externalBuiltinRoles) {
69721
69885
  const builtinRole = builtinRoles[builtinRoleId];
69722
69886
  const dbBuiltin = roles.filter(
69723
69887
  (dbRole) => getExternalRoleID(dbRole._id, dbRole.version) === builtinRoleId
@@ -69744,6 +69908,15 @@ async function getAllRoles(appId) {
69744
69908
  return roles;
69745
69909
  }
69746
69910
  }
69911
+ async function shouldIncludePowerRole(db) {
69912
+ const app = await db.tryGet("app_metadata" /* APP_METADATA */);
69913
+ const creationVersion = app?.creationVersion;
69914
+ if (!creationVersion || !import_semver.default.valid(creationVersion)) {
69915
+ return true;
69916
+ }
69917
+ const isGreaterThan3x = import_semver.default.gte(creationVersion, "3.0.0");
69918
+ return !isGreaterThan3x;
69919
+ }
69747
69920
  var AccessController = class {
69748
69921
  constructor() {
69749
69922
  this.userHierarchies = {};
@@ -69757,7 +69930,7 @@ var AccessController = class {
69757
69930
  roleIds = await getUserRoleIdHierarchy(userRoleId);
69758
69931
  this.userHierarchies[userRoleId] = roleIds;
69759
69932
  }
69760
- return roleIds?.indexOf(tryingRoleId) !== -1;
69933
+ return roleIds?.find((roleId) => compareRoleIds(roleId, tryingRoleId)) !== void 0;
69761
69934
  }
69762
69935
  async checkScreensAccess(screens, userRoleId) {
69763
69936
  let accessibleScreens = [];
@@ -69784,13 +69957,22 @@ function getDBRoleID(roleName) {
69784
69957
  return prefixRoleID(roleName);
69785
69958
  }
69786
69959
  function getExternalRoleID(roleId, version) {
69787
- if (roleId.startsWith("role" /* ROLE */) && (isBuiltin(roleId) || version === RoleIDVersion.NAME)) {
69960
+ if (roleId.startsWith(`${"role" /* ROLE */}${SEPARATOR}`) && (isBuiltin(roleId) || version === RoleIDVersion.NAME)) {
69788
69961
  const parts = roleId.split(SEPARATOR);
69789
69962
  parts.shift();
69790
69963
  return parts.join(SEPARATOR);
69791
69964
  }
69792
69965
  return roleId;
69793
69966
  }
69967
+ function getExternalRoleIDs(roleIds, version) {
69968
+ if (!roleIds) {
69969
+ return roleIds;
69970
+ } else if (typeof roleIds === "string") {
69971
+ return getExternalRoleID(roleIds, version);
69972
+ } else {
69973
+ return roleIds.map((roleId) => getExternalRoleID(roleId, version));
69974
+ }
69975
+ }
69794
69976
 
69795
69977
  // src/users/utils.ts
69796
69978
  var isBuilder2 = sdk_exports.users.isBuilder;
@@ -69842,17 +70024,14 @@ async function validateUniqueUser(email, tenantId) {
69842
70024
  }
69843
70025
  }
69844
70026
  }
69845
- async function getAccountHolderFromUserIds(userIds) {
70027
+ async function getAccountHolderFromUsers(users) {
69846
70028
  if (!environment_default.SELF_HOSTED && !environment_default.DISABLE_ACCOUNT_PORTAL) {
69847
- const tenantId = getTenantId();
69848
- const account = await getAccountByTenantId(tenantId);
69849
- if (!account) {
69850
- throw new Error(`Account not found for tenantId=${tenantId}`);
69851
- }
69852
- const budibaseUserId = account.budibaseUserId;
69853
- if (userIds.includes(budibaseUserId)) {
69854
- return account;
69855
- }
70029
+ const accountMetadata = await getExistingAccounts(
70030
+ users.map((user) => user.email)
70031
+ );
70032
+ return users.find(
70033
+ (user) => accountMetadata.map((metadata) => metadata.email).includes(user.email)
70034
+ );
69856
70035
  }
69857
70036
  }
69858
70037
 
@@ -70590,7 +70769,7 @@ __export(installation_exports, {
70590
70769
  getInstall: () => getInstall,
70591
70770
  getInstallFromDB: () => getInstallFromDB
70592
70771
  });
70593
- var import_semver = __toESM(require("semver"));
70772
+ var import_semver2 = __toESM(require("semver"));
70594
70773
  var getInstall = async () => {
70595
70774
  return withCache("installation" /* INSTALLATION */, 86400 /* ONE_DAY */, getInstallFromDB, {
70596
70775
  useTenancy: false
@@ -70659,8 +70838,8 @@ var checkInstallVersion = async () => {
70659
70838
  const newVersion = environment_default.VERSION;
70660
70839
  try {
70661
70840
  if (currentVersion !== newVersion) {
70662
- const isUpgrade = import_semver.default.gt(newVersion, currentVersion);
70663
- const isDowngrade = import_semver.default.lt(newVersion, currentVersion);
70841
+ const isUpgrade = import_semver2.default.gt(newVersion, currentVersion);
70842
+ const isDowngrade = import_semver2.default.lt(newVersion, currentVersion);
70664
70843
  const success = await updateVersion(newVersion);
70665
70844
  if (success) {
70666
70845
  await doInIdentityContext(
@@ -70799,8 +70978,9 @@ var identifyUser = async (user, account, timestamp) => {
70799
70978
  if (isSSOUser(user)) {
70800
70979
  providerType = user.providerType;
70801
70980
  }
70802
- const accountHolder = account?.budibaseUserId === user._id || false;
70803
- const verified2 = account && account?.budibaseUserId === user._id ? account.verified : false;
70981
+ const accountHolder = await getExistingAccounts([user.email]);
70982
+ const isAccountHolder = accountHolder.length > 0;
70983
+ const verified2 = !!account && isAccountHolder && account.verified;
70804
70984
  const installationId = await getInstallationId();
70805
70985
  const hosting = account ? account.hosting : getHostingFromEnv();
70806
70986
  const environment2 = getDeploymentEnvironment();
@@ -70811,7 +70991,7 @@ var identifyUser = async (user, account, timestamp) => {
70811
70991
  installationId,
70812
70992
  tenantId,
70813
70993
  verified: verified2,
70814
- accountHolder,
70994
+ accountHolder: isAccountHolder,
70815
70995
  providerType,
70816
70996
  builder,
70817
70997
  admin,
@@ -70830,8 +71010,9 @@ var identifyAccount = async (account) => {
70830
71010
  const installationId = await getInstallationId();
70831
71011
  const environment2 = getDeploymentEnvironment();
70832
71012
  if (isCloudAccount(account)) {
70833
- if (account.budibaseUserId) {
70834
- id = account.budibaseUserId;
71013
+ const user = await getGlobalUserByEmail(account.email);
71014
+ if (user?._id) {
71015
+ id = user._id;
70835
71016
  }
70836
71017
  }
70837
71018
  const identity = {
@@ -72816,24 +72997,24 @@ var UserDB = class _UserDB {
72816
72997
  }
72817
72998
  );
72818
72999
  }
72819
- static async bulkDelete(userIds) {
73000
+ static async bulkDelete(users) {
72820
73001
  const db = getGlobalDB();
72821
73002
  const response = {
72822
73003
  successful: [],
72823
73004
  unsuccessful: []
72824
73005
  };
72825
- const account = await getAccountHolderFromUserIds(userIds);
72826
- if (account) {
72827
- userIds = userIds.filter((u) => u !== account.budibaseUserId);
73006
+ const accountHolder = await getAccountHolderFromUsers(users);
73007
+ if (accountHolder) {
73008
+ users = users.filter((u) => u.userId !== accountHolder.userId);
72828
73009
  response.unsuccessful.push({
72829
- _id: account.budibaseUserId,
72830
- email: account.email,
73010
+ _id: accountHolder.userId,
73011
+ email: accountHolder.email,
72831
73012
  reason: "Account holder cannot be deleted"
72832
73013
  });
72833
73014
  }
72834
73015
  const allDocsResponse = await db.allDocs({
72835
73016
  include_docs: true,
72836
- keys: userIds
73017
+ keys: users.map((u) => u.userId)
72837
73018
  });
72838
73019
  const usersToDelete = allDocsResponse.rows.map((user) => {
72839
73020
  return user.doc;
@@ -72980,6 +73161,16 @@ async function getAllUserIds() {
72980
73161
  });
72981
73162
  return response.rows.map((row) => row.id);
72982
73163
  }
73164
+ async function getAllUsers() {
73165
+ const db = getGlobalDB();
73166
+ const startKey = `${"us" /* USER */}${SEPARATOR}`;
73167
+ const response = await db.allDocs({
73168
+ startkey: startKey,
73169
+ endkey: `${startKey}${UNICODE_MAX}`,
73170
+ include_docs: true
73171
+ });
73172
+ return response.rows.map((row) => row.doc);
73173
+ }
72983
73174
  async function bulkUpdateGlobalUsers(users) {
72984
73175
  const db = getGlobalDB();
72985
73176
  return await db.bulkDocs(users);
@@ -74435,6 +74626,7 @@ function timeMinusOneMinute() {
74435
74626
  function finalise(ctx, opts = {}) {
74436
74627
  ctx.publicEndpoint = opts.publicEndpoint || false;
74437
74628
  ctx.isAuthenticated = opts.authenticated || false;
74629
+ ctx.loginMethod = opts.loginMethod;
74438
74630
  ctx.user = opts.user;
74439
74631
  ctx.internal = opts.internal || false;
74440
74632
  ctx.version = opts.version;
@@ -74492,7 +74684,7 @@ function authenticated_default(noAuthPatterns = [], opts = {
74492
74684
  apiKey = ctx.request.headers["authorization" /* AUTHORIZATION */].split(" ")[1];
74493
74685
  }
74494
74686
  const tenantId = ctx.request.headers["x-budibase-tenant-id" /* TENANT_ID */];
74495
- let authenticated = false, user = null, internal = false;
74687
+ let authenticated = false, user = void 0, internal = false, loginMethod = void 0;
74496
74688
  if (authCookie && !apiKey) {
74497
74689
  const sessionId = authCookie.sessionId;
74498
74690
  const userId = authCookie.userId;
@@ -74514,6 +74706,7 @@ function authenticated_default(noAuthPatterns = [], opts = {
74514
74706
  });
74515
74707
  }
74516
74708
  user.csrfToken = session.csrfToken;
74709
+ loginMethod = "cookie" /* COOKIE */;
74517
74710
  if (session?.lastAccessedAt < timeMinusOneMinute()) {
74518
74711
  await updateSessionTTL(session);
74519
74712
  }
@@ -74530,17 +74723,16 @@ function authenticated_default(noAuthPatterns = [], opts = {
74530
74723
  apiKey,
74531
74724
  populateUser
74532
74725
  );
74533
- if (valid && foundUser) {
74726
+ if (valid) {
74534
74727
  authenticated = true;
74728
+ loginMethod = "api_key" /* API_KEY */;
74535
74729
  user = foundUser;
74536
- } else if (valid) {
74537
- authenticated = true;
74538
- internal = true;
74730
+ internal = !foundUser;
74539
74731
  }
74540
74732
  }
74541
74733
  if (!user && tenantId) {
74542
74734
  user = { tenantId };
74543
- } else if (user) {
74735
+ } else if (user && "password" in user) {
74544
74736
  delete user.password;
74545
74737
  }
74546
74738
  if (!authenticated) {
@@ -74557,7 +74749,14 @@ function authenticated_default(noAuthPatterns = [], opts = {
74557
74749
  status: user.status
74558
74750
  });
74559
74751
  }
74560
- finalise(ctx, { authenticated, user, internal, version, publicEndpoint });
74752
+ finalise(ctx, {
74753
+ authenticated,
74754
+ user,
74755
+ internal,
74756
+ version,
74757
+ publicEndpoint,
74758
+ loginMethod
74759
+ });
74561
74760
  if (isUser(user)) {
74562
74761
  return doInUserContext(user, ctx, next);
74563
74762
  } else {
@@ -75294,7 +75493,7 @@ var import_knex2 = require("knex");
75294
75493
  // src/sql/sqlTable.ts
75295
75494
  var import_knex = require("knex");
75296
75495
  function isIgnoredType(type) {
75297
- const ignored = ["link" /* LINK */, "formula" /* FORMULA */];
75496
+ const ignored = ["link" /* LINK */, "formula" /* FORMULA */, "ai" /* AI */];
75298
75497
  return ignored.indexOf(type) !== -1;
75299
75498
  }
75300
75499
  function generateSchema(schema, table, tables, oldTable = null, renamed) {
@@ -75390,6 +75589,8 @@ function generateSchema(schema, table, tables, oldTable = null, renamed) {
75390
75589
  break;
75391
75590
  case "formula" /* FORMULA */:
75392
75591
  break;
75592
+ case "ai" /* AI */:
75593
+ break;
75393
75594
  case "attachment" /* ATTACHMENTS */:
75394
75595
  case "attachment_single" /* ATTACHMENT_SINGLE */:
75395
75596
  case "signature_single" /* SIGNATURE_SINGLE */:
@@ -75521,7 +75722,7 @@ var SqlTableQueryBuilder = class {
75521
75722
  var sqlTable_default = SqlTableQueryBuilder;
75522
75723
 
75523
75724
  // src/sql/sql.ts
75524
- var import_lodash4 = require("lodash");
75725
+ var import_lodash5 = require("lodash");
75525
75726
  var COUNT_FIELD_NAME = "__bb_total";
75526
75727
  function getBaseLimit() {
75527
75728
  const envLimit = environment_default.SQL_MAX_ROWS ? parseInt(environment_default.SQL_MAX_ROWS) : null;
@@ -75562,6 +75763,20 @@ function convertBooleans(query) {
75562
75763
  function isSqs(table) {
75563
75764
  return table.sourceType === "internal" /* INTERNAL */ || table.sourceId === INTERNAL_TABLE_SOURCE_ID;
75564
75765
  }
75766
+ function escapeQuotes(value, quoteChar = '"') {
75767
+ return value.replace(new RegExp(quoteChar, "g"), `${quoteChar}${quoteChar}`);
75768
+ }
75769
+ function wrap(value, quoteChar = '"') {
75770
+ return `${quoteChar}${escapeQuotes(value, quoteChar)}${quoteChar}`;
75771
+ }
75772
+ function stringifyArray(value, quoteStyle = '"') {
75773
+ for (let i in value) {
75774
+ if (typeof value[i] === "string") {
75775
+ value[i] = wrap(value[i], quoteStyle);
75776
+ }
75777
+ }
75778
+ return `[${value.join(",")}]`;
75779
+ }
75565
75780
  var allowEmptyRelationships = {
75566
75781
  ["equal" /* EQUAL */]: false,
75567
75782
  ["notEqual" /* NOT_EQUAL */]: true,
@@ -75599,28 +75814,24 @@ var InternalBuilder = class {
75599
75814
  get table() {
75600
75815
  return this.query.meta.table;
75601
75816
  }
75817
+ get knexClient() {
75818
+ return this.knex.client;
75819
+ }
75602
75820
  getFieldSchema(key) {
75603
75821
  const { column } = this.splitter.run(key);
75604
75822
  return this.table.schema[column];
75605
75823
  }
75824
+ supportsILike() {
75825
+ return !(this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */);
75826
+ }
75606
75827
  quoteChars() {
75607
- switch (this.client) {
75608
- case "oracledb" /* ORACLE */:
75609
- case "pg" /* POSTGRES */:
75610
- return ['"', '"'];
75611
- case "mssql" /* MS_SQL */:
75612
- return ["[", "]"];
75613
- case "mariadb" /* MARIADB */:
75614
- case "mysql2" /* MY_SQL */:
75615
- case "sqlite3" /* SQL_LITE */:
75616
- return ["`", "`"];
75617
- }
75828
+ const wrapped = this.knexClient.wrapIdentifier("foo", {});
75829
+ return [wrapped[0], wrapped[wrapped.length - 1]];
75618
75830
  }
75619
- // Takes a string like foo and returns a quoted string like [foo] for SQL Server
75620
- // and "foo" for Postgres.
75831
+ // Takes a string like foo and returns a quoted string like [foo] for SQL
75832
+ // Server and "foo" for Postgres.
75621
75833
  quote(str) {
75622
- const [start2, end2] = this.quoteChars();
75623
- return `${start2}${str}${end2}`;
75834
+ return this.knexClient.wrapIdentifier(str, {});
75624
75835
  }
75625
75836
  isQuoted(key) {
75626
75837
  const [start2, end2] = this.quoteChars();
@@ -75635,6 +75846,27 @@ var InternalBuilder = class {
75635
75846
  }
75636
75847
  return key.map((part) => this.quote(part)).join(".");
75637
75848
  }
75849
+ quotedValue(value) {
75850
+ const formatter = this.knexClient.formatter(this.knexClient.queryBuilder());
75851
+ return formatter.wrap(value, false);
75852
+ }
75853
+ rawQuotedValue(value) {
75854
+ return this.knex.raw(this.quotedValue(value));
75855
+ }
75856
+ // Unfortuantely we cannot rely on knex's identifier escaping because it trims
75857
+ // the identifier string before escaping it, which breaks cases for us where
75858
+ // columns that start or end with a space aren't referenced correctly anymore.
75859
+ //
75860
+ // So whenever you're using an identifier binding in knex, e.g. knex.raw("??
75861
+ // as ?", ["foo", "bar"]), you need to make sure you call this:
75862
+ //
75863
+ // knex.raw("?? as ?", [this.quotedIdentifier("foo"), "bar"])
75864
+ //
75865
+ // Issue we filed against knex about this:
75866
+ // https://github.com/knex/knex/issues/6143
75867
+ rawQuotedIdentifier(key) {
75868
+ return this.knex.raw(this.quotedIdentifier(key));
75869
+ }
75638
75870
  // Turns an identifier like a.b.c or `a`.`b`.`c` into ["a", "b", "c"]
75639
75871
  splitIdentifier(key) {
75640
75872
  const [start2, end2] = this.quoteChars();
@@ -75673,7 +75905,7 @@ var InternalBuilder = class {
75673
75905
  const alias = this.getTableName(endpoint.entityId);
75674
75906
  const schema = meta.table.schema;
75675
75907
  if (!this.isFullSelectStatementRequired()) {
75676
- return [this.knex.raw(`${this.quote(alias)}.*`)];
75908
+ return [this.knex.raw("??", [`${alias}.*`])];
75677
75909
  }
75678
75910
  return resource.fields.map((field) => {
75679
75911
  const parts = field.split(/\./g);
@@ -75687,17 +75919,21 @@ var InternalBuilder = class {
75687
75919
  }).filter(({ table }) => !table || table === alias).map(({ table, column, field }) => {
75688
75920
  const columnSchema = schema[column];
75689
75921
  if (this.SPECIAL_SELECT_CASES.POSTGRES_MONEY(columnSchema)) {
75690
- return this.knex.raw(
75691
- `${this.quotedIdentifier(
75692
- [table, column].join(".")
75693
- )}::money::numeric as ${this.quote(field)}`
75694
- );
75922
+ return this.knex.raw(`??::money::numeric as "${field}"`, [
75923
+ this.rawQuotedIdentifier([table, column].join(".")),
75924
+ field
75925
+ ]);
75695
75926
  }
75696
75927
  if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(columnSchema)) {
75697
- return this.knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`);
75928
+ return this.knex.raw(`CONVERT(varchar, ??, 108) as "${field}"`, [
75929
+ this.rawQuotedIdentifier(field)
75930
+ ]);
75931
+ }
75932
+ if (table) {
75933
+ return this.rawQuotedIdentifier(`${table}.${column}`);
75934
+ } else {
75935
+ return this.rawQuotedIdentifier(field);
75698
75936
  }
75699
- const quoted = table ? `${this.quote(table)}.${this.quote(column)}` : this.quote(field);
75700
- return this.knex.raw(quoted);
75701
75937
  });
75702
75938
  }
75703
75939
  // OracleDB can't use character-large-objects (CLOBs) in WHERE clauses,
@@ -75712,12 +75948,15 @@ var InternalBuilder = class {
75712
75948
  const parts = this.splitIdentifier(field);
75713
75949
  const col = parts.pop();
75714
75950
  const schema = this.table.schema[col];
75715
- let identifier = this.quotedIdentifier(field);
75951
+ let identifier = this.rawQuotedIdentifier(field);
75716
75952
  if (schema.type === "string" /* STRING */ || schema.type === "longform" /* LONGFORM */ || schema.type === "bb_reference_single" /* BB_REFERENCE_SINGLE */ || schema.type === "bb_reference" /* BB_REFERENCE */ || schema.type === "options" /* OPTIONS */ || schema.type === "barcodeqr" /* BARCODEQR */) {
75717
75953
  if (opts?.forSelect) {
75718
- identifier = `to_char(${identifier}) as ${this.quotedIdentifier(col)}`;
75954
+ identifier = this.knex.raw("to_char(??) as ??", [
75955
+ identifier,
75956
+ this.rawQuotedIdentifier(col)
75957
+ ]);
75719
75958
  } else {
75720
- identifier = `to_char(${identifier})`;
75959
+ identifier = this.knex.raw("to_char(??)", [identifier]);
75721
75960
  }
75722
75961
  }
75723
75962
  return identifier;
@@ -75762,7 +76001,7 @@ var InternalBuilder = class {
75762
76001
  return body2;
75763
76002
  }
75764
76003
  parseFilters(filters) {
75765
- filters = (0, import_lodash4.cloneDeep)(filters);
76004
+ filters = (0, import_lodash5.cloneDeep)(filters);
75766
76005
  for (const op of Object.values(BasicOperator)) {
75767
76006
  const filter = filters[op];
75768
76007
  if (!filter) {
@@ -75822,7 +76061,6 @@ var InternalBuilder = class {
75822
76061
  return query.andWhere(`${document}.fieldName`, "=", relationship.column);
75823
76062
  }
75824
76063
  addRelationshipForFilter(query, allowEmptyRelationships2, filterKey, whereCb) {
75825
- const mainKnex = this.knex;
75826
76064
  const { relationships, endpoint, tableAliases: aliases } = this.query;
75827
76065
  const tableName = endpoint.entityId;
75828
76066
  const fromAlias = aliases?.[tableName] || tableName;
@@ -75836,7 +76074,7 @@ var InternalBuilder = class {
75836
76074
  const matchesTableName = matches2(relatedTableName) || matches2(toAlias);
75837
76075
  const matchesRelationName = matches2(relationship.column);
75838
76076
  if ((matchesTableName || matchesRelationName) && relationship.to && relationship.tableName) {
75839
- const joinTable = mainKnex.select(mainKnex.raw(1)).from({ [toAlias]: relatedTableName });
76077
+ const joinTable = this.knex.select(this.knex.raw(1)).from({ [toAlias]: relatedTableName });
75840
76078
  let subQuery = joinTable.clone();
75841
76079
  const manyToMany = validateManyToMany(relationship);
75842
76080
  let updatedKey;
@@ -75863,9 +76101,7 @@ var InternalBuilder = class {
75863
76101
  }).where(
75864
76102
  `${throughAlias}.${manyToMany.from}`,
75865
76103
  "=",
75866
- mainKnex.raw(
75867
- this.quotedIdentifier(`${fromAlias}.${manyToMany.fromPrimary}`)
75868
- )
76104
+ this.rawQuotedIdentifier(`${fromAlias}.${manyToMany.fromPrimary}`)
75869
76105
  );
75870
76106
  if (this.client === "sqlite3" /* SQL_LITE */) {
75871
76107
  subQuery = this.addJoinFieldCheck(subQuery, manyToMany);
@@ -75890,7 +76126,7 @@ var InternalBuilder = class {
75890
76126
  subQuery = subQuery.where(
75891
76127
  toKey,
75892
76128
  "=",
75893
- mainKnex.raw(this.quotedIdentifier(foreignKey))
76129
+ this.rawQuotedIdentifier(foreignKey)
75894
76130
  );
75895
76131
  query = query.where((q2) => {
75896
76132
  q2.whereExists(whereCb(updatedKey, subQuery.clone()));
@@ -75911,7 +76147,7 @@ var InternalBuilder = class {
75911
76147
  const builder = this;
75912
76148
  filters = this.parseFilters({ ...filters });
75913
76149
  const aliases = this.query.tableAliases;
75914
- const allOr = filters.allOr;
76150
+ const shouldOr = filters.allOr;
75915
76151
  const isSqlite = this.client === "sqlite3" /* SQL_LITE */;
75916
76152
  const tableName = isSqlite ? this.table._id : this.table.name;
75917
76153
  function getTableAlias(name) {
@@ -75950,7 +76186,7 @@ var InternalBuilder = class {
75950
76186
  value
75951
76187
  );
75952
76188
  } else if (shouldProcessRelationship) {
75953
- if (allOr) {
76189
+ if (shouldOr) {
75954
76190
  query = query.or;
75955
76191
  }
75956
76192
  query = builder.addRelationshipForFilter(
@@ -75965,75 +76201,89 @@ var InternalBuilder = class {
75965
76201
  }
75966
76202
  }
75967
76203
  const like = (q2, key, value) => {
75968
- const fuzzyOr = filters?.fuzzyOr;
75969
- const fnc = fuzzyOr || allOr ? "orWhere" : "where";
75970
- if (this.client === "pg" /* POSTGRES */) {
75971
- return q2[fnc](key, "ilike", `%${value}%`);
75972
- } else {
75973
- const rawFnc = `${fnc}Raw`;
75974
- return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
76204
+ if (filters?.fuzzyOr || shouldOr) {
76205
+ q2 = q2.or;
76206
+ }
76207
+ if (this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */) {
76208
+ return q2.whereRaw(`LOWER(??) LIKE ?`, [
76209
+ this.rawQuotedIdentifier(key),
75975
76210
  `%${value.toLowerCase()}%`
75976
76211
  ]);
75977
76212
  }
76213
+ return q2.whereILike(
76214
+ // @ts-expect-error knex types are wrong, raw is fine here
76215
+ this.rawQuotedIdentifier(key),
76216
+ this.knex.raw("?", [`%${value}%`])
76217
+ );
75978
76218
  };
75979
76219
  const contains = (mode, any = false) => {
75980
- const rawFnc = allOr ? "orWhereRaw" : "whereRaw";
75981
- const not = mode === filters?.notContains ? "NOT " : "";
75982
- function stringifyArray(value, quoteStyle = '"') {
75983
- for (let i in value) {
75984
- if (typeof value[i] === "string") {
75985
- value[i] = `${quoteStyle}${value[i]}${quoteStyle}`;
75986
- }
76220
+ function addModifiers(q2) {
76221
+ if (shouldOr || mode === filters?.containsAny) {
76222
+ q2 = q2.or;
75987
76223
  }
75988
- return `[${value.join(",")}]`;
76224
+ if (mode === filters?.notContains) {
76225
+ q2 = q2.not;
76226
+ }
76227
+ return q2;
75989
76228
  }
75990
76229
  if (this.client === "pg" /* POSTGRES */) {
75991
76230
  iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
75992
- const wrap = any ? "" : "'";
75993
- const op = any ? "\\?| array" : "@>";
75994
- const fieldNames = key.split(/\./g);
75995
- const table = fieldNames[0];
75996
- const col = fieldNames[1];
75997
- return q2[rawFnc](
75998
- `${not}COALESCE("${table}"."${col}"::jsonb ${op} ${wrap}${stringifyArray(
75999
- value,
76000
- any ? "'" : '"'
76001
- )}${wrap}, FALSE)`
76002
- );
76231
+ q2 = addModifiers(q2);
76232
+ if (any) {
76233
+ return q2.whereRaw(`COALESCE(??::jsonb \\?| array??, FALSE)`, [
76234
+ this.rawQuotedIdentifier(key),
76235
+ this.knex.raw(stringifyArray(value, "'"))
76236
+ ]);
76237
+ } else {
76238
+ return q2.whereRaw(`COALESCE(??::jsonb @> '??', FALSE)`, [
76239
+ this.rawQuotedIdentifier(key),
76240
+ this.knex.raw(stringifyArray(value))
76241
+ ]);
76242
+ }
76003
76243
  });
76004
76244
  } else if (this.client === "mysql2" /* MY_SQL */ || this.client === "mariadb" /* MARIADB */) {
76005
- const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS";
76006
76245
  iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
76007
- return q2[rawFnc](
76008
- `${not}COALESCE(${jsonFnc}(${key}, '${stringifyArray(
76009
- value
76010
- )}'), FALSE)`
76011
- );
76246
+ return addModifiers(q2).whereRaw(`COALESCE(?(??, ?), FALSE)`, [
76247
+ this.knex.raw(any ? "JSON_OVERLAPS" : "JSON_CONTAINS"),
76248
+ this.rawQuotedIdentifier(key),
76249
+ this.knex.raw(wrap(stringifyArray(value)))
76250
+ ]);
76012
76251
  });
76013
76252
  } else {
76014
- const andOr = mode === filters?.containsAny ? " OR " : " AND ";
76015
76253
  iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
76016
- let statement = "";
76017
- const identifier = this.quotedIdentifier(key);
76018
- for (let i in value) {
76019
- if (typeof value[i] === "string") {
76020
- value[i] = `%"${value[i].toLowerCase()}"%`;
76021
- } else {
76022
- value[i] = `%${value[i]}%`;
76023
- }
76024
- statement += `${statement ? andOr : ""}COALESCE(LOWER(${identifier}), '') LIKE ?`;
76025
- }
76026
- if (statement === "") {
76254
+ if (value.length === 0) {
76027
76255
  return q2;
76028
76256
  }
76029
- if (not) {
76030
- return q2[rawFnc](
76031
- `(NOT (${statement}) OR ${identifier} IS NULL)`,
76032
- value
76033
- );
76034
- } else {
76035
- return q2[rawFnc](statement, value);
76036
- }
76257
+ q2 = q2.where((subQuery) => {
76258
+ if (mode === filters?.notContains) {
76259
+ subQuery = subQuery.not;
76260
+ }
76261
+ subQuery = subQuery.where((subSubQuery) => {
76262
+ for (const elem of value) {
76263
+ if (mode === filters?.containsAny) {
76264
+ subSubQuery = subSubQuery.or;
76265
+ } else {
76266
+ subSubQuery = subSubQuery.and;
76267
+ }
76268
+ const lower = typeof elem === "string" ? `"${elem.toLowerCase()}"` : elem;
76269
+ subSubQuery = subSubQuery.whereLike(
76270
+ // @ts-expect-error knex types are wrong, raw is fine here
76271
+ this.knex.raw(`COALESCE(LOWER(??), '')`, [
76272
+ this.rawQuotedIdentifier(key)
76273
+ ]),
76274
+ `%${lower}%`
76275
+ );
76276
+ }
76277
+ });
76278
+ if (mode === filters?.notContains) {
76279
+ subQuery = subQuery.or.whereNull(
76280
+ // @ts-expect-error knex types are wrong, raw is fine here
76281
+ this.rawQuotedIdentifier(key)
76282
+ );
76283
+ }
76284
+ return subQuery;
76285
+ });
76286
+ return q2;
76037
76287
  });
76038
76288
  }
76039
76289
  };
@@ -76056,41 +76306,41 @@ var InternalBuilder = class {
76056
76306
  });
76057
76307
  }
76058
76308
  if (filters.oneOf) {
76059
- const fnc = allOr ? "orWhereIn" : "whereIn";
76060
76309
  iterate(
76061
76310
  filters.oneOf,
76062
76311
  "oneOf" /* ONE_OF */,
76063
76312
  (q2, key, array) => {
76313
+ if (shouldOr) {
76314
+ q2 = q2.or;
76315
+ }
76064
76316
  if (this.client === "oracledb" /* ORACLE */) {
76065
76317
  key = this.convertClobs(key);
76066
- array = Array.isArray(array) ? array : [array];
76067
- const binding = new Array(array.length).fill("?").join(",");
76068
- return q2.whereRaw(`${key} IN (${binding})`, array);
76069
- } else {
76070
- return q2[fnc](key, Array.isArray(array) ? array : [array]);
76071
76318
  }
76319
+ return q2.whereIn(key, Array.isArray(array) ? array : [array]);
76072
76320
  },
76073
76321
  (q2, key, array) => {
76322
+ if (shouldOr) {
76323
+ q2 = q2.or;
76324
+ }
76074
76325
  if (this.client === "oracledb" /* ORACLE */) {
76075
- const keyStr = `(${key.map((k) => this.convertClobs(k)).join(",")})`;
76076
- const binding = `(${array.map((a) => `(${new Array(a.length).fill("?").join(",")})`).join(",")})`;
76077
- return q2.whereRaw(`${keyStr} IN ${binding}`, array.flat());
76078
- } else {
76079
- return q2[fnc](key, Array.isArray(array) ? array : [array]);
76326
+ key = key.map((k) => this.convertClobs(k));
76080
76327
  }
76328
+ return q2.whereIn(key, Array.isArray(array) ? array : [array]);
76081
76329
  }
76082
76330
  );
76083
76331
  }
76084
76332
  if (filters.string) {
76085
76333
  iterate(filters.string, "string" /* STRING */, (q2, key, value) => {
76086
- const fnc = allOr ? "orWhere" : "where";
76087
- if (this.client === "pg" /* POSTGRES */) {
76088
- return q2[fnc](key, "ilike", `${value}%`);
76089
- } else {
76090
- const rawFnc = `${fnc}Raw`;
76091
- return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
76334
+ if (shouldOr) {
76335
+ q2 = q2.or;
76336
+ }
76337
+ if (this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */) {
76338
+ return q2.whereRaw(`LOWER(??) LIKE ?`, [
76339
+ this.rawQuotedIdentifier(key),
76092
76340
  `${value.toLowerCase()}%`
76093
76341
  ]);
76342
+ } else {
76343
+ return q2.whereILike(key, `${value}%`);
76094
76344
  }
76095
76345
  });
76096
76346
  }
@@ -76110,56 +76360,52 @@ var InternalBuilder = class {
76110
76360
  }
76111
76361
  const lowValid = isValidFilter(value.low), highValid = isValidFilter(value.high);
76112
76362
  const schema = this.getFieldSchema(key);
76363
+ let rawKey = key;
76364
+ let high = value.high;
76365
+ let low = value.low;
76113
76366
  if (this.client === "oracledb" /* ORACLE */) {
76114
- key = this.knex.raw(this.convertClobs(key));
76367
+ rawKey = this.convertClobs(key);
76368
+ } else if (this.client === "sqlite3" /* SQL_LITE */ && schema?.type === "bigint" /* BIGINT */) {
76369
+ rawKey = this.knex.raw("CAST(?? AS INTEGER)", [
76370
+ this.rawQuotedIdentifier(key)
76371
+ ]);
76372
+ high = this.knex.raw("CAST(? AS INTEGER)", [value.high]);
76373
+ low = this.knex.raw("CAST(? AS INTEGER)", [value.low]);
76374
+ }
76375
+ if (shouldOr) {
76376
+ q2 = q2.or;
76115
76377
  }
76116
76378
  if (lowValid && highValid) {
76117
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76118
- return q2.whereRaw(
76119
- `CAST(${key} AS INTEGER) BETWEEN CAST(? AS INTEGER) AND CAST(? AS INTEGER)`,
76120
- [value.low, value.high]
76121
- );
76122
- } else {
76123
- const fnc = allOr ? "orWhereBetween" : "whereBetween";
76124
- return q2[fnc](key, [value.low, value.high]);
76125
- }
76379
+ return q2.whereBetween(rawKey, [low, high]);
76126
76380
  } else if (lowValid) {
76127
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76128
- return q2.whereRaw(`CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`, [
76129
- value.low
76130
- ]);
76131
- } else {
76132
- const fnc = allOr ? "orWhere" : "where";
76133
- return q2[fnc](key, ">=", value.low);
76134
- }
76381
+ return q2.where(rawKey, ">=", low);
76135
76382
  } else if (highValid) {
76136
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76137
- return q2.whereRaw(`CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`, [
76138
- value.high
76139
- ]);
76140
- } else {
76141
- const fnc = allOr ? "orWhere" : "where";
76142
- return q2[fnc](key, "<=", value.high);
76143
- }
76383
+ return q2.where(rawKey, "<=", high);
76144
76384
  }
76145
76385
  return q2;
76146
76386
  });
76147
76387
  }
76148
76388
  if (filters.equal) {
76149
76389
  iterate(filters.equal, "equal" /* EQUAL */, (q2, key, value) => {
76150
- const fnc = allOr ? "orWhereRaw" : "whereRaw";
76390
+ if (shouldOr) {
76391
+ q2 = q2.or;
76392
+ }
76151
76393
  if (this.client === "mssql" /* MS_SQL */) {
76152
- return q2[fnc](
76153
- `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 1`,
76154
- [value]
76155
- );
76156
- } else if (this.client === "oracledb" /* ORACLE */) {
76157
- const identifier = this.convertClobs(key);
76158
- return q2[fnc](`(${identifier} IS NOT NULL AND ${identifier} = ?)`, [
76394
+ return q2.whereRaw(`CASE WHEN ?? = ? THEN 1 ELSE 0 END = 1`, [
76395
+ this.rawQuotedIdentifier(key),
76159
76396
  value
76160
76397
  ]);
76398
+ } else if (this.client === "oracledb" /* ORACLE */) {
76399
+ const identifier = this.convertClobs(key);
76400
+ return q2.where(
76401
+ (subq) => (
76402
+ // @ts-expect-error knex types are wrong, raw is fine here
76403
+ subq.whereNotNull(identifier).andWhere(identifier, value)
76404
+ )
76405
+ );
76161
76406
  } else {
76162
- return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} = ?, FALSE)`, [
76407
+ return q2.whereRaw(`COALESCE(?? = ?, FALSE)`, [
76408
+ this.rawQuotedIdentifier(key),
76163
76409
  value
76164
76410
  ]);
76165
76411
  }
@@ -76167,20 +76413,22 @@ var InternalBuilder = class {
76167
76413
  }
76168
76414
  if (filters.notEqual) {
76169
76415
  iterate(filters.notEqual, "notEqual" /* NOT_EQUAL */, (q2, key, value) => {
76170
- const fnc = allOr ? "orWhereRaw" : "whereRaw";
76416
+ if (shouldOr) {
76417
+ q2 = q2.or;
76418
+ }
76171
76419
  if (this.client === "mssql" /* MS_SQL */) {
76172
- return q2[fnc](
76173
- `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 0`,
76174
- [value]
76175
- );
76420
+ return q2.whereRaw(`CASE WHEN ?? = ? THEN 1 ELSE 0 END = 0`, [
76421
+ this.rawQuotedIdentifier(key),
76422
+ value
76423
+ ]);
76176
76424
  } else if (this.client === "oracledb" /* ORACLE */) {
76177
76425
  const identifier = this.convertClobs(key);
76178
- return q2[fnc](
76179
- `(${identifier} IS NOT NULL AND ${identifier} != ?) OR ${identifier} IS NULL`,
76180
- [value]
76181
- );
76426
+ return q2.where(
76427
+ (subq) => subq.not.whereNull(identifier).and.where(identifier, "!=", value)
76428
+ ).or.whereNull(identifier);
76182
76429
  } else {
76183
- return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} != ?, TRUE)`, [
76430
+ return q2.whereRaw(`COALESCE(?? != ?, TRUE)`, [
76431
+ this.rawQuotedIdentifier(key),
76184
76432
  value
76185
76433
  ]);
76186
76434
  }
@@ -76188,14 +76436,18 @@ var InternalBuilder = class {
76188
76436
  }
76189
76437
  if (filters.empty) {
76190
76438
  iterate(filters.empty, "empty" /* EMPTY */, (q2, key) => {
76191
- const fnc = allOr ? "orWhereNull" : "whereNull";
76192
- return q2[fnc](key);
76439
+ if (shouldOr) {
76440
+ q2 = q2.or;
76441
+ }
76442
+ return q2.whereNull(key);
76193
76443
  });
76194
76444
  }
76195
76445
  if (filters.notEmpty) {
76196
76446
  iterate(filters.notEmpty, "notEmpty" /* NOT_EMPTY */, (q2, key) => {
76197
- const fnc = allOr ? "orWhereNotNull" : "whereNotNull";
76198
- return q2[fnc](key);
76447
+ if (shouldOr) {
76448
+ q2 = q2.or;
76449
+ }
76450
+ return q2.whereNotNull(key);
76199
76451
  });
76200
76452
  }
76201
76453
  if (filters.contains) {
@@ -76264,7 +76516,7 @@ var InternalBuilder = class {
76264
76516
  const selectFields = qualifiedFields.map(
76265
76517
  (field) => this.convertClobs(field, { forSelect: true })
76266
76518
  );
76267
- query = query.groupByRaw(groupByFields.join(", ")).select(this.knex.raw(selectFields.join(", ")));
76519
+ query = query.groupBy(groupByFields).select(selectFields);
76268
76520
  } else {
76269
76521
  query = query.groupBy(qualifiedFields).select(qualifiedFields);
76270
76522
  }
@@ -76276,11 +76528,10 @@ var InternalBuilder = class {
76276
76528
  if (this.client === "oracledb" /* ORACLE */) {
76277
76529
  const field = this.convertClobs(`${tableName}.${aggregation.field}`);
76278
76530
  query = query.select(
76279
- this.knex.raw(
76280
- `COUNT(DISTINCT ${field}) as ${this.quotedIdentifier(
76281
- aggregation.name
76282
- )}`
76283
- )
76531
+ this.knex.raw(`COUNT(DISTINCT ??) as ??`, [
76532
+ field,
76533
+ aggregation.name
76534
+ ])
76284
76535
  );
76285
76536
  } else {
76286
76537
  query = query.countDistinct(
@@ -76335,9 +76586,11 @@ var InternalBuilder = class {
76335
76586
  } else {
76336
76587
  let composite = `${aliased}.${key}`;
76337
76588
  if (this.client === "oracledb" /* ORACLE */) {
76338
- query = query.orderByRaw(
76339
- `${this.convertClobs(composite)} ${direction} nulls ${nulls}`
76340
- );
76589
+ query = query.orderByRaw(`?? ?? nulls ??`, [
76590
+ this.convertClobs(composite),
76591
+ this.knex.raw(direction),
76592
+ this.knex.raw(nulls)
76593
+ ]);
76341
76594
  } else {
76342
76595
  query = query.orderBy(composite, direction, nulls);
76343
76596
  }
@@ -76359,17 +76612,18 @@ var InternalBuilder = class {
76359
76612
  }
76360
76613
  buildJsonField(field) {
76361
76614
  const parts = field.split(".");
76362
- let tableField, unaliased;
76615
+ let unaliased;
76616
+ let tableField;
76363
76617
  if (parts.length > 1) {
76364
76618
  const alias = parts.shift();
76365
76619
  unaliased = parts.join(".");
76366
- tableField = `${this.quote(alias)}.${this.quote(unaliased)}`;
76620
+ tableField = `${alias}.${unaliased}`;
76367
76621
  } else {
76368
76622
  unaliased = parts.join(".");
76369
- tableField = this.quote(unaliased);
76623
+ tableField = unaliased;
76370
76624
  }
76371
76625
  const separator = this.client === "oracledb" /* ORACLE */ ? " VALUE " : ",";
76372
- return `'${unaliased}'${separator}${tableField}`;
76626
+ return this.knex.raw(`?${separator}??`, [unaliased, this.rawQuotedIdentifier(tableField)]).toString();
76373
76627
  }
76374
76628
  maxFunctionParameters() {
76375
76629
  switch (this.client) {
@@ -76433,11 +76687,11 @@ var InternalBuilder = class {
76433
76687
  subQuery = subQuery.where(
76434
76688
  correlatedTo,
76435
76689
  "=",
76436
- knex3.raw(this.quotedIdentifier(correlatedFrom))
76690
+ this.rawQuotedIdentifier(correlatedFrom)
76437
76691
  );
76438
76692
  const standardWrap = (select) => {
76439
76693
  subQuery = subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit());
76440
- return knex3.select(knex3.raw(select)).from({
76694
+ return knex3.select(select).from({
76441
76695
  [toAlias]: subQuery
76442
76696
  });
76443
76697
  };
@@ -76446,12 +76700,12 @@ var InternalBuilder = class {
76446
76700
  case "sqlite3" /* SQL_LITE */:
76447
76701
  subQuery = this.addJoinFieldCheck(subQuery, relationship);
76448
76702
  wrapperQuery = standardWrap(
76449
- `json_group_array(json_object(${fieldList}))`
76703
+ this.knex.raw(`json_group_array(json_object(${fieldList}))`)
76450
76704
  );
76451
76705
  break;
76452
76706
  case "pg" /* POSTGRES */:
76453
76707
  wrapperQuery = standardWrap(
76454
- `json_agg(json_build_object(${fieldList}))`
76708
+ this.knex.raw(`json_agg(json_build_object(${fieldList}))`)
76455
76709
  );
76456
76710
  break;
76457
76711
  case "mariadb" /* MARIADB */:
@@ -76464,16 +76718,19 @@ var InternalBuilder = class {
76464
76718
  case "mysql2" /* MY_SQL */:
76465
76719
  case "oracledb" /* ORACLE */:
76466
76720
  wrapperQuery = standardWrap(
76467
- `json_arrayagg(json_object(${fieldList}))`
76721
+ this.knex.raw(`json_arrayagg(json_object(${fieldList}))`)
76468
76722
  );
76469
76723
  break;
76470
- case "mssql" /* MS_SQL */:
76724
+ case "mssql" /* MS_SQL */: {
76725
+ const comparatorQuery = knex3.select(`${fromAlias}.*`).from({
76726
+ [fromAlias]: subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit())
76727
+ });
76471
76728
  wrapperQuery = knex3.raw(
76472
- `(SELECT ${this.quote(toAlias)} = (${knex3.select(`${fromAlias}.*`).from({
76473
- [fromAlias]: subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit())
76474
- })} FOR JSON PATH))`
76729
+ `(SELECT ?? = (${comparatorQuery} FOR JSON PATH))`,
76730
+ [this.rawQuotedIdentifier(toAlias)]
76475
76731
  );
76476
76732
  break;
76733
+ }
76477
76734
  default:
76478
76735
  throw new Error(`JSON relationships not implement for ${sqlClient}`);
76479
76736
  }