@budibase/backend-core 2.31.8 → 2.32.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/index.js +420 -186
  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 +2 -2
  6. package/dist/plugins.js.meta.json +1 -1
  7. package/dist/src/cache/user.d.ts +7 -1
  8. package/dist/src/cache/user.js +4 -3
  9. package/dist/src/cache/user.js.map +1 -1
  10. package/dist/src/environment.d.ts +1 -0
  11. package/dist/src/environment.js +1 -1
  12. package/dist/src/environment.js.map +1 -1
  13. package/dist/src/events/index.d.ts +1 -0
  14. package/dist/src/events/index.js +3 -1
  15. package/dist/src/events/index.js.map +1 -1
  16. package/dist/src/events/publishers/ai.d.ts +7 -0
  17. package/dist/src/events/publishers/ai.js +30 -0
  18. package/dist/src/events/publishers/ai.js.map +1 -0
  19. package/dist/src/events/publishers/index.d.ts +1 -0
  20. package/dist/src/events/publishers/index.js +3 -1
  21. package/dist/src/events/publishers/index.js.map +1 -1
  22. package/dist/src/features/index.d.ts +2 -0
  23. package/dist/src/features/index.js +2 -0
  24. package/dist/src/features/index.js.map +1 -1
  25. package/dist/src/middleware/authenticated.js +16 -3
  26. package/dist/src/middleware/authenticated.js.map +1 -1
  27. package/dist/src/sql/sql.js +333 -161
  28. package/dist/src/sql/sql.js.map +1 -1
  29. package/dist/src/sql/utils.d.ts +2 -1
  30. package/dist/src/sql/utils.js +14 -0
  31. package/dist/src/sql/utils.js.map +1 -1
  32. package/dist/tests/core/utilities/structures/licenses.js +10 -0
  33. package/dist/tests/core/utilities/structures/licenses.js.map +1 -1
  34. package/dist/tests/core/utilities/structures/quotas.js +4 -0
  35. package/dist/tests/core/utilities/structures/quotas.js.map +1 -1
  36. package/package.json +4 -4
  37. package/src/cache/user.ts +17 -6
  38. package/src/environment.ts +1 -0
  39. package/src/events/index.ts +1 -0
  40. package/src/events/publishers/ai.ts +21 -0
  41. package/src/events/publishers/index.ts +1 -0
  42. package/src/features/index.ts +2 -0
  43. package/src/middleware/authenticated.ts +25 -8
  44. package/src/sql/sql.ts +460 -224
  45. package/src/sql/utils.ts +29 -1
  46. package/tests/core/utilities/structures/licenses.ts +10 -0
  47. package/tests/core/utilities/structures/quotas.ts +4 -0
package/dist/index.js CHANGED
@@ -54288,6 +54288,9 @@ var AuditedEventFriendlyName = {
54288
54288
  // EMAIL
54289
54289
  ["email:smtp:created" /* EMAIL_SMTP_CREATED */]: `Email configuration created`,
54290
54290
  ["email:smtp:updated" /* EMAIL_SMTP_UPDATED */]: `Email configuration updated`,
54291
+ // AI
54292
+ ["ai:config:created" /* AI_CONFIG_CREATED */]: `AI configuration created`,
54293
+ ["ai:config:updated" /* AI_CONFIG_UPDATED */]: `AI configuration updated`,
54291
54294
  // AUTH
54292
54295
  ["auth:sso:created" /* AUTH_SSO_CREATED */]: `SSO configuration created`,
54293
54296
  ["auth:sso:updated" /* AUTH_SSO_UPDATED */]: `SSO configuration updated`,
@@ -55065,6 +55068,12 @@ function decodeNonAscii(str) {
55065
55068
  // ../shared-core/src/filters.ts
55066
55069
  var import_lodash = require("lodash");
55067
55070
  var HBS_REGEX = /{{([^{].*?)}}/g;
55071
+ var LOGICAL_OPERATORS = Object.values(LogicalOperator);
55072
+ var SEARCH_OPERATORS = [
55073
+ ...Object.values(BasicOperator),
55074
+ ...Object.values(ArrayOperator),
55075
+ ...Object.values(RangeOperator)
55076
+ ];
55068
55077
  var getValidOperatorsForType = (fieldType, field, datasource2) => {
55069
55078
  const Op = OperatorOptions;
55070
55079
  const stringOps = [
@@ -55125,7 +55134,7 @@ var NoEmptyFilterStrings = [
55125
55134
  OperatorOptions.In.value
55126
55135
  ];
55127
55136
  function recurseLogicalOperators(filters, fn) {
55128
- for (const logical of Object.values(LogicalOperator)) {
55137
+ for (const logical of LOGICAL_OPERATORS) {
55129
55138
  if (filters[logical]) {
55130
55139
  filters[logical].conditions = filters[logical].conditions.map(
55131
55140
  (condition) => fn(condition)
@@ -55136,7 +55145,7 @@ function recurseLogicalOperators(filters, fn) {
55136
55145
  }
55137
55146
  function recurseSearchFilters(filters, processFn) {
55138
55147
  filters = processFn(filters);
55139
- for (const logical of Object.values(LogicalOperator)) {
55148
+ for (const logical of LOGICAL_OPERATORS) {
55140
55149
  if (filters[logical]) {
55141
55150
  filters[logical].conditions = filters[logical].conditions.map(
55142
55151
  (condition) => recurseSearchFilters(condition, processFn)
@@ -55353,7 +55362,7 @@ function fixupFilterArrays(filters) {
55353
55362
  recurseLogicalOperators(filters, fixupFilterArrays);
55354
55363
  return filters;
55355
55364
  }
55356
- var search = (docs, query) => {
55365
+ function search(docs, query) {
55357
55366
  let result = runQuery(docs, query.query);
55358
55367
  if (query.sort) {
55359
55368
  result = sort(result, query.sort, query.sortOrder || "ascending" /* ASCENDING */);
@@ -55367,8 +55376,8 @@ var search = (docs, query) => {
55367
55376
  response.totalRows = totalRows;
55368
55377
  }
55369
55378
  return response;
55370
- };
55371
- var runQuery = (docs, query, findInDoc = deepGet) => {
55379
+ }
55380
+ function runQuery(docs, query) {
55372
55381
  if (!docs || !Array.isArray(docs)) {
55373
55382
  return [];
55374
55383
  }
@@ -55382,7 +55391,7 @@ var runQuery = (docs, query, findInDoc = deepGet) => {
55382
55391
  }
55383
55392
  const match = (type, test) => (doc) => {
55384
55393
  for (const [key, testValue] of Object.entries(query[type] || {})) {
55385
- const valueToCheck = isLogicalSearchOperator(type) ? doc : findInDoc(doc, removeKeyNumbering(key));
55394
+ const valueToCheck = isLogicalSearchOperator(type) ? doc : deepGet(doc, removeKeyNumbering(key));
55386
55395
  const result = test(valueToCheck, testValue);
55387
55396
  if (query.allOr && result) {
55388
55397
  return true;
@@ -55599,15 +55608,17 @@ var runQuery = (docs, query, findInDoc = deepGet) => {
55599
55608
  ).map(([key]) => {
55600
55609
  return filterFunctions[key]?.(doc) ?? false;
55601
55610
  });
55602
- if (query.allOr) {
55611
+ if (!hasFilters(query)) {
55612
+ return true;
55613
+ } else if (query.allOr) {
55603
55614
  return results.some((result) => result === true);
55604
55615
  } else {
55605
55616
  return results.every((result) => result === true);
55606
55617
  }
55607
55618
  };
55608
55619
  return docs.filter(docMatch);
55609
- };
55610
- var sort = (docs, sort2, sortOrder, sortType = "string" /* STRING */) => {
55620
+ }
55621
+ function sort(docs, sort2, sortOrder, sortType = "string" /* STRING */) {
55611
55622
  if (!sort2 || !sortOrder || !sortType) {
55612
55623
  return docs;
55613
55624
  }
@@ -55629,28 +55640,45 @@ var sort = (docs, sort2, sortOrder, sortType = "string" /* STRING */) => {
55629
55640
  }
55630
55641
  return result;
55631
55642
  });
55632
- };
55633
- var limit = (docs, limit2) => {
55643
+ }
55644
+ function limit(docs, limit2) {
55634
55645
  const numLimit = parseFloat(limit2);
55635
55646
  if (isNaN(numLimit)) {
55636
55647
  return docs;
55637
55648
  }
55638
55649
  return docs.slice(0, numLimit);
55639
- };
55650
+ }
55640
55651
  var hasFilters = (query) => {
55641
55652
  if (!query) {
55642
55653
  return false;
55643
55654
  }
55644
- const skipped = ["allOr", "onEmptyFilter"];
55645
- for (let [key, value] of Object.entries(query)) {
55646
- if (skipped.includes(key) || typeof value !== "object") {
55647
- continue;
55655
+ const check = (filters) => {
55656
+ for (const logical of LOGICAL_OPERATORS) {
55657
+ if (filters[logical]) {
55658
+ for (const condition of filters[logical]?.conditions || []) {
55659
+ const result = check(condition);
55660
+ if (result) {
55661
+ return result;
55662
+ }
55663
+ }
55664
+ }
55648
55665
  }
55649
- if (Object.keys(value || {}).length !== 0) {
55650
- return true;
55666
+ for (const search2 of SEARCH_OPERATORS) {
55667
+ const searchValue = filters[search2];
55668
+ if (!searchValue || typeof searchValue !== "object") {
55669
+ continue;
55670
+ }
55671
+ const filtered2 = Object.entries(searchValue).filter((entry2) => {
55672
+ const valueDefined = entry2[1] !== void 0 || entry2[1] !== null || entry2[1] !== "";
55673
+ return search2 === "notEmpty" /* NOT_EMPTY */ || valueDefined;
55674
+ });
55675
+ if (filtered2.length !== 0) {
55676
+ return true;
55677
+ }
55651
55678
  }
55652
- }
55653
- return false;
55679
+ return false;
55680
+ };
55681
+ return check(query);
55654
55682
  };
55655
55683
 
55656
55684
  // ../shared-core/src/utils.ts
@@ -56297,6 +56325,7 @@ var environment = {
56297
56325
  // Couch/search
56298
56326
  SQL_LOGGING_ENABLE: process.env.SQL_LOGGING_ENABLE,
56299
56327
  SQL_MAX_ROWS: process.env.SQL_MAX_ROWS,
56328
+ SQL_MAX_RELATED_ROWS: process.env.MAX_RELATED_ROWS,
56300
56329
  // smtp
56301
56330
  SMTP_FALLBACK_ENABLED: process.env.SMTP_FALLBACK_ENABLED,
56302
56331
  SMTP_USER: process.env.SMTP_USER,
@@ -56788,7 +56817,8 @@ __export(utils_exports3, {
56788
56817
  isValidFilter: () => isValidFilter,
56789
56818
  isValidISODateString: () => isValidISODateString,
56790
56819
  isValidTime: () => isValidTime,
56791
- sqlLog: () => sqlLog
56820
+ sqlLog: () => sqlLog,
56821
+ validateManyToMany: () => validateManyToMany
56792
56822
  });
56793
56823
 
56794
56824
  // src/db/index.ts
@@ -59762,6 +59792,15 @@ function sqlLog(client, query, values2) {
59762
59792
  }
59763
59793
  console.log(string);
59764
59794
  }
59795
+ function isValidManyToManyRelationship(relationship) {
59796
+ return !!relationship.through && !!relationship.fromPrimary && !!relationship.from && !!relationship.toPrimary && !!relationship.to;
59797
+ }
59798
+ function validateManyToMany(relationship) {
59799
+ if (isValidManyToManyRelationship(relationship)) {
59800
+ return relationship;
59801
+ }
59802
+ return void 0;
59803
+ }
59765
59804
 
59766
59805
  // src/features/index.ts
59767
59806
  var features_exports = {};
@@ -59953,7 +59992,9 @@ var FlagSet = class {
59953
59992
  };
59954
59993
  var flags = new FlagSet({
59955
59994
  DEFAULT_VALUES: Flag.boolean(environment_default.isDev()),
59995
+ AUTOMATION_BRANCHING: Flag.boolean(environment_default.isDev()),
59956
59996
  SQS: Flag.boolean(environment_default.isDev()),
59997
+ ["AI_CUSTOM_CONFIGS" /* AI_CUSTOM_CONFIGS */]: Flag.boolean(environment_default.isDev()),
59957
59998
  ["ENRICHED_RELATIONSHIPS" /* ENRICHED_RELATIONSHIPS */]: Flag.boolean(false)
59958
59999
  });
59959
60000
 
@@ -62307,6 +62348,7 @@ async function getAccountHolderFromUserIds(userIds) {
62307
62348
  var events_exports = {};
62308
62349
  __export(events_exports, {
62309
62350
  account: () => account_default,
62351
+ ai: () => ai_default,
62310
62352
  analytics: () => analytics_exports,
62311
62353
  app: () => app_default,
62312
62354
  auditLog: () => auditLog_default,
@@ -62327,6 +62369,7 @@ __export(events_exports, {
62327
62369
  org: () => org_default,
62328
62370
  plugin: () => plugin_default,
62329
62371
  processors: () => processors_exports,
62372
+ publishEvent: () => publishEvent,
62330
62373
  query: () => query_default,
62331
62374
  role: () => role_default,
62332
62375
  rows: () => rows_default,
@@ -63891,6 +63934,20 @@ var email_default = {
63891
63934
  SMTPUpdated
63892
63935
  };
63893
63936
 
63937
+ // src/events/publishers/ai.ts
63938
+ async function AIConfigCreated(timestamp) {
63939
+ const properties = {};
63940
+ await publishEvent("ai:config:created" /* AI_CONFIG_CREATED */, properties, timestamp);
63941
+ }
63942
+ async function AIConfigUpdated() {
63943
+ const properties = {};
63944
+ await publishEvent("ai:config:updated" /* AI_CONFIG_UPDATED */, properties);
63945
+ }
63946
+ var ai_default = {
63947
+ AIConfigCreated,
63948
+ AIConfigUpdated
63949
+ };
63950
+
63894
63951
  // src/events/publishers/license.ts
63895
63952
  async function planChanged(account, opts) {
63896
63953
  const properties = {
@@ -65677,7 +65734,12 @@ async function populateUsersFromDB(userIds) {
65677
65734
  }
65678
65735
  return { users };
65679
65736
  }
65680
- async function getUser(userId, tenantId, populateUser) {
65737
+ async function getUser({
65738
+ userId,
65739
+ tenantId,
65740
+ email,
65741
+ populateUser
65742
+ }) {
65681
65743
  if (!populateUser) {
65682
65744
  populateUser = populateFromDB2;
65683
65745
  }
@@ -65691,7 +65753,7 @@ async function getUser(userId, tenantId, populateUser) {
65691
65753
  const client = await getUserClient();
65692
65754
  let user = await client.get(userId);
65693
65755
  if (!user) {
65694
- user = await populateUser(userId, tenantId);
65756
+ user = await populateUser(userId, tenantId, email);
65695
65757
  await client.store(userId, user, EXPIRY_SECONDS3);
65696
65758
  }
65697
65759
  if (user && !user.tenantId && tenantId) {
@@ -66922,7 +66984,11 @@ async function checkApiKey(apiKey, populateUser) {
66922
66984
  if (userId) {
66923
66985
  return {
66924
66986
  valid: true,
66925
- user: await getUser(userId, tenantId, populateUser)
66987
+ user: await getUser({
66988
+ userId,
66989
+ tenantId,
66990
+ populateUser
66991
+ })
66926
66992
  };
66927
66993
  } else {
66928
66994
  throw new InvalidAPIKeyError();
@@ -66956,13 +67022,18 @@ function authenticated_default(noAuthPatterns = [], opts = {
66956
67022
  try {
66957
67023
  session = await getSession(userId, sessionId);
66958
67024
  if (opts && opts.populateUser) {
66959
- user = await getUser(
67025
+ user = await getUser({
66960
67026
  userId,
66961
- session.tenantId,
66962
- opts.populateUser(ctx)
66963
- );
67027
+ tenantId: session.tenantId,
67028
+ email: session.email,
67029
+ populateUser: opts.populateUser(ctx)
67030
+ });
66964
67031
  } else {
66965
- user = await getUser(userId, session.tenantId);
67032
+ user = await getUser({
67033
+ userId,
67034
+ tenantId: session.tenantId,
67035
+ email: session.email
67036
+ });
66966
67037
  }
66967
67038
  user.csrfToken = session.csrfToken;
66968
67039
  if (session?.lastAccessedAt < timeMinusOneMinute()) {
@@ -67953,10 +68024,15 @@ var sqlTable_default = SqlTableQueryBuilder;
67953
68024
 
67954
68025
  // src/sql/sql.ts
67955
68026
  var import_lodash3 = require("lodash");
68027
+ var MAX_SQS_RELATIONSHIP_FIELDS = 63;
67956
68028
  function getBaseLimit() {
67957
68029
  const envLimit = environment_default.SQL_MAX_ROWS ? parseInt(environment_default.SQL_MAX_ROWS) : null;
67958
68030
  return envLimit || 5e3;
67959
68031
  }
68032
+ function getRelationshipLimit() {
68033
+ const envLimit = environment_default.SQL_MAX_RELATED_ROWS ? parseInt(environment_default.SQL_MAX_RELATED_ROWS) : null;
68034
+ return envLimit || 500;
68035
+ }
67960
68036
  function getTableName(table) {
67961
68037
  if (table?.sourceType === "internal" /* INTERNAL */ || table?.sourceId === INTERNAL_TABLE_SOURCE_ID) {
67962
68038
  return table?._id;
@@ -67981,6 +68057,15 @@ function convertBooleans(query) {
67981
68057
  }
67982
68058
  var InternalBuilder = class {
67983
68059
  constructor(client, knex3, query) {
68060
+ // states the various situations in which we need a full mapped select statement
68061
+ this.SPECIAL_SELECT_CASES = {
68062
+ POSTGRES_MONEY: (field) => {
68063
+ return this.client === "pg" /* POSTGRES */ && field?.externalType?.includes("money");
68064
+ },
68065
+ MSSQL_DATES: (field) => {
68066
+ return this.client === "mssql" /* MS_SQL */ && field?.type === "datetime" /* DATETIME */ && field.timeOnly;
68067
+ }
68068
+ };
67984
68069
  this.client = client;
67985
68070
  this.query = query;
67986
68071
  this.knex = knex3;
@@ -68015,48 +68100,50 @@ var InternalBuilder = class {
68015
68100
  quotedIdentifier(key) {
68016
68101
  return key.split(".").map((part) => this.quote(part)).join(".");
68017
68102
  }
68103
+ isFullSelectStatementRequired() {
68104
+ const { meta } = this.query;
68105
+ for (let column of Object.values(meta.table.schema)) {
68106
+ if (this.SPECIAL_SELECT_CASES.POSTGRES_MONEY(column)) {
68107
+ return true;
68108
+ } else if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(column)) {
68109
+ return true;
68110
+ }
68111
+ }
68112
+ return false;
68113
+ }
68018
68114
  generateSelectStatement() {
68019
- const { resource, meta } = this.query;
68115
+ const { meta, endpoint, resource, tableAliases } = this.query;
68020
68116
  if (!resource || !resource.fields || resource.fields.length === 0) {
68021
68117
  return "*";
68022
68118
  }
68119
+ const alias = tableAliases?.[endpoint.entityId] ? tableAliases?.[endpoint.entityId] : endpoint.entityId;
68023
68120
  const schema = meta.table.schema;
68121
+ if (!this.isFullSelectStatementRequired()) {
68122
+ return [this.knex.raw(`${this.quote(alias)}.*`)];
68123
+ }
68024
68124
  return resource.fields.map((field) => {
68025
68125
  const parts = field.split(/\./g);
68026
68126
  let table = void 0;
68027
- let column = void 0;
68028
- if (parts.length === 1) {
68029
- column = parts[0];
68030
- }
68031
- if (parts.length === 2) {
68032
- table = parts[0];
68033
- column = parts[1];
68034
- }
68035
- if (parts.length > 2) {
68127
+ let column = parts[0];
68128
+ if (parts.length > 1) {
68036
68129
  table = parts[0];
68037
68130
  column = parts.slice(1).join(".");
68038
68131
  }
68039
- if (!column) {
68040
- throw new Error(`Invalid field name: ${field}`);
68041
- }
68132
+ return { table, column, field };
68133
+ }).filter(({ table }) => !table || table === alias).map(({ table, column, field }) => {
68042
68134
  const columnSchema = schema[column];
68043
- if (this.client === "pg" /* POSTGRES */ && columnSchema?.externalType?.includes("money")) {
68135
+ if (this.SPECIAL_SELECT_CASES.POSTGRES_MONEY(columnSchema)) {
68044
68136
  return this.knex.raw(
68045
68137
  `${this.quotedIdentifier(
68046
68138
  [table, column].join(".")
68047
68139
  )}::money::numeric as ${this.quote(field)}`
68048
68140
  );
68049
68141
  }
68050
- if (this.client === "mssql" /* MS_SQL */ && columnSchema?.type === "datetime" /* DATETIME */ && columnSchema.timeOnly) {
68142
+ if (this.SPECIAL_SELECT_CASES.MSSQL_DATES(columnSchema)) {
68051
68143
  return this.knex.raw(`CONVERT(varchar, ${field}, 108) as "${field}"`);
68052
68144
  }
68053
- if (table) {
68054
- return this.knex.raw(
68055
- `${this.quote(table)}.${this.quote(column)} as ${this.quote(field)}`
68056
- );
68057
- } else {
68058
- return this.knex.raw(`${this.quote(field)} as ${this.quote(field)}`);
68059
- }
68145
+ const quoted = table ? `${this.quote(table)}.${this.quote(column)}` : this.quote(field);
68146
+ return this.knex.raw(quoted);
68060
68147
  });
68061
68148
  }
68062
68149
  // OracleDB can't use character-large-objects (CLOBs) in WHERE clauses,
@@ -68167,28 +68254,94 @@ var InternalBuilder = class {
68167
68254
  }
68168
68255
  return filters;
68169
68256
  }
68257
+ addJoinFieldCheck(query, relationship) {
68258
+ const document = relationship.from?.split(".")[0] || "";
68259
+ return query.andWhere(`${document}.fieldName`, "=", relationship.column);
68260
+ }
68261
+ addRelationshipForFilter(query, filterKey, whereCb) {
68262
+ const mainKnex = this.knex;
68263
+ const { relationships, endpoint, tableAliases: aliases } = this.query;
68264
+ const tableName = endpoint.entityId;
68265
+ const fromAlias = aliases?.[tableName] || tableName;
68266
+ const matches2 = (possibleTable) => filterKey.startsWith(`${possibleTable}`);
68267
+ if (!relationships) {
68268
+ return query;
68269
+ }
68270
+ for (const relationship of relationships) {
68271
+ const relatedTableName = relationship.tableName;
68272
+ const toAlias = aliases?.[relatedTableName] || relatedTableName;
68273
+ if ((matches2(relatedTableName) || matches2(toAlias)) && relationship.to && relationship.tableName) {
68274
+ let subQuery = mainKnex.select(mainKnex.raw(1)).from({ [toAlias]: relatedTableName });
68275
+ const manyToMany = validateManyToMany(relationship);
68276
+ if (manyToMany) {
68277
+ const throughAlias = aliases?.[manyToMany.through] || relationship.through;
68278
+ let throughTable = this.tableNameWithSchema(manyToMany.through, {
68279
+ alias: throughAlias,
68280
+ schema: endpoint.schema
68281
+ });
68282
+ subQuery = subQuery.innerJoin(throughTable, function() {
68283
+ this.on(
68284
+ `${toAlias}.${manyToMany.toPrimary}`,
68285
+ "=",
68286
+ `${throughAlias}.${manyToMany.to}`
68287
+ );
68288
+ }).where(
68289
+ `${throughAlias}.${manyToMany.from}`,
68290
+ "=",
68291
+ mainKnex.raw(
68292
+ this.quotedIdentifier(`${fromAlias}.${manyToMany.fromPrimary}`)
68293
+ )
68294
+ );
68295
+ if (this.client === "sqlite3" /* SQL_LITE */) {
68296
+ subQuery = this.addJoinFieldCheck(subQuery, manyToMany);
68297
+ }
68298
+ } else {
68299
+ subQuery = subQuery.where(
68300
+ `${toAlias}.${relationship.to}`,
68301
+ "=",
68302
+ mainKnex.raw(
68303
+ this.quotedIdentifier(`${fromAlias}.${relationship.from}`)
68304
+ )
68305
+ );
68306
+ }
68307
+ query = query.whereExists(whereCb(subQuery));
68308
+ break;
68309
+ }
68310
+ }
68311
+ return query;
68312
+ }
68170
68313
  // right now we only do filters on the specific table being queried
68171
68314
  addFilters(query, filters, opts) {
68172
68315
  if (!filters) {
68173
68316
  return query;
68174
68317
  }
68318
+ const builder = this;
68175
68319
  filters = this.parseFilters({ ...filters });
68176
68320
  const aliases = this.query.tableAliases;
68177
68321
  const allOr = filters.allOr;
68178
- const tableName = this.client === "sqlite3" /* SQL_LITE */ ? this.table._id : this.table.name;
68322
+ const isSqlite = this.client === "sqlite3" /* SQL_LITE */;
68323
+ const tableName = isSqlite ? this.table._id : this.table.name;
68179
68324
  function getTableAlias(name) {
68180
68325
  const alias = aliases?.[name];
68181
68326
  return alias || name;
68182
68327
  }
68183
68328
  function iterate(structure, fn, complexKeyFn) {
68329
+ const handleRelationship = (q2, key, value) => {
68330
+ const [filterTableName, ...otherProperties] = key.split(".");
68331
+ const property = otherProperties.join(".");
68332
+ const alias = getTableAlias(filterTableName);
68333
+ return fn(q2, alias ? `${alias}.${property}` : property, value);
68334
+ };
68184
68335
  for (const key in structure) {
68185
68336
  const value = structure[key];
68186
68337
  const updatedKey = removeKeyNumbering2(key);
68187
68338
  const isRelationshipField = updatedKey.includes(".");
68339
+ const shouldProcessRelationship = opts?.relationship && isRelationshipField;
68188
68340
  let castedTypeValue;
68189
68341
  if (key === "_complexIdOperator" /* COMPLEX_ID_OPERATOR */ && (castedTypeValue = structure[key]) && complexKeyFn) {
68190
68342
  const alias = getTableAlias(tableName);
68191
- complexKeyFn(
68343
+ query = complexKeyFn(
68344
+ query,
68192
68345
  castedTypeValue.id.map(
68193
68346
  (x) => alias ? `${alias}.${x}` : x
68194
68347
  ),
@@ -68196,23 +68349,26 @@ var InternalBuilder = class {
68196
68349
  );
68197
68350
  } else if (!isRelationshipField) {
68198
68351
  const alias = getTableAlias(tableName);
68199
- fn(alias ? `${alias}.${updatedKey}` : updatedKey, value);
68200
- }
68201
- if (opts?.relationship && isRelationshipField) {
68202
- const [filterTableName, property] = updatedKey.split(".");
68203
- const alias = getTableAlias(filterTableName);
68204
- fn(alias ? `${alias}.${property}` : property, value);
68352
+ query = fn(
68353
+ query,
68354
+ alias ? `${alias}.${updatedKey}` : updatedKey,
68355
+ value
68356
+ );
68357
+ } else if (shouldProcessRelationship) {
68358
+ query = builder.addRelationshipForFilter(query, updatedKey, (q2) => {
68359
+ return handleRelationship(q2, updatedKey, value);
68360
+ });
68205
68361
  }
68206
68362
  }
68207
68363
  }
68208
- const like = (key, value) => {
68364
+ const like = (q2, key, value) => {
68209
68365
  const fuzzyOr = filters?.fuzzyOr;
68210
68366
  const fnc = fuzzyOr || allOr ? "orWhere" : "where";
68211
68367
  if (this.client === "pg" /* POSTGRES */) {
68212
- query = query[fnc](key, "ilike", `%${value}%`);
68368
+ return q2[fnc](key, "ilike", `%${value}%`);
68213
68369
  } else {
68214
68370
  const rawFnc = `${fnc}Raw`;
68215
- query = query[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
68371
+ return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
68216
68372
  `%${value.toLowerCase()}%`
68217
68373
  ]);
68218
68374
  }
@@ -68229,13 +68385,13 @@ var InternalBuilder = class {
68229
68385
  return `[${value.join(",")}]`;
68230
68386
  }
68231
68387
  if (this.client === "pg" /* POSTGRES */) {
68232
- iterate(mode, (key, value) => {
68388
+ iterate(mode, (q2, key, value) => {
68233
68389
  const wrap = any ? "" : "'";
68234
68390
  const op = any ? "\\?| array" : "@>";
68235
68391
  const fieldNames = key.split(/\./g);
68236
68392
  const table = fieldNames[0];
68237
68393
  const col = fieldNames[1];
68238
- query = query[rawFnc](
68394
+ return q2[rawFnc](
68239
68395
  `${not}COALESCE("${table}"."${col}"::jsonb ${op} ${wrap}${stringifyArray(
68240
68396
  value,
68241
68397
  any ? "'" : '"'
@@ -68244,8 +68400,8 @@ var InternalBuilder = class {
68244
68400
  });
68245
68401
  } else if (this.client === "mysql2" /* MY_SQL */) {
68246
68402
  const jsonFnc = any ? "JSON_OVERLAPS" : "JSON_CONTAINS";
68247
- iterate(mode, (key, value) => {
68248
- query = query[rawFnc](
68403
+ iterate(mode, (q2, key, value) => {
68404
+ return q2[rawFnc](
68249
68405
  `${not}COALESCE(${jsonFnc}(${key}, '${stringifyArray(
68250
68406
  value
68251
68407
  )}'), FALSE)`
@@ -68253,7 +68409,7 @@ var InternalBuilder = class {
68253
68409
  });
68254
68410
  } else {
68255
68411
  const andOr = mode === filters?.containsAny ? " OR " : " AND ";
68256
- iterate(mode, (key, value) => {
68412
+ iterate(mode, (q2, key, value) => {
68257
68413
  let statement = "";
68258
68414
  const identifier = this.quotedIdentifier(key);
68259
68415
  for (let i in value) {
@@ -68265,15 +68421,15 @@ var InternalBuilder = class {
68265
68421
  statement += `${statement ? andOr : ""}COALESCE(LOWER(${identifier}), '') LIKE ?`;
68266
68422
  }
68267
68423
  if (statement === "") {
68268
- return;
68424
+ return q2;
68269
68425
  }
68270
68426
  if (not) {
68271
- query = query[rawFnc](
68427
+ return q2[rawFnc](
68272
68428
  `(NOT (${statement}) OR ${identifier} IS NULL)`,
68273
68429
  value
68274
68430
  );
68275
68431
  } else {
68276
- query = query[rawFnc](statement, value);
68432
+ return q2[rawFnc](statement, value);
68277
68433
  }
68278
68434
  });
68279
68435
  }
@@ -68300,35 +68456,35 @@ var InternalBuilder = class {
68300
68456
  const fnc = allOr ? "orWhereIn" : "whereIn";
68301
68457
  iterate(
68302
68458
  filters.oneOf,
68303
- (key, array) => {
68459
+ (q2, key, array) => {
68304
68460
  if (this.client === "oracledb" /* ORACLE */) {
68305
68461
  key = this.convertClobs(key);
68306
68462
  array = Array.isArray(array) ? array : [array];
68307
68463
  const binding = new Array(array.length).fill("?").join(",");
68308
- query = query.whereRaw(`${key} IN (${binding})`, array);
68464
+ return q2.whereRaw(`${key} IN (${binding})`, array);
68309
68465
  } else {
68310
- query = query[fnc](key, Array.isArray(array) ? array : [array]);
68466
+ return q2[fnc](key, Array.isArray(array) ? array : [array]);
68311
68467
  }
68312
68468
  },
68313
- (key, array) => {
68469
+ (q2, key, array) => {
68314
68470
  if (this.client === "oracledb" /* ORACLE */) {
68315
68471
  const keyStr = `(${key.map((k) => this.convertClobs(k)).join(",")})`;
68316
68472
  const binding = `(${array.map((a) => `(${new Array(a.length).fill("?").join(",")})`).join(",")})`;
68317
- query = query.whereRaw(`${keyStr} IN ${binding}`, array.flat());
68473
+ return q2.whereRaw(`${keyStr} IN ${binding}`, array.flat());
68318
68474
  } else {
68319
- query = query[fnc](key, Array.isArray(array) ? array : [array]);
68475
+ return q2[fnc](key, Array.isArray(array) ? array : [array]);
68320
68476
  }
68321
68477
  }
68322
68478
  );
68323
68479
  }
68324
68480
  if (filters.string) {
68325
- iterate(filters.string, (key, value) => {
68481
+ iterate(filters.string, (q2, key, value) => {
68326
68482
  const fnc = allOr ? "orWhere" : "where";
68327
68483
  if (this.client === "pg" /* POSTGRES */) {
68328
- query = query[fnc](key, "ilike", `${value}%`);
68484
+ return q2[fnc](key, "ilike", `${value}%`);
68329
68485
  } else {
68330
68486
  const rawFnc = `${fnc}Raw`;
68331
- query = query[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
68487
+ return q2[rawFnc](`LOWER(${this.quotedIdentifier(key)}) LIKE ?`, [
68332
68488
  `${value.toLowerCase()}%`
68333
68489
  ]);
68334
68490
  }
@@ -68338,7 +68494,7 @@ var InternalBuilder = class {
68338
68494
  iterate(filters.fuzzy, like);
68339
68495
  }
68340
68496
  if (filters.range) {
68341
- iterate(filters.range, (key, value) => {
68497
+ iterate(filters.range, (q2, key, value) => {
68342
68498
  const isEmptyObject = (val) => {
68343
68499
  return val && Object.keys(val).length === 0 && Object.getPrototypeOf(val) === Object.prototype;
68344
68500
  };
@@ -68355,91 +68511,87 @@ var InternalBuilder = class {
68355
68511
  }
68356
68512
  if (lowValid && highValid) {
68357
68513
  if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
68358
- query = query.whereRaw(
68514
+ return q2.whereRaw(
68359
68515
  `CAST(${key} AS INTEGER) BETWEEN CAST(? AS INTEGER) AND CAST(? AS INTEGER)`,
68360
68516
  [value.low, value.high]
68361
68517
  );
68362
68518
  } else {
68363
68519
  const fnc = allOr ? "orWhereBetween" : "whereBetween";
68364
- query = query[fnc](key, [value.low, value.high]);
68520
+ return q2[fnc](key, [value.low, value.high]);
68365
68521
  }
68366
68522
  } else if (lowValid) {
68367
68523
  if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
68368
- query = query.whereRaw(
68369
- `CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`,
68370
- [value.low]
68371
- );
68524
+ return q2.whereRaw(`CAST(${key} AS INTEGER) >= CAST(? AS INTEGER)`, [
68525
+ value.low
68526
+ ]);
68372
68527
  } else {
68373
68528
  const fnc = allOr ? "orWhere" : "where";
68374
- query = query[fnc](key, ">=", value.low);
68529
+ return q2[fnc](key, ">=", value.low);
68375
68530
  }
68376
68531
  } else if (highValid) {
68377
68532
  if (schema?.type === "bigint" /* BIGINT */ && this.client === "sqlite3" /* SQL_LITE */) {
68378
- query = query.whereRaw(
68379
- `CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`,
68380
- [value.high]
68381
- );
68533
+ return q2.whereRaw(`CAST(${key} AS INTEGER) <= CAST(? AS INTEGER)`, [
68534
+ value.high
68535
+ ]);
68382
68536
  } else {
68383
68537
  const fnc = allOr ? "orWhere" : "where";
68384
- query = query[fnc](key, "<=", value.high);
68538
+ return q2[fnc](key, "<=", value.high);
68385
68539
  }
68386
68540
  }
68541
+ return q2;
68387
68542
  });
68388
68543
  }
68389
68544
  if (filters.equal) {
68390
- iterate(filters.equal, (key, value) => {
68545
+ iterate(filters.equal, (q2, key, value) => {
68391
68546
  const fnc = allOr ? "orWhereRaw" : "whereRaw";
68392
68547
  if (this.client === "mssql" /* MS_SQL */) {
68393
- query = query[fnc](
68548
+ return q2[fnc](
68394
68549
  `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 1`,
68395
68550
  [value]
68396
68551
  );
68397
68552
  } else if (this.client === "oracledb" /* ORACLE */) {
68398
68553
  const identifier = this.convertClobs(key);
68399
- query = query[fnc](
68400
- `(${identifier} IS NOT NULL AND ${identifier} = ?)`,
68401
- [value]
68402
- );
68554
+ return q2[fnc](`(${identifier} IS NOT NULL AND ${identifier} = ?)`, [
68555
+ value
68556
+ ]);
68403
68557
  } else {
68404
- query = query[fnc](
68405
- `COALESCE(${this.quotedIdentifier(key)} = ?, FALSE)`,
68406
- [value]
68407
- );
68558
+ return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} = ?, FALSE)`, [
68559
+ value
68560
+ ]);
68408
68561
  }
68409
68562
  });
68410
68563
  }
68411
68564
  if (filters.notEqual) {
68412
- iterate(filters.notEqual, (key, value) => {
68565
+ iterate(filters.notEqual, (q2, key, value) => {
68413
68566
  const fnc = allOr ? "orWhereRaw" : "whereRaw";
68414
68567
  if (this.client === "mssql" /* MS_SQL */) {
68415
- query = query[fnc](
68568
+ return q2[fnc](
68416
68569
  `CASE WHEN ${this.quotedIdentifier(key)} = ? THEN 1 ELSE 0 END = 0`,
68417
68570
  [value]
68418
68571
  );
68419
68572
  } else if (this.client === "oracledb" /* ORACLE */) {
68420
68573
  const identifier = this.convertClobs(key);
68421
- query = query[fnc](
68574
+ return q2[fnc](
68422
68575
  `(${identifier} IS NOT NULL AND ${identifier} != ?) OR ${identifier} IS NULL`,
68423
68576
  [value]
68424
68577
  );
68425
68578
  } else {
68426
- query = query[fnc](
68427
- `COALESCE(${this.quotedIdentifier(key)} != ?, TRUE)`,
68428
- [value]
68429
- );
68579
+ return q2[fnc](`COALESCE(${this.quotedIdentifier(key)} != ?, TRUE)`, [
68580
+ value
68581
+ ]);
68430
68582
  }
68431
68583
  });
68432
68584
  }
68433
68585
  if (filters.empty) {
68434
- iterate(filters.empty, (key) => {
68586
+ iterate(filters.empty, (q2, key) => {
68435
68587
  const fnc = allOr ? "orWhereNull" : "whereNull";
68436
- query = query[fnc](key);
68588
+ return q2[fnc](key);
68437
68589
  });
68438
68590
  }
68439
68591
  if (filters.notEmpty) {
68440
- iterate(filters.notEmpty, (key) => {
68592
+ iterate(filters.notEmpty, (q2, key) => {
68441
68593
  const fnc = allOr ? "orWhereNotNull" : "whereNotNull";
68442
- query = query[fnc](key);
68594
+ return q2[fnc](key);
68443
68595
  });
68444
68596
  }
68445
68597
  if (filters.contains) {
@@ -68507,63 +68659,155 @@ var InternalBuilder = class {
68507
68659
  }
68508
68660
  return withSchema;
68509
68661
  }
68510
- addRelationships(query, fromTable, relationships, schema, aliases) {
68511
- if (!relationships) {
68512
- return query;
68662
+ buildJsonField(field) {
68663
+ const parts = field.split(".");
68664
+ let tableField, unaliased;
68665
+ if (parts.length > 1) {
68666
+ const alias = parts.shift();
68667
+ unaliased = parts.join(".");
68668
+ tableField = `${this.quote(alias)}.${this.quote(unaliased)}`;
68669
+ } else {
68670
+ unaliased = parts.join(".");
68671
+ tableField = this.quote(unaliased);
68513
68672
  }
68514
- const tableSets = {};
68673
+ const separator = this.client === "oracledb" /* ORACLE */ ? " VALUE " : ",";
68674
+ return `'${unaliased}'${separator}${tableField}`;
68675
+ }
68676
+ addJsonRelationships(query, fromTable, relationships) {
68677
+ const sqlClient = this.client;
68678
+ const knex3 = this.knex;
68679
+ const { resource, tableAliases: aliases, endpoint } = this.query;
68680
+ const fields = resource?.fields || [];
68515
68681
  for (let relationship of relationships) {
68516
- const keyObj = {
68517
- toTable: relationship.tableName,
68518
- throughTable: void 0
68519
- };
68520
- if (relationship.through) {
68521
- keyObj.throughTable = relationship.through;
68522
- }
68523
- const key = JSON.stringify(keyObj);
68524
- if (tableSets[key]) {
68525
- tableSets[key].push(relationship);
68526
- } else {
68527
- tableSets[key] = [relationship];
68682
+ const {
68683
+ tableName: toTable,
68684
+ through: throughTable,
68685
+ to: toKey,
68686
+ from: fromKey,
68687
+ fromPrimary,
68688
+ toPrimary
68689
+ } = relationship;
68690
+ if (!toTable || !fromTable) {
68691
+ continue;
68528
68692
  }
68529
- }
68530
- for (let [key, relationships2] of Object.entries(tableSets)) {
68531
- const { toTable, throughTable } = JSON.parse(key);
68532
- const toAlias = aliases?.[toTable] || toTable, throughAlias = aliases?.[throughTable] || throughTable, fromAlias = aliases?.[fromTable] || fromTable;
68693
+ const toAlias = aliases?.[toTable] || toTable, fromAlias = aliases?.[fromTable] || fromTable;
68533
68694
  let toTableWithSchema = this.tableNameWithSchema(toTable, {
68534
68695
  alias: toAlias,
68535
- schema
68536
- });
68537
- let throughTableWithSchema = this.tableNameWithSchema(throughTable, {
68538
- alias: throughAlias,
68539
- schema
68696
+ schema: endpoint.schema
68540
68697
  });
68541
- if (!throughTable) {
68542
- query = query.leftJoin(toTableWithSchema, function() {
68543
- for (let relationship of relationships2) {
68544
- const from = relationship.from, to = relationship.to;
68545
- this.orOn(`${fromAlias}.${from}`, "=", `${toAlias}.${to}`);
68546
- }
68698
+ let relationshipFields = fields.filter(
68699
+ (field) => field.split(".")[0] === toAlias
68700
+ );
68701
+ if (this.client === "sqlite3" /* SQL_LITE */) {
68702
+ relationshipFields = relationshipFields.slice(
68703
+ 0,
68704
+ MAX_SQS_RELATIONSHIP_FIELDS
68705
+ );
68706
+ }
68707
+ const fieldList = relationshipFields.map((field) => this.buildJsonField(field)).join(",");
68708
+ const primaryKey = `${toAlias}.${toPrimary || toKey}`;
68709
+ let subQuery = knex3.from(toTableWithSchema).limit(getRelationshipLimit()).orderBy(primaryKey);
68710
+ if (throughTable && toPrimary && fromPrimary) {
68711
+ const throughAlias = aliases?.[throughTable] || throughTable;
68712
+ let throughTableWithSchema = this.tableNameWithSchema(throughTable, {
68713
+ alias: throughAlias,
68714
+ schema: endpoint.schema
68547
68715
  });
68716
+ subQuery = subQuery.join(throughTableWithSchema, function() {
68717
+ this.on(`${toAlias}.${toPrimary}`, "=", `${throughAlias}.${toKey}`);
68718
+ }).where(
68719
+ `${throughAlias}.${fromKey}`,
68720
+ "=",
68721
+ knex3.raw(this.quotedIdentifier(`${fromAlias}.${fromPrimary}`))
68722
+ );
68548
68723
  } else {
68549
- query = query.leftJoin(throughTableWithSchema, function() {
68550
- for (let relationship of relationships2) {
68551
- const fromPrimary = relationship.fromPrimary;
68552
- const from = relationship.from;
68553
- this.orOn(
68554
- `${fromAlias}.${fromPrimary}`,
68555
- "=",
68556
- `${throughAlias}.${from}`
68557
- );
68558
- }
68559
- }).leftJoin(toTableWithSchema, function() {
68560
- for (let relationship of relationships2) {
68561
- const toPrimary = relationship.toPrimary;
68562
- const to = relationship.to;
68563
- this.orOn(`${toAlias}.${toPrimary}`, `${throughAlias}.${to}`);
68564
- }
68724
+ subQuery = subQuery.where(
68725
+ `${toAlias}.${toKey}`,
68726
+ "=",
68727
+ knex3.raw(this.quotedIdentifier(`${fromAlias}.${fromKey}`))
68728
+ );
68729
+ }
68730
+ const standardWrap = (select) => {
68731
+ subQuery = subQuery.select(`${toAlias}.*`);
68732
+ return knex3.select(knex3.raw(select)).from({
68733
+ [toAlias]: subQuery
68565
68734
  });
68735
+ };
68736
+ let wrapperQuery;
68737
+ switch (sqlClient) {
68738
+ case "sqlite3" /* SQL_LITE */:
68739
+ subQuery = this.addJoinFieldCheck(subQuery, relationship);
68740
+ wrapperQuery = standardWrap(
68741
+ `json_group_array(json_object(${fieldList}))`
68742
+ );
68743
+ break;
68744
+ case "pg" /* POSTGRES */:
68745
+ wrapperQuery = standardWrap(
68746
+ `json_agg(json_build_object(${fieldList}))`
68747
+ );
68748
+ break;
68749
+ case "mysql2" /* MY_SQL */:
68750
+ wrapperQuery = subQuery.select(
68751
+ knex3.raw(`json_arrayagg(json_object(${fieldList}))`)
68752
+ );
68753
+ break;
68754
+ case "oracledb" /* ORACLE */:
68755
+ wrapperQuery = standardWrap(
68756
+ `json_arrayagg(json_object(${fieldList}))`
68757
+ );
68758
+ break;
68759
+ case "mssql" /* MS_SQL */:
68760
+ wrapperQuery = knex3.raw(
68761
+ `(SELECT ${this.quote(toAlias)} = (${knex3.select(`${fromAlias}.*`).from({
68762
+ [fromAlias]: subQuery.select(`${toAlias}.*`)
68763
+ })} FOR JSON PATH))`
68764
+ );
68765
+ break;
68766
+ default:
68767
+ throw new Error(`JSON relationships not implement for ${sqlClient}`);
68566
68768
  }
68769
+ query = query.select({ [relationship.column]: wrapperQuery });
68770
+ }
68771
+ return query;
68772
+ }
68773
+ addJoin(query, tables, columns) {
68774
+ const { tableAliases: aliases, endpoint } = this.query;
68775
+ const schema = endpoint.schema;
68776
+ const toTable = tables.to, fromTable = tables.from, throughTable = tables.through;
68777
+ const toAlias = aliases?.[toTable] || toTable, throughAlias = throughTable && aliases?.[throughTable] || throughTable, fromAlias = aliases?.[fromTable] || fromTable;
68778
+ let toTableWithSchema = this.tableNameWithSchema(toTable, {
68779
+ alias: toAlias,
68780
+ schema
68781
+ });
68782
+ let throughTableWithSchema = throughTable ? this.tableNameWithSchema(throughTable, {
68783
+ alias: throughAlias,
68784
+ schema
68785
+ }) : void 0;
68786
+ if (!throughTable) {
68787
+ query = query.leftJoin(toTableWithSchema, function() {
68788
+ for (let relationship of columns) {
68789
+ const from = relationship.from, to = relationship.to;
68790
+ this.orOn(`${fromAlias}.${from}`, "=", `${toAlias}.${to}`);
68791
+ }
68792
+ });
68793
+ } else {
68794
+ query = query.leftJoin(throughTableWithSchema, function() {
68795
+ for (let relationship of columns) {
68796
+ const fromPrimary = relationship.fromPrimary;
68797
+ const from = relationship.from;
68798
+ this.orOn(
68799
+ `${fromAlias}.${fromPrimary}`,
68800
+ "=",
68801
+ `${throughAlias}.${from}`
68802
+ );
68803
+ }
68804
+ }).leftJoin(toTableWithSchema, function() {
68805
+ for (let relationship of columns) {
68806
+ const toPrimary = relationship.toPrimary;
68807
+ const to = relationship.to;
68808
+ this.orOn(`${toAlias}.${toPrimary}`, `${throughAlias}.${to}`);
68809
+ }
68810
+ });
68567
68811
  }
68568
68812
  return query;
68569
68813
  }
@@ -68631,15 +68875,14 @@ var InternalBuilder = class {
68631
68875
  if (!primary) {
68632
68876
  throw new Error("Primary key is required for upsert");
68633
68877
  }
68634
- const ret = query.insert(parsedBody).onConflict(primary).merge();
68635
- return ret;
68878
+ return query.insert(parsedBody).onConflict(primary).merge();
68636
68879
  } else if (this.client === "mssql" /* MS_SQL */ || this.client === "oracledb" /* ORACLE */) {
68637
68880
  return query.insert(parsedBody);
68638
68881
  }
68639
68882
  return query.upsert(parsedBody);
68640
68883
  }
68641
68884
  read(opts = {}) {
68642
- let { endpoint, filters, paginate, relationships, tableAliases } = this.query;
68885
+ let { endpoint, filters, paginate, relationships } = this.query;
68643
68886
  const { limits } = opts;
68644
68887
  const counting = endpoint.operation === "COUNT" /* COUNT */;
68645
68888
  const tableName = endpoint.entityId;
@@ -68664,32 +68907,23 @@ var InternalBuilder = class {
68664
68907
  if (foundOffset != null) {
68665
68908
  query = query.offset(foundOffset);
68666
68909
  }
68667
- query = this.addSorting(query);
68668
68910
  }
68669
- query = this.addFilters(query, filters);
68670
- const alias = tableAliases?.[tableName] || tableName;
68671
- let preQuery = this.knex({
68672
- // the typescript definition for the knex constructor doesn't support this
68673
- // syntax, but it is the only way to alias a pre-query result as part of
68674
- // a query - there is an alias dictionary type, but it assumes it can only
68675
- // be a table name, not a pre-query
68676
- [alias]: query
68677
- });
68678
- preQuery = !counting ? preQuery.select(this.generateSelectStatement()) : this.addDistinctCount(preQuery);
68679
- if (this.client !== "mssql" /* MS_SQL */ && !counting) {
68680
- preQuery = this.addSorting(preQuery);
68911
+ query = !counting ? query.select(this.generateSelectStatement()) : this.addDistinctCount(query);
68912
+ if (!counting) {
68913
+ query = this.addSorting(query);
68681
68914
  }
68682
- query = this.addRelationships(
68683
- preQuery,
68684
- tableName,
68685
- relationships,
68686
- endpoint.schema,
68687
- tableAliases
68688
- );
68689
- if (limits?.base) {
68690
- query = query.limit(limits.base);
68915
+ query = this.addFilters(query, filters, { relationship: true });
68916
+ if (relationships?.length) {
68917
+ const mainTable = this.query.tableAliases?.[this.query.endpoint.entityId] || this.query.endpoint.entityId;
68918
+ const cte = this.addSorting(
68919
+ this.knex.with("paginated", query).select(this.generateSelectStatement()).from({
68920
+ [mainTable]: "paginated"
68921
+ })
68922
+ );
68923
+ return this.addJsonRelationships(cte, tableName, relationships);
68924
+ } else {
68925
+ return query;
68691
68926
  }
68692
- return this.addFilters(query, filters, { relationship: true });
68693
68927
  }
68694
68928
  update(opts) {
68695
68929
  const { body: body2, filters } = this.query;