@budibase/server 3.4.15 → 3.4.17
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.
|
@@ -1,511 +1,532 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AIOperationEnum,
|
|
3
3
|
CalculationType,
|
|
4
|
+
Datasource,
|
|
4
5
|
FieldType,
|
|
5
6
|
RelationshipType,
|
|
6
|
-
SourceName,
|
|
7
7
|
Table,
|
|
8
8
|
ViewV2,
|
|
9
9
|
ViewV2Type,
|
|
10
10
|
} from "@budibase/types"
|
|
11
11
|
import { buildSqlFieldList } from "../sqlUtils"
|
|
12
12
|
import { structures } from "../../../../routes/tests/utilities"
|
|
13
|
-
import { sql } from "@budibase/backend-core"
|
|
14
13
|
import { generator } from "@budibase/backend-core/tests"
|
|
15
14
|
import { generateViewID } from "../../../../../db/utils"
|
|
16
15
|
|
|
17
|
-
import sdk from "../../../../../sdk"
|
|
18
|
-
import { cloneDeep } from "lodash"
|
|
19
16
|
import { utils } from "@budibase/shared-core"
|
|
17
|
+
import {
|
|
18
|
+
DatabaseName,
|
|
19
|
+
datasourceDescribe,
|
|
20
|
+
} from "../../../../../integrations/tests/utils"
|
|
21
|
+
import { context } from "@budibase/backend-core"
|
|
20
22
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}))
|
|
25
|
-
const getTableMock = sdk.views.getTable as jest.MockedFunction<
|
|
26
|
-
typeof sdk.views.getTable
|
|
27
|
-
>
|
|
28
|
-
|
|
29
|
-
describe("buildSqlFieldList", () => {
|
|
30
|
-
let allTables: Record<string, Table>
|
|
31
|
-
|
|
32
|
-
class TableConfig {
|
|
33
|
-
private _table: Table & { _id: string }
|
|
34
|
-
|
|
35
|
-
constructor(name: string) {
|
|
36
|
-
this._table = {
|
|
37
|
-
...structures.tableForDatasource({
|
|
38
|
-
type: "datasource",
|
|
39
|
-
source: SourceName.POSTGRES,
|
|
40
|
-
}),
|
|
41
|
-
name,
|
|
42
|
-
_id: sql.utils.buildExternalTableId("ds_id", name),
|
|
43
|
-
schema: {
|
|
44
|
-
name: {
|
|
45
|
-
name: "name",
|
|
46
|
-
type: FieldType.STRING,
|
|
47
|
-
},
|
|
48
|
-
description: {
|
|
49
|
-
name: "description",
|
|
50
|
-
type: FieldType.STRING,
|
|
51
|
-
},
|
|
52
|
-
amount: {
|
|
53
|
-
name: "amount",
|
|
54
|
-
type: FieldType.NUMBER,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
}
|
|
23
|
+
const descriptions = datasourceDescribe({
|
|
24
|
+
only: [DatabaseName.POSTGRES],
|
|
25
|
+
})
|
|
58
26
|
|
|
59
|
-
|
|
60
|
-
|
|
27
|
+
if (descriptions.length) {
|
|
28
|
+
describe.each(descriptions)(
|
|
29
|
+
"buildSqlFieldList ($dbName)",
|
|
30
|
+
({ config, dsProvider }) => {
|
|
31
|
+
let allTables: Record<string, Table>
|
|
32
|
+
let datasource: Datasource
|
|
33
|
+
|
|
34
|
+
beforeEach(async () => {
|
|
35
|
+
const ds = await dsProvider()
|
|
36
|
+
datasource = ds.datasource!
|
|
37
|
+
allTables = {}
|
|
38
|
+
})
|
|
61
39
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return this
|
|
65
|
-
}
|
|
40
|
+
class TableConfig {
|
|
41
|
+
private _table: Table
|
|
66
42
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
| FieldType.STRING
|
|
71
|
-
| FieldType.NUMBER
|
|
72
|
-
| FieldType.FORMULA
|
|
73
|
-
| FieldType.AI,
|
|
74
|
-
options?: { visible: boolean }
|
|
75
|
-
) {
|
|
76
|
-
switch (type) {
|
|
77
|
-
case FieldType.NUMBER:
|
|
78
|
-
case FieldType.STRING:
|
|
79
|
-
this._table.schema[name] = {
|
|
43
|
+
constructor(name: string) {
|
|
44
|
+
this._table = {
|
|
45
|
+
...structures.tableForDatasource(datasource),
|
|
80
46
|
name,
|
|
81
|
-
|
|
82
|
-
|
|
47
|
+
schema: {
|
|
48
|
+
name: {
|
|
49
|
+
name: "name",
|
|
50
|
+
type: FieldType.STRING,
|
|
51
|
+
},
|
|
52
|
+
description: {
|
|
53
|
+
name: "description",
|
|
54
|
+
type: FieldType.STRING,
|
|
55
|
+
},
|
|
56
|
+
amount: {
|
|
57
|
+
name: "amount",
|
|
58
|
+
type: FieldType.NUMBER,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
83
61
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
withHiddenField(field: string) {
|
|
65
|
+
this._table.schema[field].visible = false
|
|
66
|
+
return this
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
withField(
|
|
70
|
+
name: string,
|
|
71
|
+
type:
|
|
72
|
+
| FieldType.STRING
|
|
73
|
+
| FieldType.NUMBER
|
|
74
|
+
| FieldType.FORMULA
|
|
75
|
+
| FieldType.AI,
|
|
76
|
+
options?: { visible: boolean }
|
|
77
|
+
) {
|
|
78
|
+
switch (type) {
|
|
79
|
+
case FieldType.NUMBER:
|
|
80
|
+
case FieldType.STRING:
|
|
81
|
+
this._table.schema[name] = {
|
|
82
|
+
name,
|
|
83
|
+
type,
|
|
84
|
+
...options,
|
|
85
|
+
}
|
|
86
|
+
break
|
|
87
|
+
case FieldType.FORMULA:
|
|
88
|
+
this._table.schema[name] = {
|
|
89
|
+
name,
|
|
90
|
+
type,
|
|
91
|
+
formula: "any",
|
|
92
|
+
...options,
|
|
93
|
+
}
|
|
94
|
+
break
|
|
95
|
+
case FieldType.AI:
|
|
96
|
+
this._table.schema[name] = {
|
|
97
|
+
name,
|
|
98
|
+
type,
|
|
99
|
+
operation: AIOperationEnum.PROMPT,
|
|
100
|
+
...options,
|
|
101
|
+
}
|
|
102
|
+
break
|
|
103
|
+
default:
|
|
104
|
+
utils.unreachable(type)
|
|
91
105
|
}
|
|
92
|
-
|
|
93
|
-
|
|
106
|
+
return this
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
withRelation(name: string, toTableId: string) {
|
|
94
110
|
this._table.schema[name] = {
|
|
95
111
|
name,
|
|
96
|
-
type,
|
|
97
|
-
|
|
98
|
-
|
|
112
|
+
type: FieldType.LINK,
|
|
113
|
+
relationshipType: RelationshipType.ONE_TO_MANY,
|
|
114
|
+
fieldName: "link",
|
|
115
|
+
foreignKey: "link",
|
|
116
|
+
tableId: toTableId,
|
|
99
117
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
return this
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
withPrimary(field: string) {
|
|
122
|
+
this._table.primary = [field]
|
|
123
|
+
return this
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
withDisplay(field: string) {
|
|
127
|
+
this._table.primaryDisplay = field
|
|
128
|
+
return this
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async create() {
|
|
132
|
+
const table = await config.api.table.save(this._table)
|
|
133
|
+
allTables[table.name] = table
|
|
134
|
+
return table
|
|
135
|
+
}
|
|
103
136
|
}
|
|
104
|
-
return this
|
|
105
|
-
}
|
|
106
137
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
name,
|
|
110
|
-
type: FieldType.LINK,
|
|
111
|
-
relationshipType: RelationshipType.ONE_TO_MANY,
|
|
112
|
-
fieldName: "link",
|
|
113
|
-
tableId: toTableId,
|
|
114
|
-
}
|
|
115
|
-
return this
|
|
116
|
-
}
|
|
138
|
+
class ViewConfig {
|
|
139
|
+
private _view: ViewV2
|
|
117
140
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
141
|
+
constructor(table: Table) {
|
|
142
|
+
this._view = {
|
|
143
|
+
version: 2,
|
|
144
|
+
id: generateViewID(table._id!),
|
|
145
|
+
name: generator.word(),
|
|
146
|
+
tableId: table._id!,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
withVisible(field: string) {
|
|
151
|
+
this._view.schema ??= {}
|
|
152
|
+
this._view.schema[field] ??= {}
|
|
153
|
+
this._view.schema[field].visible = true
|
|
154
|
+
return this
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
withHidden(field: string) {
|
|
158
|
+
this._view.schema ??= {}
|
|
159
|
+
this._view.schema[field] ??= {}
|
|
160
|
+
this._view.schema[field].visible = false
|
|
161
|
+
return this
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
withRelationshipColumns(
|
|
165
|
+
field: string,
|
|
166
|
+
columns: Record<string, { visible: boolean }>
|
|
167
|
+
) {
|
|
168
|
+
this._view.schema ??= {}
|
|
169
|
+
this._view.schema[field] ??= {}
|
|
170
|
+
this._view.schema[field].columns = columns
|
|
171
|
+
return this
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
withCalculation(
|
|
175
|
+
name: string,
|
|
176
|
+
field: string,
|
|
177
|
+
calculationType: CalculationType
|
|
178
|
+
) {
|
|
179
|
+
this._view.type = ViewV2Type.CALCULATION
|
|
180
|
+
this._view.schema ??= {}
|
|
181
|
+
this._view.schema[name] = {
|
|
182
|
+
field,
|
|
183
|
+
calculationType,
|
|
184
|
+
visible: true,
|
|
185
|
+
}
|
|
186
|
+
return this
|
|
187
|
+
}
|
|
122
188
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
189
|
+
async create() {
|
|
190
|
+
return await config.api.viewV2.create(this._view)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
127
193
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
constructor(table: Table) {
|
|
138
|
-
this._table = table
|
|
139
|
-
this._view = {
|
|
140
|
-
version: 2,
|
|
141
|
-
id: generateViewID(table._id!),
|
|
142
|
-
name: generator.word(),
|
|
143
|
-
tableId: table._id!,
|
|
194
|
+
const buildSqlFieldListInApp: typeof buildSqlFieldList = async (
|
|
195
|
+
table,
|
|
196
|
+
allTables,
|
|
197
|
+
opts
|
|
198
|
+
) => {
|
|
199
|
+
return context.doInAppContext(config.getAppId(), () =>
|
|
200
|
+
buildSqlFieldList(table, allTables, opts)
|
|
201
|
+
)
|
|
144
202
|
}
|
|
145
|
-
}
|
|
146
203
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
204
|
+
describe("table", () => {
|
|
205
|
+
it("extracts fields from table schema", async () => {
|
|
206
|
+
const table = await new TableConfig("table").create()
|
|
207
|
+
const result = await buildSqlFieldListInApp(table, {})
|
|
208
|
+
expect(result).toEqual([
|
|
209
|
+
"table.name",
|
|
210
|
+
"table.description",
|
|
211
|
+
"table.amount",
|
|
212
|
+
"table.id",
|
|
213
|
+
])
|
|
214
|
+
})
|
|
153
215
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
216
|
+
it("excludes hidden fields", async () => {
|
|
217
|
+
const table = await new TableConfig("table")
|
|
218
|
+
.withHiddenField("description")
|
|
219
|
+
.create()
|
|
220
|
+
const result = await buildSqlFieldListInApp(table, {})
|
|
221
|
+
expect(result).toEqual(["table.name", "table.amount", "table.id"])
|
|
222
|
+
})
|
|
160
223
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
224
|
+
it("excludes non-sql fields fields", async () => {
|
|
225
|
+
const table = await new TableConfig("table")
|
|
226
|
+
.withField("formula", FieldType.FORMULA)
|
|
227
|
+
.withField("ai", FieldType.AI)
|
|
228
|
+
.create()
|
|
229
|
+
|
|
230
|
+
const result = await buildSqlFieldListInApp(table, {})
|
|
231
|
+
expect(result).toEqual([
|
|
232
|
+
"table.name",
|
|
233
|
+
"table.description",
|
|
234
|
+
"table.amount",
|
|
235
|
+
"table.id",
|
|
236
|
+
])
|
|
237
|
+
})
|
|
170
238
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
239
|
+
it("includes hidden fields if there is a formula column", async () => {
|
|
240
|
+
const table = await new TableConfig("table")
|
|
241
|
+
.withHiddenField("description")
|
|
242
|
+
.withField("formula", FieldType.FORMULA)
|
|
243
|
+
.create()
|
|
244
|
+
|
|
245
|
+
const result = await buildSqlFieldListInApp(table, {})
|
|
246
|
+
expect(result).toEqual([
|
|
247
|
+
"table.name",
|
|
248
|
+
"table.description",
|
|
249
|
+
"table.amount",
|
|
250
|
+
"table.id",
|
|
251
|
+
])
|
|
252
|
+
})
|
|
185
253
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
it("excludes hidden fields", async () => {
|
|
209
|
-
const table = new TableConfig("table")
|
|
210
|
-
.withHiddenField("description")
|
|
211
|
-
.create()
|
|
212
|
-
const result = await buildSqlFieldList(table, {})
|
|
213
|
-
expect(result).toEqual(["table.name", "table.amount"])
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
it("excludes non-sql fields fields", async () => {
|
|
217
|
-
const table = new TableConfig("table")
|
|
218
|
-
.withField("formula", FieldType.FORMULA)
|
|
219
|
-
.withField("ai", FieldType.AI)
|
|
220
|
-
.withRelation("link", "otherTableId")
|
|
221
|
-
.create()
|
|
222
|
-
|
|
223
|
-
const result = await buildSqlFieldList(table, {})
|
|
224
|
-
expect(result).toEqual([
|
|
225
|
-
"table.name",
|
|
226
|
-
"table.description",
|
|
227
|
-
"table.amount",
|
|
228
|
-
])
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
it("includes hidden fields if there is a formula column", async () => {
|
|
232
|
-
const table = new TableConfig("table")
|
|
233
|
-
.withHiddenField("description")
|
|
234
|
-
.withField("formula", FieldType.FORMULA)
|
|
235
|
-
.create()
|
|
236
|
-
|
|
237
|
-
const result = await buildSqlFieldList(table, {})
|
|
238
|
-
expect(result).toEqual([
|
|
239
|
-
"table.name",
|
|
240
|
-
"table.description",
|
|
241
|
-
"table.amount",
|
|
242
|
-
])
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
it("includes relationships fields when flagged", async () => {
|
|
246
|
-
const otherTable = new TableConfig("linkedTable")
|
|
247
|
-
.withField("id", FieldType.NUMBER)
|
|
248
|
-
.withPrimary("id")
|
|
249
|
-
.withDisplay("name")
|
|
250
|
-
.create()
|
|
251
|
-
|
|
252
|
-
const table = new TableConfig("table")
|
|
253
|
-
.withRelation("link", otherTable._id)
|
|
254
|
-
.create()
|
|
255
|
-
|
|
256
|
-
const result = await buildSqlFieldList(table, allTables, {
|
|
257
|
-
relationships: true,
|
|
258
|
-
})
|
|
259
|
-
expect(result).toEqual([
|
|
260
|
-
"table.name",
|
|
261
|
-
"table.description",
|
|
262
|
-
"table.amount",
|
|
263
|
-
"linkedTable.id",
|
|
264
|
-
"linkedTable.name",
|
|
265
|
-
])
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
it("includes all relationship fields if there is a formula column", async () => {
|
|
269
|
-
const otherTable = new TableConfig("linkedTable")
|
|
270
|
-
.withField("hidden", FieldType.STRING, { visible: false })
|
|
271
|
-
.create()
|
|
272
|
-
|
|
273
|
-
const table = new TableConfig("table")
|
|
274
|
-
.withRelation("link", otherTable._id)
|
|
275
|
-
.withField("formula", FieldType.FORMULA)
|
|
276
|
-
.create()
|
|
277
|
-
|
|
278
|
-
const result = await buildSqlFieldList(table, allTables, {
|
|
279
|
-
relationships: true,
|
|
280
|
-
})
|
|
281
|
-
expect(result).toEqual([
|
|
282
|
-
"table.name",
|
|
283
|
-
"table.description",
|
|
284
|
-
"table.amount",
|
|
285
|
-
"linkedTable.name",
|
|
286
|
-
"linkedTable.description",
|
|
287
|
-
"linkedTable.amount",
|
|
288
|
-
"linkedTable.hidden",
|
|
289
|
-
])
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
it("never includes non-sql columns from relationships", async () => {
|
|
293
|
-
const otherTable = new TableConfig("linkedTable")
|
|
294
|
-
.withField("id", FieldType.NUMBER)
|
|
295
|
-
.withField("hidden", FieldType.STRING, { visible: false })
|
|
296
|
-
.withField("formula", FieldType.FORMULA)
|
|
297
|
-
.withField("ai", FieldType.AI)
|
|
298
|
-
.withRelation("link", "otherTableId")
|
|
299
|
-
.create()
|
|
300
|
-
|
|
301
|
-
const table = new TableConfig("table")
|
|
302
|
-
.withRelation("link", otherTable._id)
|
|
303
|
-
.withField("formula", FieldType.FORMULA)
|
|
304
|
-
.create()
|
|
305
|
-
|
|
306
|
-
const result = await buildSqlFieldList(table, allTables, {
|
|
307
|
-
relationships: true,
|
|
308
|
-
})
|
|
309
|
-
expect(result).toEqual([
|
|
310
|
-
"table.name",
|
|
311
|
-
"table.description",
|
|
312
|
-
"table.amount",
|
|
313
|
-
"linkedTable.name",
|
|
314
|
-
"linkedTable.description",
|
|
315
|
-
"linkedTable.amount",
|
|
316
|
-
"linkedTable.id",
|
|
317
|
-
"linkedTable.hidden",
|
|
318
|
-
])
|
|
319
|
-
})
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
describe("view", () => {
|
|
323
|
-
it("extracts fields from table schema", async () => {
|
|
324
|
-
const view = new ViewConfig(new TableConfig("table").create())
|
|
325
|
-
.withVisible("amount")
|
|
326
|
-
.withHidden("name")
|
|
327
|
-
.create()
|
|
328
|
-
|
|
329
|
-
const result = await buildSqlFieldList(view, {})
|
|
330
|
-
expect(result).toEqual(["table.amount"])
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
it("includes all fields if there is a formula column", async () => {
|
|
334
|
-
const table = new TableConfig("table")
|
|
335
|
-
.withField("formula", FieldType.FORMULA)
|
|
336
|
-
.create()
|
|
337
|
-
const view = new ViewConfig(table)
|
|
338
|
-
.withHidden("name")
|
|
339
|
-
.withVisible("amount")
|
|
340
|
-
.withVisible("formula")
|
|
341
|
-
.create()
|
|
342
|
-
|
|
343
|
-
const result = await buildSqlFieldList(view, {})
|
|
344
|
-
expect(result).toEqual([
|
|
345
|
-
"table.name",
|
|
346
|
-
"table.description",
|
|
347
|
-
"table.amount",
|
|
348
|
-
])
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
it("does not includes all fields if the formula column is not included", async () => {
|
|
352
|
-
const table = new TableConfig("table")
|
|
353
|
-
.withField("formula", FieldType.FORMULA)
|
|
354
|
-
.create()
|
|
355
|
-
const view = new ViewConfig(table)
|
|
356
|
-
.withHidden("name")
|
|
357
|
-
.withVisible("amount")
|
|
358
|
-
.withHidden("formula")
|
|
359
|
-
.create()
|
|
360
|
-
|
|
361
|
-
const result = await buildSqlFieldList(view, {})
|
|
362
|
-
expect(result).toEqual(["table.amount"])
|
|
363
|
-
})
|
|
364
|
-
|
|
365
|
-
it("includes relationships columns", async () => {
|
|
366
|
-
const otherTable = new TableConfig("linkedTable")
|
|
367
|
-
.withField("id", FieldType.NUMBER)
|
|
368
|
-
.withField("formula", FieldType.FORMULA)
|
|
369
|
-
.withPrimary("id")
|
|
370
|
-
.create()
|
|
371
|
-
|
|
372
|
-
const table = new TableConfig("table")
|
|
373
|
-
.withRelation("link", otherTable._id)
|
|
374
|
-
.create()
|
|
375
|
-
|
|
376
|
-
const view = new ViewConfig(table)
|
|
377
|
-
.withVisible("name")
|
|
378
|
-
.withVisible("link")
|
|
379
|
-
.withRelationshipColumns("link", {
|
|
380
|
-
name: { visible: false },
|
|
381
|
-
amount: { visible: true },
|
|
382
|
-
formula: { visible: false },
|
|
254
|
+
it("includes relationships fields when flagged", async () => {
|
|
255
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
256
|
+
.withField("id", FieldType.NUMBER)
|
|
257
|
+
.withPrimary("id")
|
|
258
|
+
.withDisplay("name")
|
|
259
|
+
.create()
|
|
260
|
+
|
|
261
|
+
const table = await new TableConfig("table")
|
|
262
|
+
.withRelation("link", otherTable._id!)
|
|
263
|
+
.create()
|
|
264
|
+
|
|
265
|
+
const result = await buildSqlFieldListInApp(table, allTables, {
|
|
266
|
+
relationships: true,
|
|
267
|
+
})
|
|
268
|
+
expect(result).toEqual([
|
|
269
|
+
"table.name",
|
|
270
|
+
"table.description",
|
|
271
|
+
"table.amount",
|
|
272
|
+
"table.id",
|
|
273
|
+
"linkedTable.id",
|
|
274
|
+
"linkedTable.name",
|
|
275
|
+
])
|
|
383
276
|
})
|
|
384
|
-
.create()
|
|
385
277
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
278
|
+
it("includes all relationship fields if there is a formula column", async () => {
|
|
279
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
280
|
+
.withField("hidden", FieldType.STRING, { visible: false })
|
|
281
|
+
.create()
|
|
282
|
+
|
|
283
|
+
const table = await new TableConfig("table")
|
|
284
|
+
.withRelation("link", otherTable._id!)
|
|
285
|
+
.withField("formula", FieldType.FORMULA)
|
|
286
|
+
.create()
|
|
287
|
+
|
|
288
|
+
const result = await buildSqlFieldListInApp(table, allTables, {
|
|
289
|
+
relationships: true,
|
|
290
|
+
})
|
|
291
|
+
expect(result).toEqual([
|
|
292
|
+
"table.name",
|
|
293
|
+
"table.description",
|
|
294
|
+
"table.amount",
|
|
295
|
+
"table.id",
|
|
296
|
+
"linkedTable.name",
|
|
297
|
+
"linkedTable.description",
|
|
298
|
+
"linkedTable.amount",
|
|
299
|
+
"linkedTable.hidden",
|
|
300
|
+
"linkedTable.id",
|
|
301
|
+
])
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
it("never includes non-sql columns from relationships", async () => {
|
|
305
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
306
|
+
.withField("hidden", FieldType.STRING, { visible: false })
|
|
307
|
+
.withField("formula", FieldType.FORMULA)
|
|
308
|
+
.withField("ai", FieldType.AI)
|
|
309
|
+
.create()
|
|
310
|
+
|
|
311
|
+
const table = await new TableConfig("table")
|
|
312
|
+
.withRelation("link", otherTable._id!)
|
|
313
|
+
.withField("formula", FieldType.FORMULA)
|
|
314
|
+
.create()
|
|
315
|
+
|
|
316
|
+
const result = await buildSqlFieldListInApp(table, allTables, {
|
|
317
|
+
relationships: true,
|
|
318
|
+
})
|
|
319
|
+
expect(result).toEqual([
|
|
320
|
+
"table.name",
|
|
321
|
+
"table.description",
|
|
322
|
+
"table.amount",
|
|
323
|
+
"table.id",
|
|
324
|
+
"linkedTable.name",
|
|
325
|
+
"linkedTable.description",
|
|
326
|
+
"linkedTable.amount",
|
|
327
|
+
"linkedTable.hidden",
|
|
328
|
+
"linkedTable.id",
|
|
329
|
+
])
|
|
330
|
+
})
|
|
415
331
|
})
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
332
|
+
|
|
333
|
+
describe("view", () => {
|
|
334
|
+
it("extracts fields from table schema", async () => {
|
|
335
|
+
const view = await new ViewConfig(
|
|
336
|
+
await new TableConfig("table").create()
|
|
337
|
+
)
|
|
338
|
+
.withVisible("amount")
|
|
339
|
+
.withHidden("name")
|
|
340
|
+
.create()
|
|
341
|
+
|
|
342
|
+
const result = await buildSqlFieldListInApp(view, {})
|
|
343
|
+
expect(result).toEqual(["table.amount", "table.id"])
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
it("includes all fields if there is a formula column", async () => {
|
|
347
|
+
const table = await new TableConfig("table")
|
|
348
|
+
.withField("formula", FieldType.FORMULA)
|
|
349
|
+
.create()
|
|
350
|
+
const view = await new ViewConfig(table)
|
|
351
|
+
.withHidden("name")
|
|
352
|
+
.withVisible("amount")
|
|
353
|
+
.withVisible("formula")
|
|
354
|
+
.create()
|
|
355
|
+
|
|
356
|
+
const result = await buildSqlFieldListInApp(view, {})
|
|
357
|
+
expect(result).toEqual([
|
|
358
|
+
"table.name",
|
|
359
|
+
"table.description",
|
|
360
|
+
"table.amount",
|
|
361
|
+
"table.id",
|
|
362
|
+
])
|
|
363
|
+
})
|
|
364
|
+
|
|
365
|
+
it("does not includes all fields if the formula column is not included", async () => {
|
|
366
|
+
const table = await new TableConfig("table")
|
|
367
|
+
.withField("formula", FieldType.FORMULA)
|
|
368
|
+
.create()
|
|
369
|
+
const view = await new ViewConfig(table)
|
|
370
|
+
.withHidden("name")
|
|
371
|
+
.withVisible("amount")
|
|
372
|
+
.withHidden("formula")
|
|
373
|
+
.create()
|
|
374
|
+
|
|
375
|
+
const result = await buildSqlFieldListInApp(view, {})
|
|
376
|
+
expect(result).toEqual(["table.amount", "table.id"])
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
it("includes relationships columns", async () => {
|
|
380
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
381
|
+
.withField("id", FieldType.NUMBER)
|
|
382
|
+
.withField("formula", FieldType.FORMULA)
|
|
383
|
+
.withPrimary("id")
|
|
384
|
+
.create()
|
|
385
|
+
|
|
386
|
+
const table = await new TableConfig("table")
|
|
387
|
+
.withRelation("link", otherTable._id!)
|
|
388
|
+
.create()
|
|
389
|
+
|
|
390
|
+
const view = await new ViewConfig(table)
|
|
391
|
+
.withVisible("name")
|
|
392
|
+
.withVisible("link")
|
|
393
|
+
.withRelationshipColumns("link", {
|
|
394
|
+
name: { visible: false },
|
|
395
|
+
amount: { visible: true },
|
|
396
|
+
formula: { visible: false },
|
|
397
|
+
})
|
|
398
|
+
.create()
|
|
399
|
+
|
|
400
|
+
const result = await buildSqlFieldListInApp(view, allTables, {
|
|
401
|
+
relationships: true,
|
|
402
|
+
})
|
|
403
|
+
expect(result).toEqual([
|
|
404
|
+
"table.name",
|
|
405
|
+
"table.id",
|
|
406
|
+
"linkedTable.id",
|
|
407
|
+
"linkedTable.amount",
|
|
408
|
+
])
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
it("excludes relationships fields when view is not included in the view", async () => {
|
|
412
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
413
|
+
.withField("id", FieldType.NUMBER)
|
|
414
|
+
.withPrimary("id")
|
|
415
|
+
.withDisplay("name")
|
|
416
|
+
.create()
|
|
417
|
+
|
|
418
|
+
const table = await new TableConfig("table")
|
|
419
|
+
.withRelation("link", otherTable._id!)
|
|
420
|
+
.withField("formula", FieldType.FORMULA)
|
|
421
|
+
.create()
|
|
422
|
+
|
|
423
|
+
const view = await new ViewConfig(table)
|
|
424
|
+
.withVisible("name")
|
|
425
|
+
.withHidden("amount")
|
|
426
|
+
.create()
|
|
427
|
+
|
|
428
|
+
const result = await buildSqlFieldListInApp(view, allTables, {
|
|
429
|
+
relationships: true,
|
|
430
|
+
})
|
|
431
|
+
expect(result).toEqual(["table.name", "table.id"])
|
|
437
432
|
})
|
|
438
|
-
.create()
|
|
439
433
|
|
|
440
|
-
|
|
441
|
-
|
|
434
|
+
it("does not include relationships columns for hidden links", async () => {
|
|
435
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
436
|
+
.withField("id", FieldType.NUMBER)
|
|
437
|
+
.withField("formula", FieldType.FORMULA)
|
|
438
|
+
.withPrimary("id")
|
|
439
|
+
.create()
|
|
440
|
+
|
|
441
|
+
const table = await new TableConfig("table")
|
|
442
|
+
.withRelation("link", otherTable._id!)
|
|
443
|
+
.create()
|
|
444
|
+
|
|
445
|
+
const view = await new ViewConfig(table)
|
|
446
|
+
.withVisible("name")
|
|
447
|
+
.withHidden("link")
|
|
448
|
+
.withRelationshipColumns("link", {
|
|
449
|
+
name: { visible: false },
|
|
450
|
+
amount: { visible: true },
|
|
451
|
+
formula: { visible: false },
|
|
452
|
+
})
|
|
453
|
+
.create()
|
|
454
|
+
|
|
455
|
+
const result = await buildSqlFieldListInApp(view, allTables, {
|
|
456
|
+
relationships: true,
|
|
457
|
+
})
|
|
458
|
+
expect(result).toEqual(["table.name", "table.id"])
|
|
459
|
+
})
|
|
460
|
+
|
|
461
|
+
it("includes all relationship fields if there is a formula column", async () => {
|
|
462
|
+
const otherTable = await new TableConfig("linkedTable")
|
|
463
|
+
.withField("id", FieldType.NUMBER)
|
|
464
|
+
.withField("hidden", FieldType.STRING, { visible: false })
|
|
465
|
+
.withField("formula", FieldType.FORMULA)
|
|
466
|
+
.withField("ai", FieldType.AI)
|
|
467
|
+
.withPrimary("id")
|
|
468
|
+
.create()
|
|
469
|
+
|
|
470
|
+
const table = await new TableConfig("table")
|
|
471
|
+
.withRelation("link", otherTable._id!)
|
|
472
|
+
.withField("formula", FieldType.FORMULA)
|
|
473
|
+
.create()
|
|
474
|
+
|
|
475
|
+
const view = await new ViewConfig(table)
|
|
476
|
+
.withVisible("name")
|
|
477
|
+
.withVisible("formula")
|
|
478
|
+
.withHidden("link")
|
|
479
|
+
.withRelationshipColumns("link", {
|
|
480
|
+
name: { visible: false },
|
|
481
|
+
amount: { visible: true },
|
|
482
|
+
formula: { visible: false },
|
|
483
|
+
})
|
|
484
|
+
.create()
|
|
485
|
+
|
|
486
|
+
const result = await buildSqlFieldListInApp(view, allTables, {
|
|
487
|
+
relationships: true,
|
|
488
|
+
})
|
|
489
|
+
expect(result).toEqual([
|
|
490
|
+
"table.name",
|
|
491
|
+
"table.description",
|
|
492
|
+
"table.amount",
|
|
493
|
+
"table.id",
|
|
494
|
+
"linkedTable.name",
|
|
495
|
+
"linkedTable.description",
|
|
496
|
+
"linkedTable.amount",
|
|
497
|
+
"linkedTable.id",
|
|
498
|
+
"linkedTable.hidden",
|
|
499
|
+
])
|
|
500
|
+
})
|
|
442
501
|
})
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
const table = new TableConfig("table")
|
|
457
|
-
.withRelation("link", otherTable._id)
|
|
458
|
-
.withField("formula", FieldType.FORMULA)
|
|
459
|
-
.create()
|
|
460
|
-
|
|
461
|
-
const view = new ViewConfig(table)
|
|
462
|
-
.withVisible("name")
|
|
463
|
-
.withVisible("formula")
|
|
464
|
-
.withHidden("link")
|
|
465
|
-
.withRelationshipColumns("link", {
|
|
466
|
-
name: { visible: false },
|
|
467
|
-
amount: { visible: true },
|
|
468
|
-
formula: { visible: false },
|
|
502
|
+
|
|
503
|
+
describe("calculation view", () => {
|
|
504
|
+
it("does not include calculation fields", async () => {
|
|
505
|
+
const view = await new ViewConfig(
|
|
506
|
+
await new TableConfig("table").create()
|
|
507
|
+
)
|
|
508
|
+
.withCalculation("average", "amount", CalculationType.AVG)
|
|
509
|
+
|
|
510
|
+
.create()
|
|
511
|
+
|
|
512
|
+
const result = await buildSqlFieldListInApp(view, {})
|
|
513
|
+
expect(result).toEqual([])
|
|
469
514
|
})
|
|
470
|
-
.create()
|
|
471
515
|
|
|
472
|
-
|
|
473
|
-
|
|
516
|
+
it("includes visible fields calculation fields", async () => {
|
|
517
|
+
const view = await new ViewConfig(
|
|
518
|
+
await new TableConfig("table").create()
|
|
519
|
+
)
|
|
520
|
+
.withCalculation("average", "amount", CalculationType.AVG)
|
|
521
|
+
.withHidden("name")
|
|
522
|
+
.withVisible("amount")
|
|
523
|
+
|
|
524
|
+
.create()
|
|
525
|
+
|
|
526
|
+
const result = await buildSqlFieldListInApp(view, {})
|
|
527
|
+
expect(result).toEqual(["table.amount"])
|
|
528
|
+
})
|
|
474
529
|
})
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
"table.amount",
|
|
479
|
-
"linkedTable.name",
|
|
480
|
-
"linkedTable.description",
|
|
481
|
-
"linkedTable.amount",
|
|
482
|
-
"linkedTable.id",
|
|
483
|
-
"linkedTable.hidden",
|
|
484
|
-
])
|
|
485
|
-
})
|
|
486
|
-
})
|
|
487
|
-
|
|
488
|
-
describe("calculation view", () => {
|
|
489
|
-
it("does not include calculation fields", async () => {
|
|
490
|
-
const view = new ViewConfig(new TableConfig("table").create())
|
|
491
|
-
.withCalculation("average", "amount", CalculationType.AVG)
|
|
492
|
-
|
|
493
|
-
.create()
|
|
494
|
-
|
|
495
|
-
const result = await buildSqlFieldList(view, {})
|
|
496
|
-
expect(result).toEqual([])
|
|
497
|
-
})
|
|
498
|
-
|
|
499
|
-
it("includes visible fields calculation fields", async () => {
|
|
500
|
-
const view = new ViewConfig(new TableConfig("table").create())
|
|
501
|
-
.withCalculation("average", "amount", CalculationType.AVG)
|
|
502
|
-
.withHidden("name")
|
|
503
|
-
.withVisible("amount")
|
|
504
|
-
|
|
505
|
-
.create()
|
|
506
|
-
|
|
507
|
-
const result = await buildSqlFieldList(view, {})
|
|
508
|
-
expect(result).toEqual(["table.amount"])
|
|
509
|
-
})
|
|
510
|
-
})
|
|
511
|
-
})
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
}
|