@budibase/backend-core 2.33.14 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/sql/sql.ts CHANGED
@@ -179,12 +179,6 @@ class InternalBuilder {
179
179
  return this.table.schema[column]
180
180
  }
181
181
 
182
- private supportsILike(): boolean {
183
- return !(
184
- this.client === SqlClient.ORACLE || this.client === SqlClient.SQL_LITE
185
- )
186
- }
187
-
188
182
  private quoteChars(): [string, string] {
189
183
  const wrapped = this.knexClient.wrapIdentifier("foo", {})
190
184
  return [wrapped[0], wrapped[wrapped.length - 1]]
@@ -216,8 +210,30 @@ class InternalBuilder {
216
210
  return formatter.wrap(value, false)
217
211
  }
218
212
 
219
- private rawQuotedValue(value: string): Knex.Raw {
220
- return this.knex.raw(this.quotedValue(value))
213
+ private castIntToString(identifier: string | Knex.Raw): Knex.Raw {
214
+ switch (this.client) {
215
+ case SqlClient.ORACLE: {
216
+ return this.knex.raw("to_char(??)", [identifier])
217
+ }
218
+ case SqlClient.POSTGRES: {
219
+ return this.knex.raw("??::TEXT", [identifier])
220
+ }
221
+ case SqlClient.MY_SQL:
222
+ case SqlClient.MARIADB: {
223
+ return this.knex.raw("CAST(?? AS CHAR)", [identifier])
224
+ }
225
+ case SqlClient.SQL_LITE: {
226
+ // Technically sqlite can actually represent numbers larger than a 64bit
227
+ // int as a string, but it does it using scientific notation (e.g.
228
+ // "1e+20") which is not what we want. Given that the external SQL
229
+ // databases are limited to supporting only 64bit ints, we settle for
230
+ // that here.
231
+ return this.knex.raw("printf('%d', ??)", [identifier])
232
+ }
233
+ case SqlClient.MS_SQL: {
234
+ return this.knex.raw("CONVERT(NVARCHAR, ??)", [identifier])
235
+ }
236
+ }
221
237
  }
222
238
 
223
239
  // Unfortuantely we cannot rely on knex's identifier escaping because it trims
@@ -512,7 +528,7 @@ class InternalBuilder {
512
528
  if (!matchesTableName) {
513
529
  updatedKey = filterKey.replace(
514
530
  new RegExp(`^${relationship.column}.`),
515
- `${aliases![relationship.tableName]}.`
531
+ `${aliases?.[relationship.tableName] || relationship.tableName}.`
516
532
  )
517
533
  } else {
518
534
  updatedKey = filterKey
@@ -1074,24 +1090,36 @@ class InternalBuilder {
1074
1090
  )
1075
1091
  }
1076
1092
  } else {
1077
- query = query.count(`* as ${aggregation.name}`)
1093
+ if (this.client === SqlClient.ORACLE) {
1094
+ const field = this.convertClobs(`${tableName}.${aggregation.field}`)
1095
+ query = query.select(
1096
+ this.knex.raw(`COUNT(??) as ??`, [field, aggregation.name])
1097
+ )
1098
+ } else {
1099
+ query = query.count(`${aggregation.field} as ${aggregation.name}`)
1100
+ }
1078
1101
  }
1079
1102
  } else {
1080
- const field = `${tableName}.${aggregation.field} as ${aggregation.name}`
1081
- switch (op) {
1082
- case CalculationType.SUM:
1083
- query = query.sum(field)
1084
- break
1085
- case CalculationType.AVG:
1086
- query = query.avg(field)
1087
- break
1088
- case CalculationType.MIN:
1089
- query = query.min(field)
1090
- break
1091
- case CalculationType.MAX:
1092
- query = query.max(field)
1093
- break
1103
+ const fieldSchema = this.getFieldSchema(aggregation.field)
1104
+ if (!fieldSchema) {
1105
+ // This should not happen in practice.
1106
+ throw new Error(
1107
+ `field schema missing for aggregation target: ${aggregation.field}`
1108
+ )
1109
+ }
1110
+
1111
+ let aggregate = this.knex.raw("??(??)", [
1112
+ this.knex.raw(op),
1113
+ this.rawQuotedIdentifier(`${tableName}.${aggregation.field}`),
1114
+ ])
1115
+
1116
+ if (fieldSchema.type === FieldType.BIGINT) {
1117
+ aggregate = this.castIntToString(aggregate)
1094
1118
  }
1119
+
1120
+ query = query.select(
1121
+ this.knex.raw("?? as ??", [aggregate, aggregation.name])
1122
+ )
1095
1123
  }
1096
1124
  }
1097
1125
  return query
@@ -1434,7 +1462,8 @@ class InternalBuilder {
1434
1462
  schema.constraints?.presence === true ||
1435
1463
  schema.type === FieldType.FORMULA ||
1436
1464
  schema.type === FieldType.AUTO ||
1437
- schema.type === FieldType.LINK
1465
+ schema.type === FieldType.LINK ||
1466
+ schema.type === FieldType.AI
1438
1467
  ) {
1439
1468
  continue
1440
1469
  }
@@ -1556,7 +1585,7 @@ class InternalBuilder {
1556
1585
  query = this.addFilters(query, filters, { relationship: true })
1557
1586
 
1558
1587
  // handle relationships with a CTE for all others
1559
- if (relationships?.length) {
1588
+ if (relationships?.length && aggregations.length === 0) {
1560
1589
  const mainTable =
1561
1590
  this.query.tableAliases?.[this.query.endpoint.entityId] ||
1562
1591
  this.query.endpoint.entityId
@@ -1571,10 +1600,8 @@ class InternalBuilder {
1571
1600
  // add JSON aggregations attached to the CTE
1572
1601
  return this.addJsonRelationships(cte, tableName, relationships)
1573
1602
  }
1574
- // no relationships found - return query
1575
- else {
1576
- return query
1577
- }
1603
+
1604
+ return query
1578
1605
  }
1579
1606
 
1580
1607
  update(opts: QueryOptions): Knex.QueryBuilder {
@@ -102,6 +102,14 @@ export const useAppBuilders = () => {
102
102
  return useFeature(Feature.APP_BUILDERS)
103
103
  }
104
104
 
105
+ export const useBudibaseAI = () => {
106
+ return useFeature(Feature.BUDIBASE_AI)
107
+ }
108
+
109
+ export const useAICustomConfigs = () => {
110
+ return useFeature(Feature.AI_CUSTOM_CONFIGS)
111
+ }
112
+
105
113
  // QUOTAS
106
114
 
107
115
  export const setAutomationLogsQuota = (value: number) => {