@budibase/backend-core 2.33.1 → 2.33.3

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
@@ -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;
@@ -67726,12 +67784,13 @@ var FlagSet = class {
67726
67784
  }
67727
67785
  };
67728
67786
  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),
67787
+ ["DEFAULT_VALUES" /* DEFAULT_VALUES */]: Flag.boolean(environment_default.isDev()),
67788
+ ["AUTOMATION_BRANCHING" /* AUTOMATION_BRANCHING */]: Flag.boolean(environment_default.isDev()),
67789
+ ["SQS" /* SQS */]: Flag.boolean(true),
67732
67790
  ["AI_CUSTOM_CONFIGS" /* AI_CUSTOM_CONFIGS */]: Flag.boolean(environment_default.isDev()),
67733
67791
  ["ENRICHED_RELATIONSHIPS" /* ENRICHED_RELATIONSHIPS */]: Flag.boolean(environment_default.isDev()),
67734
- ["TABLES_DEFAULT_ADMIN" /* TABLES_DEFAULT_ADMIN */]: Flag.boolean(environment_default.isDev())
67792
+ ["TABLES_DEFAULT_ADMIN" /* TABLES_DEFAULT_ADMIN */]: Flag.boolean(environment_default.isDev()),
67793
+ ["BUDIBASE_AI" /* BUDIBASE_AI */]: Flag.boolean(environment_default.isDev())
67735
67794
  });
67736
67795
 
67737
67796
  // src/features/tests/utils.ts
@@ -68119,7 +68178,7 @@ var DatabaseImpl = class _DatabaseImpl {
68119
68178
  });
68120
68179
  }
68121
68180
  async destroy() {
68122
- if (await flags.isEnabled("SQS") && await this.exists(SQLITE_DESIGN_DOC_ID)) {
68181
+ if (await flags.isEnabled("SQS" /* SQS */) && await this.exists(SQLITE_DESIGN_DOC_ID)) {
68123
68182
  const definition = await this.get(SQLITE_DESIGN_DOC_ID);
68124
68183
  definition.sql.tables = {};
68125
68184
  await this.put(definition);
@@ -69321,27 +69380,35 @@ var EmailUnavailableError = class extends Error {
69321
69380
  };
69322
69381
 
69323
69382
  // src/security/roles.ts
69324
- var roles_exports = {};
69325
- __export(roles_exports, {
69383
+ var roles_exports2 = {};
69384
+ __export(roles_exports2, {
69326
69385
  AccessController: () => AccessController,
69327
69386
  BUILTIN_ROLE_IDS: () => BUILTIN_ROLE_IDS,
69328
- Role: () => Role,
69387
+ Role: () => Role2,
69388
+ RoleHierarchyTraversal: () => RoleHierarchyTraversal,
69329
69389
  RoleIDVersion: () => RoleIDVersion,
69330
69390
  builtinRoleToNumber: () => builtinRoleToNumber,
69331
69391
  checkForRoleResourceArray: () => checkForRoleResourceArray,
69392
+ compareRoleIds: () => compareRoleIds,
69393
+ externalRole: () => externalRole,
69394
+ findRole: () => findRole,
69332
69395
  getAllRoleIds: () => getAllRoleIds,
69333
69396
  getAllRoles: () => getAllRoles,
69334
69397
  getBuiltinRole: () => getBuiltinRole,
69335
69398
  getBuiltinRoles: () => getBuiltinRoles,
69336
69399
  getDBRoleID: () => getDBRoleID,
69337
69400
  getExternalRoleID: () => getExternalRoleID,
69401
+ getExternalRoleIDs: () => getExternalRoleIDs,
69338
69402
  getRole: () => getRole,
69339
69403
  getUserRoleHierarchy: () => getUserRoleHierarchy,
69340
69404
  getUserRoleIdHierarchy: () => getUserRoleIdHierarchy,
69341
69405
  isBuiltin: () => isBuiltin,
69342
69406
  lowerBuiltinRoleID: () => lowerBuiltinRoleID,
69343
- roleToNumber: () => roleToNumber
69407
+ prefixRoleIDNoBuiltin: () => prefixRoleIDNoBuiltin,
69408
+ roleToNumber: () => roleToNumber,
69409
+ saveRoles: () => saveRoles
69344
69410
  });
69411
+ var import_semver = __toESM(require("semver"));
69345
69412
 
69346
69413
  // src/security/permissions.ts
69347
69414
  var permissions_exports = {};
@@ -69493,6 +69560,7 @@ var GLOBAL_BUILDER = "globalBuilder" /* GLOBAL_BUILDER */;
69493
69560
 
69494
69561
  // src/security/roles.ts
69495
69562
  var import_cloneDeep2 = __toESM(require("lodash/fp/cloneDeep"));
69563
+ var import_lodash4 = require("lodash");
69496
69564
  var BUILTIN_ROLE_IDS = {
69497
69565
  ADMIN: "ADMIN",
69498
69566
  POWER: "POWER",
@@ -69503,19 +69571,20 @@ var BUILTIN_IDS = {
69503
69571
  ...BUILTIN_ROLE_IDS,
69504
69572
  BUILDER: "BUILDER"
69505
69573
  };
69506
- var EXTERNAL_BUILTIN_ROLE_IDS = [
69507
- BUILTIN_IDS.ADMIN,
69508
- BUILTIN_IDS.POWER,
69509
- BUILTIN_IDS.BASIC,
69510
- BUILTIN_IDS.PUBLIC
69511
- ];
69512
69574
  var RoleIDVersion = {
69513
69575
  // original version, with a UUID based ID
69514
69576
  UUID: void 0,
69515
69577
  // new version - with name based ID
69516
69578
  NAME: "name"
69517
69579
  };
69518
- var Role = class {
69580
+ function rolesInList(roleIds, ids) {
69581
+ if (Array.isArray(ids)) {
69582
+ return ids.filter((id) => roleIds.includes(id)).length === ids.length;
69583
+ } else {
69584
+ return roleIds.includes(ids);
69585
+ }
69586
+ }
69587
+ var Role2 = class {
69519
69588
  constructor(id, name, permissionId, uiMetadata) {
69520
69589
  this.permissions = {};
69521
69590
  this._id = id;
@@ -69525,12 +69594,57 @@ var Role = class {
69525
69594
  this.version = RoleIDVersion.NAME;
69526
69595
  }
69527
69596
  addInheritance(inherits) {
69597
+ if (inherits && typeof inherits === "string") {
69598
+ inherits = prefixRoleIDNoBuiltin(inherits);
69599
+ } else if (inherits && Array.isArray(inherits)) {
69600
+ inherits = inherits.map(prefixRoleIDNoBuiltin);
69601
+ }
69528
69602
  this.inherits = inherits;
69529
69603
  return this;
69530
69604
  }
69531
69605
  };
69606
+ var RoleHierarchyTraversal = class {
69607
+ constructor(allRoles, opts) {
69608
+ this.allRoles = allRoles;
69609
+ this.opts = opts;
69610
+ }
69611
+ walk(role) {
69612
+ const opts = this.opts, allRoles = this.allRoles;
69613
+ let roleList = [];
69614
+ if (!role || !role._id) {
69615
+ return roleList;
69616
+ }
69617
+ roleList.push(role);
69618
+ if (Array.isArray(role.inherits)) {
69619
+ for (let roleId of role.inherits) {
69620
+ const foundRole = findRole(roleId, allRoles, opts);
69621
+ if (foundRole) {
69622
+ roleList = roleList.concat(this.walk(foundRole));
69623
+ }
69624
+ }
69625
+ } else {
69626
+ const foundRoleIds = [];
69627
+ let currentRole = role;
69628
+ while (currentRole && currentRole.inherits && !rolesInList(foundRoleIds, currentRole.inherits)) {
69629
+ if (Array.isArray(currentRole.inherits)) {
69630
+ return roleList.concat(this.walk(currentRole));
69631
+ } else {
69632
+ foundRoleIds.push(currentRole.inherits);
69633
+ currentRole = findRole(currentRole.inherits, allRoles, opts);
69634
+ if (currentRole) {
69635
+ roleList.push(currentRole);
69636
+ }
69637
+ }
69638
+ if (helpers_exports.roles.checkForRoleInheritanceLoops(roleList)) {
69639
+ break;
69640
+ }
69641
+ }
69642
+ }
69643
+ return (0, import_lodash4.uniqBy)(roleList, (role2) => role2._id);
69644
+ }
69645
+ };
69532
69646
  var BUILTIN_ROLES = {
69533
- ADMIN: new Role(
69647
+ ADMIN: new Role2(
69534
69648
  BUILTIN_IDS.ADMIN,
69535
69649
  BUILTIN_IDS.ADMIN,
69536
69650
  "admin" /* ADMIN */,
@@ -69540,7 +69654,7 @@ var BUILTIN_ROLES = {
69540
69654
  color: "var(--spectrum-global-color-static-red-400)" /* ADMIN */
69541
69655
  }
69542
69656
  ).addInheritance(BUILTIN_IDS.POWER),
69543
- POWER: new Role(
69657
+ POWER: new Role2(
69544
69658
  BUILTIN_IDS.POWER,
69545
69659
  BUILTIN_IDS.POWER,
69546
69660
  "power" /* POWER */,
@@ -69550,7 +69664,7 @@ var BUILTIN_ROLES = {
69550
69664
  color: "var(--spectrum-global-color-static-orange-400)" /* POWER */
69551
69665
  }
69552
69666
  ).addInheritance(BUILTIN_IDS.BASIC),
69553
- BASIC: new Role(
69667
+ BASIC: new Role2(
69554
69668
  BUILTIN_IDS.BASIC,
69555
69669
  BUILTIN_IDS.BASIC,
69556
69670
  "write" /* WRITE */,
@@ -69560,7 +69674,7 @@ var BUILTIN_ROLES = {
69560
69674
  color: "var(--spectrum-global-color-static-green-400)" /* BASIC */
69561
69675
  }
69562
69676
  ).addInheritance(BUILTIN_IDS.PUBLIC),
69563
- PUBLIC: new Role(
69677
+ PUBLIC: new Role2(
69564
69678
  BUILTIN_IDS.PUBLIC,
69565
69679
  BUILTIN_IDS.PUBLIC,
69566
69680
  "public" /* PUBLIC */,
@@ -69570,7 +69684,7 @@ var BUILTIN_ROLES = {
69570
69684
  color: "var(--spectrum-global-color-static-blue-400)" /* PUBLIC */
69571
69685
  }
69572
69686
  ),
69573
- BUILDER: new Role(
69687
+ BUILDER: new Role2(
69574
69688
  BUILTIN_IDS.BUILDER,
69575
69689
  BUILTIN_IDS.BUILDER,
69576
69690
  "admin" /* ADMIN */,
@@ -69585,7 +69699,14 @@ function getBuiltinRoles() {
69585
69699
  return (0, import_cloneDeep2.default)(BUILTIN_ROLES);
69586
69700
  }
69587
69701
  function isBuiltin(role) {
69588
- return getBuiltinRole(role) !== void 0;
69702
+ return Object.values(BUILTIN_ROLE_IDS).includes(role);
69703
+ }
69704
+ function prefixRoleIDNoBuiltin(roleId) {
69705
+ if (isBuiltin(roleId)) {
69706
+ return roleId;
69707
+ } else {
69708
+ return prefixRoleID(roleId);
69709
+ }
69589
69710
  }
69590
69711
  function getBuiltinRole(roleId) {
69591
69712
  const role = Object.values(BUILTIN_ROLES).find(
@@ -69607,7 +69728,11 @@ function builtinRoleToNumber(id) {
69607
69728
  if (!role) {
69608
69729
  break;
69609
69730
  }
69610
- role = builtins[role.inherits];
69731
+ if (Array.isArray(role.inherits)) {
69732
+ throw new Error("Built-in roles don't support multi-inheritance");
69733
+ } else {
69734
+ role = builtins[role.inherits];
69735
+ }
69611
69736
  count++;
69612
69737
  } while (role !== null);
69613
69738
  return count;
@@ -69619,12 +69744,26 @@ async function roleToNumber(id) {
69619
69744
  const hierarchy = await getUserRoleHierarchy(id, {
69620
69745
  defaultPublic: true
69621
69746
  });
69622
- for (let role of hierarchy) {
69623
- if (role?.inherits && isBuiltin(role.inherits)) {
69747
+ const findNumber = (role) => {
69748
+ if (!role.inherits) {
69749
+ return 0;
69750
+ }
69751
+ if (Array.isArray(role.inherits)) {
69752
+ const highestBuiltin = role.inherits.map((roleId) => {
69753
+ const foundRole = hierarchy.find((role2) => role2._id === roleId);
69754
+ if (foundRole) {
69755
+ return findNumber(foundRole) + 1;
69756
+ }
69757
+ }).filter((number) => number).sort().pop();
69758
+ if (highestBuiltin != void 0) {
69759
+ return highestBuiltin;
69760
+ }
69761
+ } else if (isBuiltin(role.inherits)) {
69624
69762
  return builtinRoleToNumber(role.inherits) + 1;
69625
69763
  }
69626
- }
69627
- return 0;
69764
+ return 0;
69765
+ };
69766
+ return Math.max(...hierarchy.map(findNumber));
69628
69767
  }
69629
69768
  function lowerBuiltinRoleID(roleId1, roleId2) {
69630
69769
  if (!roleId1) {
@@ -69635,39 +69774,67 @@ function lowerBuiltinRoleID(roleId1, roleId2) {
69635
69774
  }
69636
69775
  return builtinRoleToNumber(roleId1) > builtinRoleToNumber(roleId2) ? roleId2 : roleId1;
69637
69776
  }
69638
- async function getRole(roleId, opts) {
69777
+ function compareRoleIds(roleId1, roleId2) {
69778
+ return prefixRoleID(roleId1) === prefixRoleID(roleId2);
69779
+ }
69780
+ function externalRole(role) {
69781
+ let _id;
69782
+ if (role._id) {
69783
+ _id = getExternalRoleID(role._id);
69784
+ }
69785
+ return {
69786
+ ...role,
69787
+ _id,
69788
+ inherits: getExternalRoleIDs(role.inherits, role.version)
69789
+ };
69790
+ }
69791
+ function findRole(roleId, roles, opts) {
69639
69792
  let role = getBuiltinRole(roleId);
69640
69793
  if (!role) {
69641
69794
  roleId = prefixRoleID(roleId);
69642
69795
  }
69643
- try {
69644
- const db = getAppDB();
69645
- const dbRole = await db.get(getDBRoleID(roleId));
69646
- role = Object.assign(role || {}, dbRole);
69796
+ const dbRole = roles.find(
69797
+ (role2) => role2._id && compareRoleIds(role2._id, roleId)
69798
+ );
69799
+ if (!dbRole && !isBuiltin(roleId) && opts?.defaultPublic) {
69800
+ return (0, import_cloneDeep2.default)(BUILTIN_ROLES.PUBLIC);
69801
+ }
69802
+ role = Object.assign(role || {}, dbRole);
69803
+ if (role?._id) {
69647
69804
  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;
69805
+ }
69806
+ return Object.keys(role).length === 0 ? void 0 : role;
69807
+ }
69808
+ async function getRole(roleId, opts) {
69809
+ const db = getAppDB();
69810
+ const roleList = [];
69811
+ if (!isBuiltin(roleId)) {
69812
+ const role = await db.tryGet(getDBRoleID(roleId));
69813
+ if (role) {
69814
+ roleList.push(role);
69654
69815
  }
69655
69816
  }
69656
- return role;
69817
+ return findRole(roleId, roleList, opts);
69818
+ }
69819
+ async function saveRoles(roles) {
69820
+ const db = getAppDB();
69821
+ await db.bulkDocs(
69822
+ roles.filter((role) => role._id).map((role) => ({
69823
+ ...role,
69824
+ _id: prefixRoleID(role._id)
69825
+ }))
69826
+ );
69657
69827
  }
69658
69828
  async function getAllUserRoles(userRoleId, opts) {
69829
+ const allRoles = await getAllRoles();
69659
69830
  if (userRoleId === BUILTIN_IDS.ADMIN) {
69660
- return getAllRoles();
69831
+ return allRoles;
69661
69832
  }
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
- }
69833
+ const foundRole = findRole(userRoleId, allRoles, opts);
69834
+ let roles = [];
69835
+ if (foundRole) {
69836
+ const traversal = new RoleHierarchyTraversal(allRoles, opts);
69837
+ roles = traversal.walk(foundRole);
69671
69838
  }
69672
69839
  return roles;
69673
69840
  }
@@ -69717,7 +69884,22 @@ async function getAllRoles(appId) {
69717
69884
  );
69718
69885
  }
69719
69886
  const builtinRoles = getBuiltinRoles();
69720
- for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
69887
+ let externalBuiltinRoles = [];
69888
+ if (!db || await shouldIncludePowerRole(db)) {
69889
+ externalBuiltinRoles = [
69890
+ BUILTIN_IDS.ADMIN,
69891
+ BUILTIN_IDS.POWER,
69892
+ BUILTIN_IDS.BASIC,
69893
+ BUILTIN_IDS.PUBLIC
69894
+ ];
69895
+ } else {
69896
+ externalBuiltinRoles = [
69897
+ BUILTIN_IDS.ADMIN,
69898
+ BUILTIN_IDS.BASIC,
69899
+ BUILTIN_IDS.PUBLIC
69900
+ ];
69901
+ }
69902
+ for (let builtinRoleId of externalBuiltinRoles) {
69721
69903
  const builtinRole = builtinRoles[builtinRoleId];
69722
69904
  const dbBuiltin = roles.filter(
69723
69905
  (dbRole) => getExternalRoleID(dbRole._id, dbRole.version) === builtinRoleId
@@ -69744,6 +69926,15 @@ async function getAllRoles(appId) {
69744
69926
  return roles;
69745
69927
  }
69746
69928
  }
69929
+ async function shouldIncludePowerRole(db) {
69930
+ const app = await db.tryGet("app_metadata" /* APP_METADATA */);
69931
+ const creationVersion = app?.creationVersion;
69932
+ if (!creationVersion || !import_semver.default.valid(creationVersion)) {
69933
+ return true;
69934
+ }
69935
+ const isGreaterThan3x = import_semver.default.gte(creationVersion, "3.0.0");
69936
+ return !isGreaterThan3x;
69937
+ }
69747
69938
  var AccessController = class {
69748
69939
  constructor() {
69749
69940
  this.userHierarchies = {};
@@ -69757,7 +69948,7 @@ var AccessController = class {
69757
69948
  roleIds = await getUserRoleIdHierarchy(userRoleId);
69758
69949
  this.userHierarchies[userRoleId] = roleIds;
69759
69950
  }
69760
- return roleIds?.indexOf(tryingRoleId) !== -1;
69951
+ return roleIds?.find((roleId) => compareRoleIds(roleId, tryingRoleId)) !== void 0;
69761
69952
  }
69762
69953
  async checkScreensAccess(screens, userRoleId) {
69763
69954
  let accessibleScreens = [];
@@ -69784,13 +69975,22 @@ function getDBRoleID(roleName) {
69784
69975
  return prefixRoleID(roleName);
69785
69976
  }
69786
69977
  function getExternalRoleID(roleId, version) {
69787
- if (roleId.startsWith("role" /* ROLE */) && (isBuiltin(roleId) || version === RoleIDVersion.NAME)) {
69978
+ if (roleId.startsWith(`${"role" /* ROLE */}${SEPARATOR}`) && (isBuiltin(roleId) || version === RoleIDVersion.NAME)) {
69788
69979
  const parts = roleId.split(SEPARATOR);
69789
69980
  parts.shift();
69790
69981
  return parts.join(SEPARATOR);
69791
69982
  }
69792
69983
  return roleId;
69793
69984
  }
69985
+ function getExternalRoleIDs(roleIds, version) {
69986
+ if (!roleIds) {
69987
+ return roleIds;
69988
+ } else if (typeof roleIds === "string") {
69989
+ return getExternalRoleID(roleIds, version);
69990
+ } else {
69991
+ return roleIds.map((roleId) => getExternalRoleID(roleId, version));
69992
+ }
69993
+ }
69794
69994
 
69795
69995
  // src/users/utils.ts
69796
69996
  var isBuilder2 = sdk_exports.users.isBuilder;
@@ -70590,7 +70790,7 @@ __export(installation_exports, {
70590
70790
  getInstall: () => getInstall,
70591
70791
  getInstallFromDB: () => getInstallFromDB
70592
70792
  });
70593
- var import_semver = __toESM(require("semver"));
70793
+ var import_semver2 = __toESM(require("semver"));
70594
70794
  var getInstall = async () => {
70595
70795
  return withCache("installation" /* INSTALLATION */, 86400 /* ONE_DAY */, getInstallFromDB, {
70596
70796
  useTenancy: false
@@ -70659,8 +70859,8 @@ var checkInstallVersion = async () => {
70659
70859
  const newVersion = environment_default.VERSION;
70660
70860
  try {
70661
70861
  if (currentVersion !== newVersion) {
70662
- const isUpgrade = import_semver.default.gt(newVersion, currentVersion);
70663
- const isDowngrade = import_semver.default.lt(newVersion, currentVersion);
70862
+ const isUpgrade = import_semver2.default.gt(newVersion, currentVersion);
70863
+ const isDowngrade = import_semver2.default.lt(newVersion, currentVersion);
70664
70864
  const success = await updateVersion(newVersion);
70665
70865
  if (success) {
70666
70866
  await doInIdentityContext(
@@ -74435,6 +74635,7 @@ function timeMinusOneMinute() {
74435
74635
  function finalise(ctx, opts = {}) {
74436
74636
  ctx.publicEndpoint = opts.publicEndpoint || false;
74437
74637
  ctx.isAuthenticated = opts.authenticated || false;
74638
+ ctx.loginMethod = opts.loginMethod;
74438
74639
  ctx.user = opts.user;
74439
74640
  ctx.internal = opts.internal || false;
74440
74641
  ctx.version = opts.version;
@@ -74492,7 +74693,7 @@ function authenticated_default(noAuthPatterns = [], opts = {
74492
74693
  apiKey = ctx.request.headers["authorization" /* AUTHORIZATION */].split(" ")[1];
74493
74694
  }
74494
74695
  const tenantId = ctx.request.headers["x-budibase-tenant-id" /* TENANT_ID */];
74495
- let authenticated = false, user = null, internal = false;
74696
+ let authenticated = false, user = void 0, internal = false, loginMethod = void 0;
74496
74697
  if (authCookie && !apiKey) {
74497
74698
  const sessionId = authCookie.sessionId;
74498
74699
  const userId = authCookie.userId;
@@ -74514,6 +74715,7 @@ function authenticated_default(noAuthPatterns = [], opts = {
74514
74715
  });
74515
74716
  }
74516
74717
  user.csrfToken = session.csrfToken;
74718
+ loginMethod = "cookie" /* COOKIE */;
74517
74719
  if (session?.lastAccessedAt < timeMinusOneMinute()) {
74518
74720
  await updateSessionTTL(session);
74519
74721
  }
@@ -74530,17 +74732,16 @@ function authenticated_default(noAuthPatterns = [], opts = {
74530
74732
  apiKey,
74531
74733
  populateUser
74532
74734
  );
74533
- if (valid && foundUser) {
74735
+ if (valid) {
74534
74736
  authenticated = true;
74737
+ loginMethod = "api_key" /* API_KEY */;
74535
74738
  user = foundUser;
74536
- } else if (valid) {
74537
- authenticated = true;
74538
- internal = true;
74739
+ internal = !foundUser;
74539
74740
  }
74540
74741
  }
74541
74742
  if (!user && tenantId) {
74542
74743
  user = { tenantId };
74543
- } else if (user) {
74744
+ } else if (user && "password" in user) {
74544
74745
  delete user.password;
74545
74746
  }
74546
74747
  if (!authenticated) {
@@ -74557,7 +74758,14 @@ function authenticated_default(noAuthPatterns = [], opts = {
74557
74758
  status: user.status
74558
74759
  });
74559
74760
  }
74560
- finalise(ctx, { authenticated, user, internal, version, publicEndpoint });
74761
+ finalise(ctx, {
74762
+ authenticated,
74763
+ user,
74764
+ internal,
74765
+ version,
74766
+ publicEndpoint,
74767
+ loginMethod
74768
+ });
74561
74769
  if (isUser(user)) {
74562
74770
  return doInUserContext(user, ctx, next);
74563
74771
  } else {
@@ -75294,7 +75502,7 @@ var import_knex2 = require("knex");
75294
75502
  // src/sql/sqlTable.ts
75295
75503
  var import_knex = require("knex");
75296
75504
  function isIgnoredType(type) {
75297
- const ignored = ["link" /* LINK */, "formula" /* FORMULA */];
75505
+ const ignored = ["link" /* LINK */, "formula" /* FORMULA */, "ai" /* AI */];
75298
75506
  return ignored.indexOf(type) !== -1;
75299
75507
  }
75300
75508
  function generateSchema(schema, table, tables, oldTable = null, renamed) {
@@ -75390,6 +75598,8 @@ function generateSchema(schema, table, tables, oldTable = null, renamed) {
75390
75598
  break;
75391
75599
  case "formula" /* FORMULA */:
75392
75600
  break;
75601
+ case "ai" /* AI */:
75602
+ break;
75393
75603
  case "attachment" /* ATTACHMENTS */:
75394
75604
  case "attachment_single" /* ATTACHMENT_SINGLE */:
75395
75605
  case "signature_single" /* SIGNATURE_SINGLE */:
@@ -75521,7 +75731,7 @@ var SqlTableQueryBuilder = class {
75521
75731
  var sqlTable_default = SqlTableQueryBuilder;
75522
75732
 
75523
75733
  // src/sql/sql.ts
75524
- var import_lodash4 = require("lodash");
75734
+ var import_lodash5 = require("lodash");
75525
75735
  var COUNT_FIELD_NAME = "__bb_total";
75526
75736
  function getBaseLimit() {
75527
75737
  const envLimit = environment_default.SQL_MAX_ROWS ? parseInt(environment_default.SQL_MAX_ROWS) : null;
@@ -75562,6 +75772,35 @@ function convertBooleans(query) {
75562
75772
  function isSqs(table) {
75563
75773
  return table.sourceType === "internal" /* INTERNAL */ || table.sourceId === INTERNAL_TABLE_SOURCE_ID;
75564
75774
  }
75775
+ function escapeQuotes(value, quoteChar = '"') {
75776
+ return value.replace(new RegExp(quoteChar, "g"), `${quoteChar}${quoteChar}`);
75777
+ }
75778
+ function wrap(value, quoteChar = '"') {
75779
+ return `${quoteChar}${escapeQuotes(value, quoteChar)}${quoteChar}`;
75780
+ }
75781
+ function stringifyArray(value, quoteStyle = '"') {
75782
+ for (let i in value) {
75783
+ if (typeof value[i] === "string") {
75784
+ value[i] = wrap(value[i], quoteStyle);
75785
+ }
75786
+ }
75787
+ return `[${value.join(",")}]`;
75788
+ }
75789
+ var allowEmptyRelationships = {
75790
+ ["equal" /* EQUAL */]: false,
75791
+ ["notEqual" /* NOT_EQUAL */]: true,
75792
+ ["empty" /* EMPTY */]: false,
75793
+ ["notEmpty" /* NOT_EMPTY */]: true,
75794
+ ["fuzzy" /* FUZZY */]: false,
75795
+ ["string" /* STRING */]: false,
75796
+ ["range" /* RANGE */]: false,
75797
+ ["contains" /* CONTAINS */]: false,
75798
+ ["notContains" /* NOT_CONTAINS */]: true,
75799
+ ["containsAny" /* CONTAINS_ANY */]: false,
75800
+ ["oneOf" /* ONE_OF */]: false,
75801
+ ["$and" /* AND */]: false,
75802
+ ["$or" /* OR */]: false
75803
+ };
75565
75804
  var InternalBuilder = class {
75566
75805
  constructor(client, knex3, query) {
75567
75806
  // states the various situations in which we need a full mapped select statement
@@ -75584,28 +75823,24 @@ var InternalBuilder = class {
75584
75823
  get table() {
75585
75824
  return this.query.meta.table;
75586
75825
  }
75826
+ get knexClient() {
75827
+ return this.knex.client;
75828
+ }
75587
75829
  getFieldSchema(key) {
75588
75830
  const { column } = this.splitter.run(key);
75589
75831
  return this.table.schema[column];
75590
75832
  }
75833
+ supportsILike() {
75834
+ return !(this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */);
75835
+ }
75591
75836
  quoteChars() {
75592
- switch (this.client) {
75593
- case "oracledb" /* ORACLE */:
75594
- case "pg" /* POSTGRES */:
75595
- return ['"', '"'];
75596
- case "mssql" /* MS_SQL */:
75597
- return ["[", "]"];
75598
- case "mariadb" /* MARIADB */:
75599
- case "mysql2" /* MY_SQL */:
75600
- case "sqlite3" /* SQL_LITE */:
75601
- return ["`", "`"];
75602
- }
75837
+ const wrapped = this.knexClient.wrapIdentifier("foo", {});
75838
+ return [wrapped[0], wrapped[wrapped.length - 1]];
75603
75839
  }
75604
- // Takes a string like foo and returns a quoted string like [foo] for SQL Server
75605
- // and "foo" for Postgres.
75840
+ // Takes a string like foo and returns a quoted string like [foo] for SQL
75841
+ // Server and "foo" for Postgres.
75606
75842
  quote(str) {
75607
- const [start2, end2] = this.quoteChars();
75608
- return `${start2}${str}${end2}`;
75843
+ return this.knexClient.wrapIdentifier(str, {});
75609
75844
  }
75610
75845
  isQuoted(key) {
75611
75846
  const [start2, end2] = this.quoteChars();
@@ -75620,6 +75855,27 @@ var InternalBuilder = class {
75620
75855
  }
75621
75856
  return key.map((part) => this.quote(part)).join(".");
75622
75857
  }
75858
+ quotedValue(value) {
75859
+ const formatter = this.knexClient.formatter(this.knexClient.queryBuilder());
75860
+ return formatter.wrap(value, false);
75861
+ }
75862
+ rawQuotedValue(value) {
75863
+ return this.knex.raw(this.quotedValue(value));
75864
+ }
75865
+ // Unfortuantely we cannot rely on knex's identifier escaping because it trims
75866
+ // the identifier string before escaping it, which breaks cases for us where
75867
+ // columns that start or end with a space aren't referenced correctly anymore.
75868
+ //
75869
+ // So whenever you're using an identifier binding in knex, e.g. knex.raw("??
75870
+ // as ?", ["foo", "bar"]), you need to make sure you call this:
75871
+ //
75872
+ // knex.raw("?? as ?", [this.quotedIdentifier("foo"), "bar"])
75873
+ //
75874
+ // Issue we filed against knex about this:
75875
+ // https://github.com/knex/knex/issues/6143
75876
+ rawQuotedIdentifier(key) {
75877
+ return this.knex.raw(this.quotedIdentifier(key));
75878
+ }
75623
75879
  // Turns an identifier like a.b.c or `a`.`b`.`c` into ["a", "b", "c"]
75624
75880
  splitIdentifier(key) {
75625
75881
  const [start2, end2] = this.quoteChars();
@@ -75658,7 +75914,7 @@ var InternalBuilder = class {
75658
75914
  const alias = this.getTableName(endpoint.entityId);
75659
75915
  const schema = meta.table.schema;
75660
75916
  if (!this.isFullSelectStatementRequired()) {
75661
- return [this.knex.raw(`${this.quote(alias)}.*`)];
75917
+ return [this.knex.raw("??", [`${alias}.*`])];
75662
75918
  }
75663
75919
  return resource.fields.map((field) => {
75664
75920
  const parts = field.split(/\./g);
@@ -75672,17 +75928,21 @@ var InternalBuilder = class {
75672
75928
  }).filter(({ table }) => !table || table === alias).map(({ table, column, field }) => {
75673
75929
  const columnSchema = schema[column];
75674
75930
  if (this.SPECIAL_SELECT_CASES.POSTGRES_MONEY(columnSchema)) {
75675
- return this.knex.raw(
75676
- `${this.quotedIdentifier(
75677
- [table, column].join(".")
75678
- )}::money::numeric as ${this.quote(field)}`
75679
- );
75931
+ return this.knex.raw(`??::money::numeric as "${field}"`, [
75932
+ this.rawQuotedIdentifier([table, column].join(".")),
75933
+ field
75934
+ ]);
75680
75935
  }
75681
75936
  if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(columnSchema)) {
75682
- return this.knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`);
75937
+ return this.knex.raw(`CONVERT(varchar, ??, 108) as "${field}"`, [
75938
+ this.rawQuotedIdentifier(field)
75939
+ ]);
75940
+ }
75941
+ if (table) {
75942
+ return this.rawQuotedIdentifier(`${table}.${column}`);
75943
+ } else {
75944
+ return this.rawQuotedIdentifier(field);
75683
75945
  }
75684
- const quoted = table ? `${this.quote(table)}.${this.quote(column)}` : this.quote(field);
75685
- return this.knex.raw(quoted);
75686
75946
  });
75687
75947
  }
75688
75948
  // OracleDB can't use character-large-objects (CLOBs) in WHERE clauses,
@@ -75697,12 +75957,15 @@ var InternalBuilder = class {
75697
75957
  const parts = this.splitIdentifier(field);
75698
75958
  const col = parts.pop();
75699
75959
  const schema = this.table.schema[col];
75700
- let identifier = this.quotedIdentifier(field);
75960
+ let identifier = this.rawQuotedIdentifier(field);
75701
75961
  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 */) {
75702
75962
  if (opts?.forSelect) {
75703
- identifier = `to_char(${identifier}) as ${this.quotedIdentifier(col)}`;
75963
+ identifier = this.knex.raw("to_char(??) as ??", [
75964
+ identifier,
75965
+ this.rawQuotedIdentifier(col)
75966
+ ]);
75704
75967
  } else {
75705
- identifier = `to_char(${identifier})`;
75968
+ identifier = this.knex.raw("to_char(??)", [identifier]);
75706
75969
  }
75707
75970
  }
75708
75971
  return identifier;
@@ -75747,7 +76010,7 @@ var InternalBuilder = class {
75747
76010
  return body2;
75748
76011
  }
75749
76012
  parseFilters(filters) {
75750
- filters = (0, import_lodash4.cloneDeep)(filters);
76013
+ filters = (0, import_lodash5.cloneDeep)(filters);
75751
76014
  for (const op of Object.values(BasicOperator)) {
75752
76015
  const filter = filters[op];
75753
76016
  if (!filter) {
@@ -75806,21 +76069,32 @@ var InternalBuilder = class {
75806
76069
  const document = relationship.from?.split(".")[0] || "";
75807
76070
  return query.andWhere(`${document}.fieldName`, "=", relationship.column);
75808
76071
  }
75809
- addRelationshipForFilter(query, filterKey, whereCb) {
75810
- const mainKnex = this.knex;
76072
+ addRelationshipForFilter(query, allowEmptyRelationships2, filterKey, whereCb) {
75811
76073
  const { relationships, endpoint, tableAliases: aliases } = this.query;
75812
76074
  const tableName = endpoint.entityId;
75813
76075
  const fromAlias = aliases?.[tableName] || tableName;
75814
- const matches2 = (possibleTable) => filterKey.startsWith(`${possibleTable}`);
76076
+ const matches2 = (value) => filterKey.match(new RegExp(`^${value}\\.`));
75815
76077
  if (!relationships) {
75816
76078
  return query;
75817
76079
  }
75818
76080
  for (const relationship of relationships) {
75819
76081
  const relatedTableName = relationship.tableName;
75820
76082
  const toAlias = aliases?.[relatedTableName] || relatedTableName;
75821
- if ((matches2(relatedTableName) || matches2(toAlias)) && relationship.to && relationship.tableName) {
75822
- let subQuery = mainKnex.select(mainKnex.raw(1)).from({ [toAlias]: relatedTableName });
76083
+ const matchesTableName = matches2(relatedTableName) || matches2(toAlias);
76084
+ const matchesRelationName = matches2(relationship.column);
76085
+ if ((matchesTableName || matchesRelationName) && relationship.to && relationship.tableName) {
76086
+ const joinTable = this.knex.select(this.knex.raw(1)).from({ [toAlias]: relatedTableName });
76087
+ let subQuery = joinTable.clone();
75823
76088
  const manyToMany = validateManyToMany(relationship);
76089
+ let updatedKey;
76090
+ if (!matchesTableName) {
76091
+ updatedKey = filterKey.replace(
76092
+ new RegExp(`^${relationship.column}.`),
76093
+ `${aliases[relationship.tableName]}.`
76094
+ );
76095
+ } else {
76096
+ updatedKey = filterKey;
76097
+ }
75824
76098
  if (manyToMany) {
75825
76099
  const throughAlias = aliases?.[manyToMany.through] || relationship.through;
75826
76100
  let throughTable = this.tableNameWithSchema(manyToMany.through, {
@@ -75836,24 +76110,40 @@ var InternalBuilder = class {
75836
76110
  }).where(
75837
76111
  `${throughAlias}.${manyToMany.from}`,
75838
76112
  "=",
75839
- mainKnex.raw(
75840
- this.quotedIdentifier(`${fromAlias}.${manyToMany.fromPrimary}`)
75841
- )
76113
+ this.rawQuotedIdentifier(`${fromAlias}.${manyToMany.fromPrimary}`)
75842
76114
  );
75843
76115
  if (this.client === "sqlite3" /* SQL_LITE */) {
75844
76116
  subQuery = this.addJoinFieldCheck(subQuery, manyToMany);
75845
76117
  }
76118
+ query = query.where((q2) => {
76119
+ q2.whereExists(whereCb(updatedKey, subQuery));
76120
+ if (allowEmptyRelationships2) {
76121
+ q2.orWhereNotExists(
76122
+ joinTable.clone().innerJoin(throughTable, function() {
76123
+ this.on(
76124
+ `${fromAlias}.${manyToMany.fromPrimary}`,
76125
+ "=",
76126
+ `${throughAlias}.${manyToMany.from}`
76127
+ );
76128
+ })
76129
+ );
76130
+ }
76131
+ });
75846
76132
  } else {
76133
+ const toKey = `${toAlias}.${relationship.to}`;
76134
+ const foreignKey = `${fromAlias}.${relationship.from}`;
75847
76135
  subQuery = subQuery.where(
75848
- `${toAlias}.${relationship.to}`,
76136
+ toKey,
75849
76137
  "=",
75850
- mainKnex.raw(
75851
- this.quotedIdentifier(`${fromAlias}.${relationship.from}`)
75852
- )
76138
+ this.rawQuotedIdentifier(foreignKey)
75853
76139
  );
76140
+ query = query.where((q2) => {
76141
+ q2.whereExists(whereCb(updatedKey, subQuery.clone()));
76142
+ if (allowEmptyRelationships2) {
76143
+ q2.orWhereNotExists(subQuery);
76144
+ }
76145
+ });
75854
76146
  }
75855
- query = query.whereExists(whereCb(subQuery));
75856
- break;
75857
76147
  }
75858
76148
  }
75859
76149
  return query;
@@ -75866,14 +76156,14 @@ var InternalBuilder = class {
75866
76156
  const builder = this;
75867
76157
  filters = this.parseFilters({ ...filters });
75868
76158
  const aliases = this.query.tableAliases;
75869
- const allOr = filters.allOr;
76159
+ const shouldOr = filters.allOr;
75870
76160
  const isSqlite = this.client === "sqlite3" /* SQL_LITE */;
75871
76161
  const tableName = isSqlite ? this.table._id : this.table.name;
75872
76162
  function getTableAlias(name) {
75873
76163
  const alias = aliases?.[name];
75874
76164
  return alias || name;
75875
76165
  }
75876
- function iterate(structure, fn, complexKeyFn) {
76166
+ function iterate(structure, operation, fn, complexKeyFn) {
75877
76167
  const handleRelationship = (q2, key, value) => {
75878
76168
  const [filterTableName, ...otherProperties] = key.split(".");
75879
76169
  const property = otherProperties.join(".");
@@ -75905,85 +76195,104 @@ var InternalBuilder = class {
75905
76195
  value
75906
76196
  );
75907
76197
  } else if (shouldProcessRelationship) {
75908
- if (allOr) {
76198
+ if (shouldOr) {
75909
76199
  query = query.or;
75910
76200
  }
75911
- query = builder.addRelationshipForFilter(query, updatedKey, (q2) => {
75912
- return handleRelationship(q2, updatedKey, value);
75913
- });
76201
+ query = builder.addRelationshipForFilter(
76202
+ query,
76203
+ allowEmptyRelationships[operation],
76204
+ updatedKey,
76205
+ (updatedKey2, q2) => {
76206
+ return handleRelationship(q2, updatedKey2, value);
76207
+ }
76208
+ );
75914
76209
  }
75915
76210
  }
75916
76211
  }
75917
76212
  const like = (q2, key, value) => {
75918
- const fuzzyOr = filters?.fuzzyOr;
75919
- const fnc = fuzzyOr || allOr ? "orWhere" : "where";
75920
- if (this.client === "pg" /* POSTGRES */) {
75921
- return q2[fnc](key, "ilike", `%${value}%`);
75922
- } else {
75923
- const rawFnc = `${fnc}Raw`;
75924
- return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
76213
+ if (filters?.fuzzyOr || shouldOr) {
76214
+ q2 = q2.or;
76215
+ }
76216
+ if (this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */) {
76217
+ return q2.whereRaw(`LOWER(??) LIKE ?`, [
76218
+ this.rawQuotedIdentifier(key),
75925
76219
  `%${value.toLowerCase()}%`
75926
76220
  ]);
75927
76221
  }
76222
+ return q2.whereILike(
76223
+ // @ts-expect-error knex types are wrong, raw is fine here
76224
+ this.rawQuotedIdentifier(key),
76225
+ this.knex.raw("?", [`%${value}%`])
76226
+ );
75928
76227
  };
75929
76228
  const contains = (mode, any = false) => {
75930
- const rawFnc = allOr ? "orWhereRaw" : "whereRaw";
75931
- const not = mode === filters?.notContains ? "NOT " : "";
75932
- function stringifyArray(value, quoteStyle = '"') {
75933
- for (let i in value) {
75934
- if (typeof value[i] === "string") {
75935
- value[i] = `${quoteStyle}${value[i]}${quoteStyle}`;
75936
- }
76229
+ function addModifiers(q2) {
76230
+ if (shouldOr || mode === filters?.containsAny) {
76231
+ q2 = q2.or;
76232
+ }
76233
+ if (mode === filters?.notContains) {
76234
+ q2 = q2.not;
75937
76235
  }
75938
- return `[${value.join(",")}]`;
76236
+ return q2;
75939
76237
  }
75940
76238
  if (this.client === "pg" /* POSTGRES */) {
75941
- iterate(mode, (q2, key, value) => {
75942
- const wrap = any ? "" : "'";
75943
- const op = any ? "\\?| array" : "@>";
75944
- const fieldNames = key.split(/\./g);
75945
- const table = fieldNames[0];
75946
- const col = fieldNames[1];
75947
- return q2[rawFnc](
75948
- `${not}COALESCE("${table}"."${col}"::jsonb ${op} ${wrap}${stringifyArray(
75949
- value,
75950
- any ? "'" : '"'
75951
- )}${wrap}, FALSE)`
75952
- );
76239
+ iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
76240
+ q2 = addModifiers(q2);
76241
+ if (any) {
76242
+ return q2.whereRaw(`COALESCE(??::jsonb \\?| array??, FALSE)`, [
76243
+ this.rawQuotedIdentifier(key),
76244
+ this.knex.raw(stringifyArray(value, "'"))
76245
+ ]);
76246
+ } else {
76247
+ return q2.whereRaw(`COALESCE(??::jsonb @> '??', FALSE)`, [
76248
+ this.rawQuotedIdentifier(key),
76249
+ this.knex.raw(stringifyArray(value))
76250
+ ]);
76251
+ }
75953
76252
  });
75954
76253
  } else if (this.client === "mysql2" /* MY_SQL */ || this.client === "mariadb" /* MARIADB */) {
75955
- const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS";
75956
- iterate(mode, (q2, key, value) => {
75957
- return q2[rawFnc](
75958
- `${not}COALESCE(${jsonFnc}(${key}, '${stringifyArray(
75959
- value
75960
- )}'), FALSE)`
75961
- );
76254
+ iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
76255
+ return addModifiers(q2).whereRaw(`COALESCE(?(??, ?), FALSE)`, [
76256
+ this.knex.raw(any ? "JSON_OVERLAPS" : "JSON_CONTAINS"),
76257
+ this.rawQuotedIdentifier(key),
76258
+ this.knex.raw(wrap(stringifyArray(value)))
76259
+ ]);
75962
76260
  });
75963
76261
  } else {
75964
- const andOr = mode === filters?.containsAny ? " OR " : " AND ";
75965
- iterate(mode, (q2, key, value) => {
75966
- let statement = "";
75967
- const identifier = this.quotedIdentifier(key);
75968
- for (let i in value) {
75969
- if (typeof value[i] === "string") {
75970
- value[i] = `%"${value[i].toLowerCase()}"%`;
75971
- } else {
75972
- value[i] = `%${value[i]}%`;
75973
- }
75974
- statement += `${statement ? andOr : ""}COALESCE(LOWER(${identifier}), '') LIKE ?`;
75975
- }
75976
- if (statement === "") {
76262
+ iterate(mode, "contains" /* CONTAINS */, (q2, key, value) => {
76263
+ if (value.length === 0) {
75977
76264
  return q2;
75978
76265
  }
75979
- if (not) {
75980
- return q2[rawFnc](
75981
- `(NOT (${statement}) OR ${identifier} IS NULL)`,
75982
- value
75983
- );
75984
- } else {
75985
- return q2[rawFnc](statement, value);
75986
- }
76266
+ q2 = q2.where((subQuery) => {
76267
+ if (mode === filters?.notContains) {
76268
+ subQuery = subQuery.not;
76269
+ }
76270
+ subQuery = subQuery.where((subSubQuery) => {
76271
+ for (const elem of value) {
76272
+ if (mode === filters?.containsAny) {
76273
+ subSubQuery = subSubQuery.or;
76274
+ } else {
76275
+ subSubQuery = subSubQuery.and;
76276
+ }
76277
+ const lower = typeof elem === "string" ? `"${elem.toLowerCase()}"` : elem;
76278
+ subSubQuery = subSubQuery.whereLike(
76279
+ // @ts-expect-error knex types are wrong, raw is fine here
76280
+ this.knex.raw(`COALESCE(LOWER(??), '')`, [
76281
+ this.rawQuotedIdentifier(key)
76282
+ ]),
76283
+ `%${lower}%`
76284
+ );
76285
+ }
76286
+ });
76287
+ if (mode === filters?.notContains) {
76288
+ subQuery = subQuery.or.whereNull(
76289
+ // @ts-expect-error knex types are wrong, raw is fine here
76290
+ this.rawQuotedIdentifier(key)
76291
+ );
76292
+ }
76293
+ return subQuery;
76294
+ });
76295
+ return q2;
75987
76296
  });
75988
76297
  }
75989
76298
  };
@@ -76006,48 +76315,49 @@ var InternalBuilder = class {
76006
76315
  });
76007
76316
  }
76008
76317
  if (filters.oneOf) {
76009
- const fnc = allOr ? "orWhereIn" : "whereIn";
76010
76318
  iterate(
76011
76319
  filters.oneOf,
76320
+ "oneOf" /* ONE_OF */,
76012
76321
  (q2, key, array) => {
76322
+ if (shouldOr) {
76323
+ q2 = q2.or;
76324
+ }
76013
76325
  if (this.client === "oracledb" /* ORACLE */) {
76014
76326
  key = this.convertClobs(key);
76015
- array = Array.isArray(array) ? array : [array];
76016
- const binding = new Array(array.length).fill("?").join(",");
76017
- return q2.whereRaw(`${key} IN (${binding})`, array);
76018
- } else {
76019
- return q2[fnc](key, Array.isArray(array) ? array : [array]);
76020
76327
  }
76328
+ return q2.whereIn(key, Array.isArray(array) ? array : [array]);
76021
76329
  },
76022
76330
  (q2, key, array) => {
76331
+ if (shouldOr) {
76332
+ q2 = q2.or;
76333
+ }
76023
76334
  if (this.client === "oracledb" /* ORACLE */) {
76024
- const keyStr = `(${key.map((k) => this.convertClobs(k)).join(",")})`;
76025
- const binding = `(${array.map((a) => `(${new Array(a.length).fill("?").join(",")})`).join(",")})`;
76026
- return q2.whereRaw(`${keyStr} IN ${binding}`, array.flat());
76027
- } else {
76028
- return q2[fnc](key, Array.isArray(array) ? array : [array]);
76335
+ key = key.map((k) => this.convertClobs(k));
76029
76336
  }
76337
+ return q2.whereIn(key, Array.isArray(array) ? array : [array]);
76030
76338
  }
76031
76339
  );
76032
76340
  }
76033
76341
  if (filters.string) {
76034
- iterate(filters.string, (q2, key, value) => {
76035
- const fnc = allOr ? "orWhere" : "where";
76036
- if (this.client === "pg" /* POSTGRES */) {
76037
- return q2[fnc](key, "ilike", `${value}%`);
76038
- } else {
76039
- const rawFnc = `${fnc}Raw`;
76040
- return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
76342
+ iterate(filters.string, "string" /* STRING */, (q2, key, value) => {
76343
+ if (shouldOr) {
76344
+ q2 = q2.or;
76345
+ }
76346
+ if (this.client === "oracledb" /* ORACLE */ || this.client === "sqlite3" /* SQL_LITE */) {
76347
+ return q2.whereRaw(`LOWER(??) LIKE ?`, [
76348
+ this.rawQuotedIdentifier(key),
76041
76349
  `${value.toLowerCase()}%`
76042
76350
  ]);
76351
+ } else {
76352
+ return q2.whereILike(key, `${value}%`);
76043
76353
  }
76044
76354
  });
76045
76355
  }
76046
76356
  if (filters.fuzzy) {
76047
- iterate(filters.fuzzy, like);
76357
+ iterate(filters.fuzzy, "fuzzy" /* FUZZY */, like);
76048
76358
  }
76049
76359
  if (filters.range) {
76050
- iterate(filters.range, (q2, key, value) => {
76360
+ iterate(filters.range, "range" /* RANGE */, (q2, key, value) => {
76051
76361
  const isEmptyObject = (val) => {
76052
76362
  return val && Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
76053
76363
  };
@@ -76059,92 +76369,94 @@ var InternalBuilder = class {
76059
76369
  }
76060
76370
  const lowValid = isValidFilter(value.low), highValid = isValidFilter(value.high);
76061
76371
  const schema = this.getFieldSchema(key);
76372
+ let rawKey = key;
76373
+ let high = value.high;
76374
+ let low = value.low;
76062
76375
  if (this.client === "oracledb" /* ORACLE */) {
76063
- key = this.knex.raw(this.convertClobs(key));
76376
+ rawKey = this.convertClobs(key);
76377
+ } else if (this.client === "sqlite3" /* SQL_LITE */ && schema?.type === "bigint" /* BIGINT */) {
76378
+ rawKey = this.knex.raw("CAST(?? AS INTEGER)", [
76379
+ this.rawQuotedIdentifier(key)
76380
+ ]);
76381
+ high = this.knex.raw("CAST(? AS INTEGER)", [value.high]);
76382
+ low = this.knex.raw("CAST(? AS INTEGER)", [value.low]);
76383
+ }
76384
+ if (shouldOr) {
76385
+ q2 = q2.or;
76064
76386
  }
76065
76387
  if (lowValid && highValid) {
76066
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76067
- return q2.whereRaw(
76068
- `CAST(${key} AS INTEGER) BETWEEN CAST(? AS INTEGER) AND CAST(? AS INTEGER)`,
76069
- [value.low, value.high]
76070
- );
76071
- } else {
76072
- const fnc = allOr ? "orWhereBetween" : "whereBetween";
76073
- return q2[fnc](key, [value.low, value.high]);
76074
- }
76388
+ return q2.whereBetween(rawKey, [low, high]);
76075
76389
  } else if (lowValid) {
76076
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76077
- return q2.whereRaw(`CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`, [
76078
- value.low
76079
- ]);
76080
- } else {
76081
- const fnc = allOr ? "orWhere" : "where";
76082
- return q2[fnc](key, ">=", value.low);
76083
- }
76390
+ return q2.where(rawKey, ">=", low);
76084
76391
  } else if (highValid) {
76085
- if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
76086
- return q2.whereRaw(`CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`, [
76087
- value.high
76088
- ]);
76089
- } else {
76090
- const fnc = allOr ? "orWhere" : "where";
76091
- return q2[fnc](key, "<=", value.high);
76092
- }
76392
+ return q2.where(rawKey, "<=", high);
76093
76393
  }
76094
76394
  return q2;
76095
76395
  });
76096
76396
  }
76097
76397
  if (filters.equal) {
76098
- iterate(filters.equal, (q2, key, value) => {
76099
- const fnc = allOr ? "orWhereRaw" : "whereRaw";
76398
+ iterate(filters.equal, "equal" /* EQUAL */, (q2, key, value) => {
76399
+ if (shouldOr) {
76400
+ q2 = q2.or;
76401
+ }
76100
76402
  if (this.client === "mssql" /* MS_SQL */) {
76101
- return q2[fnc](
76102
- `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 1`,
76103
- [value]
76104
- );
76105
- } else if (this.client === "oracledb" /* ORACLE */) {
76106
- const identifier = this.convertClobs(key);
76107
- return q2[fnc](`(${identifier} IS NOT NULL AND ${identifier} = ?)`, [
76403
+ return q2.whereRaw(`CASE WHEN ?? = ? THEN 1 ELSE 0 END = 1`, [
76404
+ this.rawQuotedIdentifier(key),
76108
76405
  value
76109
76406
  ]);
76407
+ } else if (this.client === "oracledb" /* ORACLE */) {
76408
+ const identifier = this.convertClobs(key);
76409
+ return q2.where(
76410
+ (subq) => (
76411
+ // @ts-expect-error knex types are wrong, raw is fine here
76412
+ subq.whereNotNull(identifier).andWhere(identifier, value)
76413
+ )
76414
+ );
76110
76415
  } else {
76111
- return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} = ?, FALSE)`, [
76416
+ return q2.whereRaw(`COALESCE(?? = ?, FALSE)`, [
76417
+ this.rawQuotedIdentifier(key),
76112
76418
  value
76113
76419
  ]);
76114
76420
  }
76115
76421
  });
76116
76422
  }
76117
76423
  if (filters.notEqual) {
76118
- iterate(filters.notEqual, (q2, key, value) => {
76119
- const fnc = allOr ? "orWhereRaw" : "whereRaw";
76424
+ iterate(filters.notEqual, "notEqual" /* NOT_EQUAL */, (q2, key, value) => {
76425
+ if (shouldOr) {
76426
+ q2 = q2.or;
76427
+ }
76120
76428
  if (this.client === "mssql" /* MS_SQL */) {
76121
- return q2[fnc](
76122
- `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 0`,
76123
- [value]
76124
- );
76429
+ return q2.whereRaw(`CASE WHEN ?? = ? THEN 1 ELSE 0 END = 0`, [
76430
+ this.rawQuotedIdentifier(key),
76431
+ value
76432
+ ]);
76125
76433
  } else if (this.client === "oracledb" /* ORACLE */) {
76126
76434
  const identifier = this.convertClobs(key);
76127
- return q2[fnc](
76128
- `(${identifier} IS NOT NULL AND ${identifier} != ?) OR ${identifier} IS NULL`,
76129
- [value]
76130
- );
76435
+ return q2.where(
76436
+ (subq) => subq.not.whereNull(identifier).and.where(identifier, "!=", value)
76437
+ ).or.whereNull(identifier);
76131
76438
  } else {
76132
- return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} != ?, TRUE)`, [
76439
+ return q2.whereRaw(`COALESCE(?? != ?, TRUE)`, [
76440
+ this.rawQuotedIdentifier(key),
76133
76441
  value
76134
76442
  ]);
76135
76443
  }
76136
76444
  });
76137
76445
  }
76138
76446
  if (filters.empty) {
76139
- iterate(filters.empty, (q2, key) => {
76140
- const fnc = allOr ? "orWhereNull" : "whereNull";
76141
- return q2[fnc](key);
76447
+ iterate(filters.empty, "empty" /* EMPTY */, (q2, key) => {
76448
+ if (shouldOr) {
76449
+ q2 = q2.or;
76450
+ }
76451
+ return q2.whereNull(key);
76142
76452
  });
76143
76453
  }
76144
76454
  if (filters.notEmpty) {
76145
- iterate(filters.notEmpty, (q2, key) => {
76146
- const fnc = allOr ? "orWhereNotNull" : "whereNotNull";
76147
- return q2[fnc](key);
76455
+ iterate(filters.notEmpty, "notEmpty" /* NOT_EMPTY */, (q2, key) => {
76456
+ if (shouldOr) {
76457
+ q2 = q2.or;
76458
+ }
76459
+ return q2.whereNotNull(key);
76148
76460
  });
76149
76461
  }
76150
76462
  if (filters.contains) {
@@ -76213,7 +76525,7 @@ var InternalBuilder = class {
76213
76525
  const selectFields = qualifiedFields.map(
76214
76526
  (field) => this.convertClobs(field, { forSelect: true })
76215
76527
  );
76216
- query = query.groupByRaw(groupByFields.join(", ")).select(this.knex.raw(selectFields.join(", ")));
76528
+ query = query.groupBy(groupByFields).select(selectFields);
76217
76529
  } else {
76218
76530
  query = query.groupBy(qualifiedFields).select(qualifiedFields);
76219
76531
  }
@@ -76225,11 +76537,10 @@ var InternalBuilder = class {
76225
76537
  if (this.client === "oracledb" /* ORACLE */) {
76226
76538
  const field = this.convertClobs(`${tableName}.${aggregation.field}`);
76227
76539
  query = query.select(
76228
- this.knex.raw(
76229
- `COUNT(DISTINCT ${field}) as ${this.quotedIdentifier(
76230
- aggregation.name
76231
- )}`
76232
- )
76540
+ this.knex.raw(`COUNT(DISTINCT ??) as ??`, [
76541
+ field,
76542
+ aggregation.name
76543
+ ])
76233
76544
  );
76234
76545
  } else {
76235
76546
  query = query.countDistinct(
@@ -76284,9 +76595,11 @@ var InternalBuilder = class {
76284
76595
  } else {
76285
76596
  let composite = `${aliased}.${key}`;
76286
76597
  if (this.client === "oracledb" /* ORACLE */) {
76287
- query = query.orderByRaw(
76288
- `${this.convertClobs(composite)} ${direction} nulls ${nulls}`
76289
- );
76598
+ query = query.orderByRaw(`?? ?? nulls ??`, [
76599
+ this.convertClobs(composite),
76600
+ this.knex.raw(direction),
76601
+ this.knex.raw(nulls)
76602
+ ]);
76290
76603
  } else {
76291
76604
  query = query.orderBy(composite, direction, nulls);
76292
76605
  }
@@ -76308,17 +76621,18 @@ var InternalBuilder = class {
76308
76621
  }
76309
76622
  buildJsonField(field) {
76310
76623
  const parts = field.split(".");
76311
- let tableField, unaliased;
76624
+ let unaliased;
76625
+ let tableField;
76312
76626
  if (parts.length > 1) {
76313
76627
  const alias = parts.shift();
76314
76628
  unaliased = parts.join(".");
76315
- tableField = `${this.quote(alias)}.${this.quote(unaliased)}`;
76629
+ tableField = `${alias}.${unaliased}`;
76316
76630
  } else {
76317
76631
  unaliased = parts.join(".");
76318
- tableField = this.quote(unaliased);
76632
+ tableField = unaliased;
76319
76633
  }
76320
76634
  const separator = this.client === "oracledb" /* ORACLE */ ? " VALUE " : ",";
76321
- return `'${unaliased}'${separator}${tableField}`;
76635
+ return this.knex.raw(`?${separator}??`, [unaliased, this.rawQuotedIdentifier(tableField)]).toString();
76322
76636
  }
76323
76637
  maxFunctionParameters() {
76324
76638
  switch (this.client) {
@@ -76382,11 +76696,11 @@ var InternalBuilder = class {
76382
76696
  subQuery = subQuery.where(
76383
76697
  correlatedTo,
76384
76698
  "=",
76385
- knex3.raw(this.quotedIdentifier(correlatedFrom))
76699
+ this.rawQuotedIdentifier(correlatedFrom)
76386
76700
  );
76387
76701
  const standardWrap = (select) => {
76388
76702
  subQuery = subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit());
76389
- return knex3.select(knex3.raw(select)).from({
76703
+ return knex3.select(select).from({
76390
76704
  [toAlias]: subQuery
76391
76705
  });
76392
76706
  };
@@ -76395,12 +76709,12 @@ var InternalBuilder = class {
76395
76709
  case "sqlite3" /* SQL_LITE */:
76396
76710
  subQuery = this.addJoinFieldCheck(subQuery, relationship);
76397
76711
  wrapperQuery = standardWrap(
76398
- `json_group_array(json_object(${fieldList}))`
76712
+ this.knex.raw(`json_group_array(json_object(${fieldList}))`)
76399
76713
  );
76400
76714
  break;
76401
76715
  case "pg" /* POSTGRES */:
76402
76716
  wrapperQuery = standardWrap(
76403
- `json_agg(json_build_object(${fieldList}))`
76717
+ this.knex.raw(`json_agg(json_build_object(${fieldList}))`)
76404
76718
  );
76405
76719
  break;
76406
76720
  case "mariadb" /* MARIADB */:
@@ -76413,16 +76727,19 @@ var InternalBuilder = class {
76413
76727
  case "mysql2" /* MY_SQL */:
76414
76728
  case "oracledb" /* ORACLE */:
76415
76729
  wrapperQuery = standardWrap(
76416
- `json_arrayagg(json_object(${fieldList}))`
76730
+ this.knex.raw(`json_arrayagg(json_object(${fieldList}))`)
76417
76731
  );
76418
76732
  break;
76419
- case "mssql" /* MS_SQL */:
76733
+ case "mssql" /* MS_SQL */: {
76734
+ const comparatorQuery = knex3.select(`${fromAlias}.*`).from({
76735
+ [fromAlias]: subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit())
76736
+ });
76420
76737
  wrapperQuery = knex3.raw(
76421
- `(SELECT ${this.quote(toAlias)} = (${knex3.select(`${fromAlias}.*`).from({
76422
- [fromAlias]: subQuery.select(`${toAlias}.*`).limit(getRelationshipLimit())
76423
- })} FOR JSON PATH))`
76738
+ `(SELECT ?? = (${comparatorQuery} FOR JSON PATH))`,
76739
+ [this.rawQuotedIdentifier(toAlias)]
76424
76740
  );
76425
76741
  break;
76742
+ }
76426
76743
  default:
76427
76744
  throw new Error(`JSON relationships not implement for ${sqlClient}`);
76428
76745
  }