@budibase/server 1.0.90 → 1.0.91-alpha.10
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/builder/assets/{index.7c8961b4.css → index.9ae0eacb.css} +1 -1
- package/builder/assets/{index.5cea89f7.js → index.aa487b9b.js} +212 -212
- package/builder/assets/{vendor.a7c6ad0a.js → vendor.8e34a169.js} +1 -1
- package/builder/index.html +3 -3
- package/coverage/clover.xml +192 -191
- package/coverage/coverage-final.json +10 -10
- package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
- package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/controllers/application.js.html +1 -1
- package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
- package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
- package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
- package/coverage/lcov-report/api/controllers/cloud.js.html +1 -1
- package/coverage/lcov-report/api/controllers/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +1 -1
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/index.html +1 -1
- package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
- package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
- package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
- package/coverage/lcov-report/api/controllers/migrations.js.html +1 -1
- package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.html +1 -1
- package/coverage/lcov-report/api/controllers/query/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query/validation.js.html +2 -2
- package/coverage/lcov-report/api/controllers/role.js.html +1 -1
- package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/index.html +10 -10
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +19 -7
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/staticFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +6 -6
- package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
- package/coverage/lcov-report/api/controllers/script.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/bulkFormula.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/external.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/internal.js.html +1 -1
- package/coverage/lcov-report/api/controllers/table/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
- package/coverage/lcov-report/api/controllers/user.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.html +1 -1
- package/coverage/lcov-report/api/controllers/view/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/utils.js.html +1 -1
- package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
- package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
- package/coverage/lcov-report/api/index.html +1 -1
- package/coverage/lcov-report/api/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/analytics.js.html +3 -3
- package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
- package/coverage/lcov-report/api/routes/application.js.html +1 -1
- package/coverage/lcov-report/api/routes/auth.js.html +1 -1
- package/coverage/lcov-report/api/routes/automation.js.html +1 -1
- package/coverage/lcov-report/api/routes/backup.js.html +1 -1
- package/coverage/lcov-report/api/routes/cloud.js.html +1 -1
- package/coverage/lcov-report/api/routes/component.js.html +1 -1
- package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
- package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
- package/coverage/lcov-report/api/routes/dev.js.html +1 -1
- package/coverage/lcov-report/api/routes/index.html +1 -1
- package/coverage/lcov-report/api/routes/index.js.html +1 -1
- package/coverage/lcov-report/api/routes/integration.js.html +1 -1
- package/coverage/lcov-report/api/routes/layout.js.html +1 -1
- package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
- package/coverage/lcov-report/api/routes/migrations.js.html +1 -1
- package/coverage/lcov-report/api/routes/permission.js.html +1 -1
- package/coverage/lcov-report/api/routes/query.js.html +1 -1
- package/coverage/lcov-report/api/routes/role.js.html +1 -1
- package/coverage/lcov-report/api/routes/routing.js.html +1 -1
- package/coverage/lcov-report/api/routes/row.js.html +1 -1
- package/coverage/lcov-report/api/routes/screen.js.html +1 -1
- package/coverage/lcov-report/api/routes/script.js.html +1 -1
- package/coverage/lcov-report/api/routes/static.js.html +1 -1
- package/coverage/lcov-report/api/routes/table.js.html +1 -1
- package/coverage/lcov-report/api/routes/templates.js.html +1 -1
- package/coverage/lcov-report/api/routes/user.js.html +1 -1
- package/coverage/lcov-report/api/routes/utils/index.html +1 -1
- package/coverage/lcov-report/api/routes/utils/validators.js.html +1 -1
- package/coverage/lcov-report/api/routes/view.js.html +1 -1
- package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/actions.js.html +1 -1
- package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
- package/coverage/lcov-report/automations/bullboard.js.html +1 -1
- package/coverage/lcov-report/automations/index.html +1 -1
- package/coverage/lcov-report/automations/index.js.html +1 -1
- package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
- package/coverage/lcov-report/automations/steps/createRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
- package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
- package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
- package/coverage/lcov-report/automations/steps/index.html +1 -1
- package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
- package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
- package/coverage/lcov-report/automations/steps/queryRows.js.html +1 -1
- package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
- package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
- package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
- package/coverage/lcov-report/automations/steps/updateRow.js.html +1 -1
- package/coverage/lcov-report/automations/steps/utils.js.html +1 -1
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
- package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
- package/coverage/lcov-report/automations/triggers.js.html +1 -1
- package/coverage/lcov-report/automations/utils.js.html +1 -1
- package/coverage/lcov-report/constants/index.html +1 -1
- package/coverage/lcov-report/constants/index.js.html +1 -1
- package/coverage/lcov-report/constants/layouts.js.html +1 -1
- package/coverage/lcov-report/constants/screens.js.html +1 -1
- package/coverage/lcov-report/db/client.js.html +1 -1
- package/coverage/lcov-report/db/inMemoryView.js.html +1 -1
- package/coverage/lcov-report/db/index.html +1 -1
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.html +1 -1
- package/coverage/lcov-report/db/linkedRows/index.js.html +11 -11
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +7 -7
- package/coverage/lcov-report/db/newid.js.html +2 -2
- package/coverage/lcov-report/db/utils.js.html +2 -2
- package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
- package/coverage/lcov-report/events/index.html +1 -1
- package/coverage/lcov-report/events/index.js.html +1 -1
- package/coverage/lcov-report/events/utils.js.html +1 -1
- package/coverage/lcov-report/index.html +10 -10
- package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
- package/coverage/lcov-report/integrations/tests/index.html +1 -1
- package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
- package/coverage/lcov-report/middleware/authorized.js.html +1 -1
- package/coverage/lcov-report/middleware/builder.js.html +1 -1
- package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
- package/coverage/lcov-report/middleware/index.html +1 -1
- package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
- package/coverage/lcov-report/middleware/publicApi.js.html +1 -1
- package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
- package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
- package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
- package/coverage/lcov-report/middleware/utils.js.html +1 -1
- package/coverage/lcov-report/threads/automation.js.html +1 -1
- package/coverage/lcov-report/threads/index.html +1 -1
- package/coverage/lcov-report/threads/index.js.html +1 -1
- package/coverage/lcov-report/threads/query.js.html +1 -1
- package/coverage/lcov-report/threads/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
- package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
- package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
- package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
- package/coverage/lcov-report/utilities/global.js.html +1 -1
- package/coverage/lcov-report/utilities/index.html +1 -1
- package/coverage/lcov-report/utilities/index.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
- package/coverage/lcov-report/utilities/queue/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.html +1 -1
- package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.html +1 -1
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +12 -12
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +8 -8
- package/coverage/lcov-report/utilities/scriptRunner.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +1 -1
- package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/index.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/rows.js.html +1 -1
- package/coverage/lcov-report/utilities/usageQuota/usageQuoteReset.js.html +1 -1
- package/coverage/lcov-report/utilities/users.js.html +1 -1
- package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
- package/coverage/lcov.info +281 -280
- package/dist/api/controllers/query/import/index.js +2 -1
- package/dist/api/controllers/query/import/sources/base/index.js +12 -1
- package/dist/api/controllers/query/import/sources/curl.js +2 -2
- package/dist/api/controllers/query/import/sources/openapi3.js +174 -0
- package/dist/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
- package/dist/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
- package/dist/api/controllers/row/internal.js +2 -1
- package/dist/api/routes/analytics.js +2 -2
- package/dist/definitions/datasource.js +1 -0
- package/dist/integrations/base/sql.js +16 -9
- package/dist/integrations/firebase.js +192 -0
- package/dist/integrations/index.js +3 -0
- package/dist/package.json +5 -4
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/src/api/controllers/query/import/index.ts +2 -1
- package/src/api/controllers/query/import/sources/base/index.ts +12 -2
- package/src/api/controllers/query/import/sources/curl.ts +2 -2
- package/src/api/controllers/query/import/sources/openapi3.ts +205 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.json +253 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/crud/crud.yaml +153 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.json +1225 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/data/petstore/petstore.yaml +804 -0
- package/src/api/controllers/query/import/sources/tests/openapi3/openapi3.spec.js +240 -0
- package/src/api/controllers/query/import/tests/index.spec.js +43 -0
- package/src/api/controllers/row/internal.js +5 -1
- package/src/api/routes/analytics.js +2 -2
- package/src/api/routes/tests/misc.spec.js +2 -2
- package/src/definitions/datasource.ts +1 -0
- package/src/integrations/base/sql.ts +14 -9
- package/src/integrations/firebase.ts +205 -0
- package/src/integrations/index.ts +3 -0
- package/src/integrations/tests/sql.spec.js +51 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
const fs = require("fs")
|
|
2
|
+
const path = require("path")
|
|
3
|
+
|
|
4
|
+
const { OpenAPI3 } = require("../../openapi3")
|
|
5
|
+
|
|
6
|
+
const getData = (file, extension) => {
|
|
7
|
+
return fs.readFileSync(
|
|
8
|
+
path.join(__dirname, `./data/${file}/${file}.${extension}`),
|
|
9
|
+
"utf8"
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
describe("OpenAPI3 Import", () => {
|
|
14
|
+
let openapi3
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
openapi3 = new OpenAPI3()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("validates unsupported data", async () => {
|
|
21
|
+
let data
|
|
22
|
+
let supported
|
|
23
|
+
|
|
24
|
+
// non json / yaml
|
|
25
|
+
data = "curl http://example.com"
|
|
26
|
+
supported = await openapi3.isSupported(data)
|
|
27
|
+
expect(supported).toBe(false)
|
|
28
|
+
|
|
29
|
+
// Empty
|
|
30
|
+
data = ""
|
|
31
|
+
supported = await openapi3.isSupported(data)
|
|
32
|
+
expect(supported).toBe(false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const runTests = async (filename, test, assertions) => {
|
|
36
|
+
for (let extension of ["json", "yaml"]) {
|
|
37
|
+
await test(filename, extension, assertions)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const testImportInfo = async (file, extension) => {
|
|
42
|
+
await openapi3.isSupported(getData(file, extension))
|
|
43
|
+
const info = await openapi3.getInfo()
|
|
44
|
+
expect(info.name).toBe("Swagger Petstore - OpenAPI 3.0")
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
it("returns import info", async () => {
|
|
48
|
+
await runTests("petstore", testImportInfo)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
describe("Returns queries", () => {
|
|
52
|
+
const indexQueries = queries => {
|
|
53
|
+
return queries.reduce((acc, query) => {
|
|
54
|
+
acc[query.name] = query
|
|
55
|
+
return acc
|
|
56
|
+
}, {})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const getQueries = async (file, extension) => {
|
|
60
|
+
await openapi3.isSupported(getData(file, extension))
|
|
61
|
+
const queries = await openapi3.getQueries()
|
|
62
|
+
expect(queries.length).toBe(6)
|
|
63
|
+
return indexQueries(queries)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const testVerb = async (file, extension, assertions) => {
|
|
67
|
+
const queries = await getQueries(file, extension)
|
|
68
|
+
for (let [operationId, method] of Object.entries(assertions)) {
|
|
69
|
+
expect(queries[operationId].queryVerb).toBe(method)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
it("populates verb", async () => {
|
|
74
|
+
const assertions = {
|
|
75
|
+
createEntity: "create",
|
|
76
|
+
getEntities: "read",
|
|
77
|
+
getEntity: "read",
|
|
78
|
+
updateEntity: "update",
|
|
79
|
+
patchEntity: "patch",
|
|
80
|
+
deleteEntity: "delete",
|
|
81
|
+
}
|
|
82
|
+
await runTests("crud", testVerb, assertions)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const testPath = async (file, extension, assertions) => {
|
|
86
|
+
const queries = await getQueries(file, extension)
|
|
87
|
+
for (let [operationId, urlPath] of Object.entries(assertions)) {
|
|
88
|
+
expect(queries[operationId].fields.path).toBe(urlPath)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
it("populates path", async () => {
|
|
93
|
+
const assertions = {
|
|
94
|
+
createEntity: "http://example.com/entities",
|
|
95
|
+
getEntities: "http://example.com/entities",
|
|
96
|
+
getEntity: "http://example.com/entities/{{entityId}}",
|
|
97
|
+
updateEntity: "http://example.com/entities/{{entityId}}",
|
|
98
|
+
patchEntity: "http://example.com/entities/{{entityId}}",
|
|
99
|
+
deleteEntity: "http://example.com/entities/{{entityId}}",
|
|
100
|
+
}
|
|
101
|
+
await runTests("crud", testPath, assertions)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const testHeaders = async (file, extension, assertions) => {
|
|
105
|
+
const queries = await getQueries(file, extension)
|
|
106
|
+
for (let [operationId, headers] of Object.entries(assertions)) {
|
|
107
|
+
expect(queries[operationId].fields.headers).toStrictEqual(headers)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const contentTypeHeader = {
|
|
112
|
+
"Content-Type": "application/json",
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
it("populates headers", async () => {
|
|
116
|
+
const assertions = {
|
|
117
|
+
createEntity: {
|
|
118
|
+
...contentTypeHeader,
|
|
119
|
+
},
|
|
120
|
+
getEntities: {},
|
|
121
|
+
getEntity: {},
|
|
122
|
+
updateEntity: {
|
|
123
|
+
...contentTypeHeader,
|
|
124
|
+
},
|
|
125
|
+
patchEntity: {
|
|
126
|
+
...contentTypeHeader,
|
|
127
|
+
},
|
|
128
|
+
deleteEntity: {
|
|
129
|
+
"x-api-key": "{{x-api-key}}",
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
await runTests("crud", testHeaders, assertions)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const testQuery = async (file, extension, assertions) => {
|
|
137
|
+
const queries = await getQueries(file, extension)
|
|
138
|
+
for (let [operationId, queryString] of Object.entries(assertions)) {
|
|
139
|
+
expect(queries[operationId].fields.queryString).toStrictEqual(
|
|
140
|
+
queryString
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
it("populates query", async () => {
|
|
146
|
+
const assertions = {
|
|
147
|
+
createEntity: "",
|
|
148
|
+
getEntities: "page={{page}}&size={{size}}",
|
|
149
|
+
getEntity: "",
|
|
150
|
+
updateEntity: "",
|
|
151
|
+
patchEntity: "",
|
|
152
|
+
deleteEntity: "",
|
|
153
|
+
}
|
|
154
|
+
await runTests("crud", testQuery, assertions)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const testParameters = async (file, extension, assertions) => {
|
|
158
|
+
const queries = await getQueries(file, extension)
|
|
159
|
+
for (let [operationId, parameters] of Object.entries(assertions)) {
|
|
160
|
+
expect(queries[operationId].parameters).toStrictEqual(parameters)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
it("populates parameters", async () => {
|
|
165
|
+
const assertions = {
|
|
166
|
+
createEntity: [],
|
|
167
|
+
getEntities: [
|
|
168
|
+
{
|
|
169
|
+
name: "page",
|
|
170
|
+
default: "",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "size",
|
|
174
|
+
default: "",
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
getEntity: [
|
|
178
|
+
{
|
|
179
|
+
name: "entityId",
|
|
180
|
+
default: "",
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
updateEntity: [
|
|
184
|
+
{
|
|
185
|
+
name: "entityId",
|
|
186
|
+
default: "",
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
patchEntity: [
|
|
190
|
+
{
|
|
191
|
+
name: "entityId",
|
|
192
|
+
default: "",
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
deleteEntity: [
|
|
196
|
+
{
|
|
197
|
+
name: "entityId",
|
|
198
|
+
default: "",
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
name: "x-api-key",
|
|
202
|
+
default: "",
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
}
|
|
206
|
+
await runTests("crud", testParameters, assertions)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
const testBody = async (file, extension, assertions) => {
|
|
210
|
+
const queries = await getQueries(file, extension)
|
|
211
|
+
for (let [operationId, body] of Object.entries(assertions)) {
|
|
212
|
+
expect(queries[operationId].fields.requestBody).toStrictEqual(
|
|
213
|
+
JSON.stringify(body, null, 2)
|
|
214
|
+
)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
it("populates body", async () => {
|
|
218
|
+
const assertions = {
|
|
219
|
+
createEntity: {
|
|
220
|
+
name: "name",
|
|
221
|
+
type: "type",
|
|
222
|
+
},
|
|
223
|
+
getEntities: undefined,
|
|
224
|
+
getEntity: undefined,
|
|
225
|
+
updateEntity: {
|
|
226
|
+
id: 1,
|
|
227
|
+
name: "name",
|
|
228
|
+
type: "type",
|
|
229
|
+
},
|
|
230
|
+
patchEntity: {
|
|
231
|
+
id: 1,
|
|
232
|
+
name: "name",
|
|
233
|
+
type: "type",
|
|
234
|
+
},
|
|
235
|
+
deleteEntity: undefined,
|
|
236
|
+
}
|
|
237
|
+
await runTests("crud", testBody, assertions)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
})
|
|
@@ -23,14 +23,27 @@ const oapi2CrudYaml = getData("openapi2/data/crud/crud.json")
|
|
|
23
23
|
const oapi2PetstoreJson = getData("openapi2/data/petstore/petstore.json")
|
|
24
24
|
const oapi2PetstoreYaml = getData("openapi2/data/petstore/petstore.json")
|
|
25
25
|
|
|
26
|
+
// openapi3
|
|
27
|
+
const oapi3CrudJson = getData("openapi3/data/crud/crud.json")
|
|
28
|
+
const oapi3CrudYaml = getData("openapi3/data/crud/crud.json")
|
|
29
|
+
const oapi3PetstoreJson = getData("openapi3/data/petstore/petstore.json")
|
|
30
|
+
const oapi3PetstoreYaml = getData("openapi3/data/petstore/petstore.json")
|
|
31
|
+
|
|
26
32
|
// curl
|
|
27
33
|
const curl = getData("curl/data/post.txt")
|
|
28
34
|
|
|
29
35
|
const datasets = {
|
|
36
|
+
// openapi2 (swagger)
|
|
30
37
|
oapi2CrudJson,
|
|
31
38
|
oapi2CrudYaml,
|
|
32
39
|
oapi2PetstoreJson,
|
|
33
40
|
oapi2PetstoreYaml,
|
|
41
|
+
// openapi3
|
|
42
|
+
oapi3CrudJson,
|
|
43
|
+
oapi3CrudYaml,
|
|
44
|
+
oapi3PetstoreJson,
|
|
45
|
+
oapi3PetstoreYaml,
|
|
46
|
+
// curl
|
|
34
47
|
curl
|
|
35
48
|
}
|
|
36
49
|
|
|
@@ -56,6 +69,7 @@ describe("Rest Importer", () => {
|
|
|
56
69
|
|
|
57
70
|
it("gets info", async () => {
|
|
58
71
|
const assertions = {
|
|
72
|
+
// openapi2 (swagger)
|
|
59
73
|
"oapi2CrudJson" : {
|
|
60
74
|
name: "CRUD",
|
|
61
75
|
},
|
|
@@ -68,6 +82,20 @@ describe("Rest Importer", () => {
|
|
|
68
82
|
"oapi2PetstoreYaml" :{
|
|
69
83
|
name: "Swagger Petstore",
|
|
70
84
|
},
|
|
85
|
+
// openapi3
|
|
86
|
+
"oapi3CrudJson" : {
|
|
87
|
+
name: "CRUD",
|
|
88
|
+
},
|
|
89
|
+
"oapi3CrudYaml" : {
|
|
90
|
+
name: "CRUD",
|
|
91
|
+
},
|
|
92
|
+
"oapi3PetstoreJson" : {
|
|
93
|
+
name: "Swagger Petstore - OpenAPI 3.0",
|
|
94
|
+
},
|
|
95
|
+
"oapi3PetstoreYaml" :{
|
|
96
|
+
name: "Swagger Petstore - OpenAPI 3.0",
|
|
97
|
+
},
|
|
98
|
+
// curl
|
|
71
99
|
"curl": {
|
|
72
100
|
name: "example.com",
|
|
73
101
|
}
|
|
@@ -89,6 +117,7 @@ describe("Rest Importer", () => {
|
|
|
89
117
|
// simple sanity assertions that the whole dataset
|
|
90
118
|
// makes it through the importer
|
|
91
119
|
const assertions = {
|
|
120
|
+
// openapi2 (swagger)
|
|
92
121
|
"oapi2CrudJson" : {
|
|
93
122
|
count: 6,
|
|
94
123
|
},
|
|
@@ -101,6 +130,20 @@ describe("Rest Importer", () => {
|
|
|
101
130
|
"oapi2PetstoreYaml" :{
|
|
102
131
|
count: 20,
|
|
103
132
|
},
|
|
133
|
+
// openapi3
|
|
134
|
+
"oapi3CrudJson" : {
|
|
135
|
+
count: 6,
|
|
136
|
+
},
|
|
137
|
+
"oapi3CrudYaml" :{
|
|
138
|
+
count: 6,
|
|
139
|
+
},
|
|
140
|
+
"oapi3PetstoreJson" : {
|
|
141
|
+
count: 19,
|
|
142
|
+
},
|
|
143
|
+
"oapi3PetstoreYaml" :{
|
|
144
|
+
count: 19,
|
|
145
|
+
},
|
|
146
|
+
// curl
|
|
104
147
|
"curl": {
|
|
105
148
|
count: 1
|
|
106
149
|
}
|
|
@@ -85,7 +85,11 @@ exports.patch = async ctx => {
|
|
|
85
85
|
const isUserTable = tableId === InternalTables.USER_METADATA
|
|
86
86
|
let oldRow
|
|
87
87
|
try {
|
|
88
|
-
|
|
88
|
+
let dbTable = await db.get(tableId)
|
|
89
|
+
oldRow = await outputProcessing(
|
|
90
|
+
dbTable,
|
|
91
|
+
await findRow(ctx, tableId, inputs._id)
|
|
92
|
+
)
|
|
89
93
|
} catch (err) {
|
|
90
94
|
if (isUserTable) {
|
|
91
95
|
// don't include the rev, it'll be the global rev
|
|
@@ -4,7 +4,7 @@ const controller = require("../controllers/analytics")
|
|
|
4
4
|
const router = Router()
|
|
5
5
|
|
|
6
6
|
router
|
|
7
|
-
.get("/api/
|
|
8
|
-
.post("/api/
|
|
7
|
+
.get("/api/bbtel", controller.isEnabled)
|
|
8
|
+
.post("/api/bbtel/ping", controller.endUserPing)
|
|
9
9
|
|
|
10
10
|
module.exports = router
|
|
@@ -11,10 +11,10 @@ describe("run misc tests", () => {
|
|
|
11
11
|
await config.init()
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
describe("/
|
|
14
|
+
describe("/bbtel", () => {
|
|
15
15
|
it("check if analytics enabled", async () => {
|
|
16
16
|
const res = await request
|
|
17
|
-
.get(`/api/
|
|
17
|
+
.get(`/api/bbtel`)
|
|
18
18
|
.set(config.defaultHeaders())
|
|
19
19
|
.expect("Content-Type", /json/)
|
|
20
20
|
.expect(200)
|
|
@@ -27,11 +27,8 @@ function parse(input: any) {
|
|
|
27
27
|
if (typeof input !== "string") {
|
|
28
28
|
return input
|
|
29
29
|
}
|
|
30
|
-
if (input === MAX_ISO_DATE) {
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
if (input === MIN_ISO_DATE) {
|
|
34
|
-
return new Date(-8640000000000000)
|
|
30
|
+
if (input === MAX_ISO_DATE || input === MIN_ISO_DATE) {
|
|
31
|
+
return null
|
|
35
32
|
}
|
|
36
33
|
if (isIsoDateString(input)) {
|
|
37
34
|
return new Date(input)
|
|
@@ -130,11 +127,19 @@ class InternalBuilder {
|
|
|
130
127
|
}
|
|
131
128
|
if (filters.range) {
|
|
132
129
|
iterate(filters.range, (key, value) => {
|
|
133
|
-
if (
|
|
134
|
-
|
|
130
|
+
if (value.low && value.high) {
|
|
131
|
+
// Use a between operator if we have 2 valid range values
|
|
132
|
+
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
|
133
|
+
query = query[fnc](key, [value.low, value.high])
|
|
134
|
+
} else if (value.low) {
|
|
135
|
+
// Use just a single greater than operator if we only have a low
|
|
136
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
137
|
+
query = query[fnc](key, ">", value.low)
|
|
138
|
+
} else if (value.high) {
|
|
139
|
+
// Use just a single less than operator if we only have a high
|
|
140
|
+
const fnc = allOr ? "orWhere" : "where"
|
|
141
|
+
query = query[fnc](key, "<", value.high)
|
|
135
142
|
}
|
|
136
|
-
const fnc = allOr ? "orWhereBetween" : "whereBetween"
|
|
137
|
-
query = query[fnc](key, [value.low, value.high])
|
|
138
143
|
})
|
|
139
144
|
}
|
|
140
145
|
if (filters.equal) {
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DatasourceFieldTypes,
|
|
3
|
+
Integration,
|
|
4
|
+
QueryTypes,
|
|
5
|
+
} from "../definitions/datasource"
|
|
6
|
+
import { IntegrationBase } from "./base/IntegrationBase"
|
|
7
|
+
import { Firestore, WhereFilterOp } from "@google-cloud/firestore"
|
|
8
|
+
|
|
9
|
+
module Firebase {
|
|
10
|
+
interface FirebaseConfig {
|
|
11
|
+
email: string
|
|
12
|
+
privateKey: string
|
|
13
|
+
projectId: string
|
|
14
|
+
serviceAccount?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const SCHEMA: Integration = {
|
|
18
|
+
docs: "https://firebase.google.com/docs/firestore/quickstart",
|
|
19
|
+
friendlyName: "Firestore",
|
|
20
|
+
description:
|
|
21
|
+
"Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
|
|
22
|
+
datasource: {
|
|
23
|
+
email: {
|
|
24
|
+
type: DatasourceFieldTypes.STRING,
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
privateKey: {
|
|
28
|
+
type: DatasourceFieldTypes.STRING,
|
|
29
|
+
required: true,
|
|
30
|
+
},
|
|
31
|
+
projectId: {
|
|
32
|
+
type: DatasourceFieldTypes.STRING,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
serviceAccount: {
|
|
36
|
+
type: DatasourceFieldTypes.JSON,
|
|
37
|
+
required: false,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
query: {
|
|
41
|
+
create: {
|
|
42
|
+
type: QueryTypes.JSON,
|
|
43
|
+
},
|
|
44
|
+
read: {
|
|
45
|
+
type: QueryTypes.JSON,
|
|
46
|
+
},
|
|
47
|
+
update: {
|
|
48
|
+
type: QueryTypes.JSON,
|
|
49
|
+
},
|
|
50
|
+
delete: {
|
|
51
|
+
type: QueryTypes.JSON,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
extra: {
|
|
55
|
+
collection: {
|
|
56
|
+
displayName: "Collection",
|
|
57
|
+
type: DatasourceFieldTypes.STRING,
|
|
58
|
+
required: true,
|
|
59
|
+
},
|
|
60
|
+
filterField: {
|
|
61
|
+
displayName: "Filter field",
|
|
62
|
+
type: DatasourceFieldTypes.STRING,
|
|
63
|
+
required: false,
|
|
64
|
+
},
|
|
65
|
+
filter: {
|
|
66
|
+
displayName: "Filter comparison",
|
|
67
|
+
type: DatasourceFieldTypes.LIST,
|
|
68
|
+
required: false,
|
|
69
|
+
data: {
|
|
70
|
+
read: [
|
|
71
|
+
"==",
|
|
72
|
+
"<",
|
|
73
|
+
"<=",
|
|
74
|
+
"==",
|
|
75
|
+
"!=",
|
|
76
|
+
">=",
|
|
77
|
+
">",
|
|
78
|
+
"array-contains",
|
|
79
|
+
"in",
|
|
80
|
+
"not-in",
|
|
81
|
+
"array-contains-any",
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
filterValue: {
|
|
86
|
+
displayName: "Filter value",
|
|
87
|
+
type: DatasourceFieldTypes.STRING,
|
|
88
|
+
required: false,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
class FirebaseIntegration implements IntegrationBase {
|
|
94
|
+
private config: FirebaseConfig
|
|
95
|
+
private db: Firestore
|
|
96
|
+
|
|
97
|
+
constructor(config: FirebaseConfig) {
|
|
98
|
+
this.config = config
|
|
99
|
+
if (config.serviceAccount) {
|
|
100
|
+
const serviceAccount = JSON.parse(config.serviceAccount)
|
|
101
|
+
this.db = new Firestore({
|
|
102
|
+
projectId: serviceAccount.project_id,
|
|
103
|
+
credentials: {
|
|
104
|
+
client_email: serviceAccount.client_email,
|
|
105
|
+
private_key: serviceAccount.private_key,
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
} else {
|
|
109
|
+
this.db = new Firestore({
|
|
110
|
+
projectId: config.projectId,
|
|
111
|
+
credentials: {
|
|
112
|
+
client_email: config.email,
|
|
113
|
+
private_key: config.privateKey,
|
|
114
|
+
},
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async create(query: { json: object; extra: { [key: string]: string } }) {
|
|
120
|
+
try {
|
|
121
|
+
const documentReference = this.db
|
|
122
|
+
.collection(query.extra.collection)
|
|
123
|
+
.doc()
|
|
124
|
+
await documentReference.set({ ...query.json, id: documentReference.id })
|
|
125
|
+
const snapshot = await documentReference.get()
|
|
126
|
+
return snapshot.data()
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error("Error writing to Firestore", err)
|
|
129
|
+
throw err
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async read(query: { json: object; extra: { [key: string]: string } }) {
|
|
134
|
+
try {
|
|
135
|
+
let snapshot
|
|
136
|
+
const collectionRef = this.db.collection(query.extra.collection)
|
|
137
|
+
if (
|
|
138
|
+
query.extra.filterField &&
|
|
139
|
+
query.extra.filter &&
|
|
140
|
+
query.extra.filterValue
|
|
141
|
+
) {
|
|
142
|
+
snapshot = await collectionRef
|
|
143
|
+
.where(
|
|
144
|
+
query.extra.filterField,
|
|
145
|
+
query.extra.filter as WhereFilterOp,
|
|
146
|
+
query.extra.filterValue
|
|
147
|
+
)
|
|
148
|
+
.get()
|
|
149
|
+
} else {
|
|
150
|
+
snapshot = await collectionRef.get()
|
|
151
|
+
}
|
|
152
|
+
const result: any[] = []
|
|
153
|
+
snapshot.forEach(doc => result.push(doc.data()))
|
|
154
|
+
|
|
155
|
+
return result
|
|
156
|
+
} catch (err) {
|
|
157
|
+
console.error("Error querying Firestore", err)
|
|
158
|
+
throw err
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async update(query: {
|
|
163
|
+
json: Record<string, any>
|
|
164
|
+
extra: { [key: string]: string }
|
|
165
|
+
}) {
|
|
166
|
+
try {
|
|
167
|
+
await this.db
|
|
168
|
+
.collection(query.extra.collection)
|
|
169
|
+
.doc(query.json.id)
|
|
170
|
+
.update(query.json)
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
await this.db
|
|
174
|
+
.collection(query.extra.collection)
|
|
175
|
+
.doc(query.json.id)
|
|
176
|
+
.get()
|
|
177
|
+
).data()
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.error("Error writing to firebase", err)
|
|
180
|
+
throw err
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async delete(query: {
|
|
185
|
+
json: { id: string }
|
|
186
|
+
extra: { [key: string]: string }
|
|
187
|
+
}) {
|
|
188
|
+
try {
|
|
189
|
+
await this.db
|
|
190
|
+
.collection(query.extra.collection)
|
|
191
|
+
.doc(query.json.id)
|
|
192
|
+
.delete()
|
|
193
|
+
return true
|
|
194
|
+
} catch (err) {
|
|
195
|
+
console.error("Error writing to mongodb", err)
|
|
196
|
+
throw err
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = {
|
|
202
|
+
schema: SCHEMA,
|
|
203
|
+
integration: FirebaseIntegration,
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -10,6 +10,7 @@ const mysql = require("./mysql")
|
|
|
10
10
|
const arangodb = require("./arangodb")
|
|
11
11
|
const rest = require("./rest")
|
|
12
12
|
const googlesheets = require("./googlesheets")
|
|
13
|
+
const firebase = require("./firebase")
|
|
13
14
|
const { SourceNames } = require("../definitions/datasource")
|
|
14
15
|
const environment = require("../environment")
|
|
15
16
|
|
|
@@ -25,6 +26,7 @@ const DEFINITIONS = {
|
|
|
25
26
|
[SourceNames.MYSQL]: mysql.schema,
|
|
26
27
|
[SourceNames.ARANGODB]: arangodb.schema,
|
|
27
28
|
[SourceNames.REST]: rest.schema,
|
|
29
|
+
[SourceNames.FIREBASE]: firebase.schema,
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
const INTEGRATIONS = {
|
|
@@ -39,6 +41,7 @@ const INTEGRATIONS = {
|
|
|
39
41
|
[SourceNames.MYSQL]: mysql.integration,
|
|
40
42
|
[SourceNames.ARANGODB]: arangodb.integration,
|
|
41
43
|
[SourceNames.REST]: rest.integration,
|
|
44
|
+
[SourceNames.FIREBASE]: firebase.integration,
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
// optionally add oracle integration if the oracle binary can be installed
|
|
@@ -187,4 +187,55 @@ describe("SQL query builder", () => {
|
|
|
187
187
|
sql: `select * from (select * from \`${TABLE_NAME}\` limit ?) as \`${TABLE_NAME}\``
|
|
188
188
|
})
|
|
189
189
|
})
|
|
190
|
+
|
|
191
|
+
it("should use greater than when only low range specified", () => {
|
|
192
|
+
const date = new Date()
|
|
193
|
+
const query = sql._query(generateReadJson({
|
|
194
|
+
filters: {
|
|
195
|
+
range: {
|
|
196
|
+
property: {
|
|
197
|
+
low: date,
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}))
|
|
202
|
+
expect(query).toEqual({
|
|
203
|
+
bindings: [date, limit],
|
|
204
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"`
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
it("should use less than when only high range specified", () => {
|
|
209
|
+
const date = new Date()
|
|
210
|
+
const query = sql._query(generateReadJson({
|
|
211
|
+
filters: {
|
|
212
|
+
range: {
|
|
213
|
+
property: {
|
|
214
|
+
high: date,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}))
|
|
219
|
+
expect(query).toEqual({
|
|
220
|
+
bindings: [date, limit],
|
|
221
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" < $1 limit $2) as "${TABLE_NAME}"`
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it("should use greater than when only low range specified", () => {
|
|
226
|
+
const date = new Date()
|
|
227
|
+
const query = sql._query(generateReadJson({
|
|
228
|
+
filters: {
|
|
229
|
+
range: {
|
|
230
|
+
property: {
|
|
231
|
+
low: date,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}))
|
|
236
|
+
expect(query).toEqual({
|
|
237
|
+
bindings: [date, limit],
|
|
238
|
+
sql: `select * from (select * from "${TABLE_NAME}" where "${TABLE_NAME}"."property" > $1 limit $2) as "${TABLE_NAME}"`
|
|
239
|
+
})
|
|
240
|
+
})
|
|
190
241
|
})
|