@budibase/server 0.9.140-alpha.4 → 0.9.140-alpha.5
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.2bcd18f5.js → index.80d850d1.js} +1 -1
- package/builder/index.html +1 -1
- package/coverage/clover.xml +646 -528
- package/coverage/coverage-final.json +17 -15
- 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/component.js.html +1 -1
- package/coverage/lcov-report/api/controllers/datasource.js.html +3 -3
- package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
- package/coverage/lcov-report/api/controllers/hosting.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/permission.js.html +1 -1
- package/coverage/lcov-report/api/controllers/query.js.html +1 -1
- 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 +19 -19
- package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/internal.js.html +242 -47
- package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
- package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
- 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/index.html +1 -1
- package/coverage/lcov-report/api/controllers/table/index.js.html +2 -2
- package/coverage/lcov-report/api/controllers/table/utils.js.html +31 -19
- 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 +32 -17
- package/coverage/lcov-report/api/controllers/view/index.js.html +84 -186
- package/coverage/lcov-report/api/controllers/view/utils.js.html +407 -0
- 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 +1 -1
- 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/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/hosting.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/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/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 +10 -19
- package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
- package/coverage/lcov-report/automations/steps/deleteRow.js.html +14 -20
- 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 +31 -31
- 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 +18 -27
- 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 +12 -21
- package/coverage/lcov-report/automations/steps/utils.js.html +23 -23
- package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
- package/coverage/lcov-report/automations/thread.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 +224 -0
- package/coverage/lcov-report/db/index.html +34 -19
- package/coverage/lcov-report/db/index.js.html +1 -1
- package/coverage/lcov-report/db/linkedRows/LinkController.js.html +4 -4
- package/coverage/lcov-report/db/linkedRows/index.html +14 -14
- package/coverage/lcov-report/db/linkedRows/index.js.html +18 -9
- package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
- package/coverage/lcov-report/db/newid.js.html +1 -1
- package/coverage/lcov-report/db/utils.js.html +37 -10
- 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 +65 -65
- 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/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/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 +15 -15
- package/coverage/lcov-report/utilities/rowProcessor/index.js.html +58 -13
- package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
- package/coverage/lcov-report/utilities/security.js.html +2 -2
- package/coverage/lcov-report/utilities/statusCodes.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 +1093 -883
- package/dist/api/controllers/datasource.js +2 -2
- package/dist/api/controllers/row/ExternalRequest.js +4 -0
- package/dist/api/controllers/row/internal.js +97 -23
- package/dist/api/controllers/table/index.js +1 -1
- package/dist/api/controllers/table/utils.js +13 -11
- package/dist/api/controllers/view/index.js +74 -96
- package/dist/api/controllers/view/utils.js +102 -0
- package/dist/automations/steps/createRow.js +5 -8
- package/dist/automations/steps/deleteRow.js +7 -10
- package/dist/automations/steps/queryRows.js +11 -14
- package/dist/automations/steps/updateRow.js +4 -7
- package/dist/db/inMemoryView.js +51 -0
- package/dist/db/linkedRows/index.js +5 -2
- package/dist/db/utils.js +7 -0
- package/dist/environment.js +7 -1
- package/dist/integrations/mysql.js +2 -13
- package/dist/integrations/postgres.js +8 -14
- package/dist/integrations/utils.js +19 -1
- package/dist/package.json +5 -5
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utilities/rowProcessor/index.js +10 -5
- package/package.json +6 -6
- package/scripts/integrations/service-vehicles/docker-compose.yml +28 -0
- package/scripts/integrations/service-vehicles/init.sql +52 -0
- package/scripts/integrations/service-vehicles/reset.sh +3 -0
- package/src/api/controllers/datasource.js +2 -2
- package/src/api/controllers/row/ExternalRequest.ts +5 -1
- package/src/api/controllers/row/internal.js +88 -23
- package/src/api/controllers/table/index.js +1 -1
- package/src/api/controllers/table/utils.js +16 -12
- package/src/api/controllers/view/index.js +82 -116
- package/src/api/controllers/view/utils.js +109 -0
- package/src/api/routes/tests/view.spec.js +1 -1
- package/src/automations/steps/createRow.js +5 -8
- package/src/automations/steps/deleteRow.js +8 -10
- package/src/automations/steps/queryRows.js +11 -14
- package/src/automations/steps/updateRow.js +7 -10
- package/src/db/inMemoryView.js +48 -0
- package/src/db/linkedRows/index.js +5 -2
- package/src/db/utils.js +9 -0
- package/src/environment.js +8 -1
- package/src/integrations/mysql.ts +2 -13
- package/src/integrations/postgres.ts +9 -16
- package/src/integrations/utils.ts +18 -0
- package/src/utilities/rowProcessor/index.js +20 -5
|
@@ -96,10 +96,11 @@ const TYPE_TRANSFORM_MAP = {
|
|
|
96
96
|
* @param {Object} user The user to be used for an appId as well as the createdBy and createdAt fields.
|
|
97
97
|
* @param {Object} table The table which is to be used for the schema, as well as handling auto IDs incrementing.
|
|
98
98
|
* @param {Object} row The row which is to be updated with information for the auto columns.
|
|
99
|
+
* @param {Object} opts specific options for function to carry out optional features.
|
|
99
100
|
* @returns {{row: Object, table: Object}} The updated row and table, the table may need to be updated
|
|
100
101
|
* for automatic ID purposes.
|
|
101
102
|
*/
|
|
102
|
-
function processAutoColumn(user, table, row) {
|
|
103
|
+
function processAutoColumn(user, table, row, opts = { reprocessing: false, noAutoRelationships: false }) {
|
|
103
104
|
let now = new Date().toISOString();
|
|
104
105
|
// if a row doesn't have a revision then it doesn't exist yet
|
|
105
106
|
const creating = !row._rev;
|
|
@@ -109,7 +110,7 @@ function processAutoColumn(user, table, row) {
|
|
|
109
110
|
}
|
|
110
111
|
switch (schema.subtype) {
|
|
111
112
|
case AutoFieldSubTypes.CREATED_BY:
|
|
112
|
-
if (creating) {
|
|
113
|
+
if (creating && !opts.reprocessing && !opts.noAutoRelationships) {
|
|
113
114
|
row[key] = [user.userId];
|
|
114
115
|
}
|
|
115
116
|
break;
|
|
@@ -119,7 +120,9 @@ function processAutoColumn(user, table, row) {
|
|
|
119
120
|
}
|
|
120
121
|
break;
|
|
121
122
|
case AutoFieldSubTypes.UPDATED_BY:
|
|
122
|
-
|
|
123
|
+
if (!opts.reprocessing && !opts.noAutoRelationships) {
|
|
124
|
+
row[key] = [user.userId];
|
|
125
|
+
}
|
|
123
126
|
break;
|
|
124
127
|
case AutoFieldSubTypes.UPDATED_AT:
|
|
125
128
|
row[key] = now;
|
|
@@ -134,6 +137,7 @@ function processAutoColumn(user, table, row) {
|
|
|
134
137
|
}
|
|
135
138
|
return { table, row };
|
|
136
139
|
}
|
|
140
|
+
exports.processAutoColumn = processAutoColumn;
|
|
137
141
|
/**
|
|
138
142
|
* This will coerce a value to the correct types based on the type transform map
|
|
139
143
|
* @param {object} row The value to coerce
|
|
@@ -156,9 +160,10 @@ exports.coerce = (row, type) => {
|
|
|
156
160
|
* @param {object} user the user which is performing the input.
|
|
157
161
|
* @param {object} row the row which is being created/updated.
|
|
158
162
|
* @param {object} table the table which the row is being saved to.
|
|
163
|
+
* @param {object} opts some input processing options (like disabling auto-column relationships).
|
|
159
164
|
* @returns {object} the row which has been prepared to be written to the DB.
|
|
160
165
|
*/
|
|
161
|
-
exports.inputProcessing = (user = {}, table, row) => {
|
|
166
|
+
exports.inputProcessing = (user = {}, table, row, opts = { noAutoRelationships: false }) => {
|
|
162
167
|
let clonedRow = cloneDeep(row);
|
|
163
168
|
// need to copy the table so it can be differenced on way out
|
|
164
169
|
const copiedTable = cloneDeep(table);
|
|
@@ -182,7 +187,7 @@ exports.inputProcessing = (user = {}, table, row) => {
|
|
|
182
187
|
}
|
|
183
188
|
}
|
|
184
189
|
// handle auto columns - this returns an object like {table, row}
|
|
185
|
-
return processAutoColumn(user, copiedTable, clonedRow);
|
|
190
|
+
return processAutoColumn(user, copiedTable, clonedRow, opts);
|
|
186
191
|
};
|
|
187
192
|
/**
|
|
188
193
|
* This function enriches the input rows with anything they are supposed to contain, for example
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@budibase/server",
|
|
3
3
|
"email": "hi@budibase.com",
|
|
4
|
-
"version": "0.9.140-alpha.
|
|
4
|
+
"version": "0.9.140-alpha.5",
|
|
5
5
|
"description": "Budibase Web Server",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"repository": {
|
|
@@ -62,9 +62,9 @@
|
|
|
62
62
|
"author": "Budibase",
|
|
63
63
|
"license": "AGPL-3.0-or-later",
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@budibase/auth": "^0.9.140-alpha.
|
|
66
|
-
"@budibase/client": "^0.9.140-alpha.
|
|
67
|
-
"@budibase/string-templates": "^0.9.140-alpha.
|
|
65
|
+
"@budibase/auth": "^0.9.140-alpha.5",
|
|
66
|
+
"@budibase/client": "^0.9.140-alpha.5",
|
|
67
|
+
"@budibase/string-templates": "^0.9.140-alpha.5",
|
|
68
68
|
"@elastic/elasticsearch": "7.10.0",
|
|
69
69
|
"@koa/router": "8.0.0",
|
|
70
70
|
"@sendgrid/mail": "7.1.1",
|
|
@@ -102,6 +102,7 @@
|
|
|
102
102
|
"pg": "8.5.1",
|
|
103
103
|
"pino-pretty": "4.0.0",
|
|
104
104
|
"pouchdb": "7.2.1",
|
|
105
|
+
"pouchdb-adapter-memory": "^7.2.1",
|
|
105
106
|
"pouchdb-all-dbs": "1.0.2",
|
|
106
107
|
"pouchdb-find": "^7.2.2",
|
|
107
108
|
"pouchdb-replication-stream": "1.2.9",
|
|
@@ -131,7 +132,6 @@
|
|
|
131
132
|
"express": "^4.17.1",
|
|
132
133
|
"jest": "^27.0.5",
|
|
133
134
|
"nodemon": "^2.0.4",
|
|
134
|
-
"pouchdb-adapter-memory": "^7.2.1",
|
|
135
135
|
"prettier": "^2.3.1",
|
|
136
136
|
"rimraf": "^3.0.2",
|
|
137
137
|
"supertest": "^4.0.2",
|
|
@@ -140,5 +140,5 @@
|
|
|
140
140
|
"typescript": "^4.3.5",
|
|
141
141
|
"update-dotenv": "^1.1.1"
|
|
142
142
|
},
|
|
143
|
-
"gitHead": "
|
|
143
|
+
"gitHead": "15cd5e45144b43db3af75d58bbe695dc497b7cbd"
|
|
144
144
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: "3.8"
|
|
2
|
+
services:
|
|
3
|
+
db:
|
|
4
|
+
container_name: postgres-vehicle
|
|
5
|
+
image: postgres
|
|
6
|
+
restart: always
|
|
7
|
+
environment:
|
|
8
|
+
POSTGRES_USER: root
|
|
9
|
+
POSTGRES_PASSWORD: root
|
|
10
|
+
POSTGRES_DB: main
|
|
11
|
+
ports:
|
|
12
|
+
- "5432:5432"
|
|
13
|
+
volumes:
|
|
14
|
+
#- pg_data:/var/lib/postgresql/data/
|
|
15
|
+
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
|
16
|
+
|
|
17
|
+
pgadmin:
|
|
18
|
+
container_name: pgadmin
|
|
19
|
+
image: dpage/pgadmin4
|
|
20
|
+
restart: always
|
|
21
|
+
environment:
|
|
22
|
+
PGADMIN_DEFAULT_EMAIL: root@root.com
|
|
23
|
+
PGADMIN_DEFAULT_PASSWORD: root
|
|
24
|
+
ports:
|
|
25
|
+
- "5050:80"
|
|
26
|
+
|
|
27
|
+
#volumes:
|
|
28
|
+
# pg_data:
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
SELECT 'CREATE DATABASE main'
|
|
2
|
+
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'main')\gexec
|
|
3
|
+
CREATE TABLE Vehicles (
|
|
4
|
+
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
|
|
5
|
+
Registration text COLLATE pg_catalog."default",
|
|
6
|
+
Make text COLLATE pg_catalog."default",
|
|
7
|
+
Model text COLLATE pg_catalog."default",
|
|
8
|
+
Colour text COLLATE pg_catalog."default",
|
|
9
|
+
Year smallint,
|
|
10
|
+
CONSTRAINT Vehicles_pkey PRIMARY KEY (id)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE ServiceLog (
|
|
14
|
+
id bigint NOT NULL GENERATED ALWAYS AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1 ),
|
|
15
|
+
Description text COLLATE pg_catalog."default",
|
|
16
|
+
VehicleId bigint,
|
|
17
|
+
ServiceDate timestamp without time zone,
|
|
18
|
+
Category text COLLATE pg_catalog."default",
|
|
19
|
+
Mileage bigint,
|
|
20
|
+
CONSTRAINT ServiceLog_pkey PRIMARY KEY (id),
|
|
21
|
+
CONSTRAINT vehicle_foreign_key FOREIGN KEY (VehicleId)
|
|
22
|
+
REFERENCES Vehicles (id) MATCH SIMPLE
|
|
23
|
+
ON UPDATE NO ACTION
|
|
24
|
+
ON DELETE NO ACTION
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
28
|
+
VALUES ('FAZ 9837','Volkswagen','Polo','White',2002);
|
|
29
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
30
|
+
VALUES ('JHI 8827','BMW','M3','Black',2013);
|
|
31
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
32
|
+
VALUES ('D903PI','Volvo','XC40','Grey',2014);
|
|
33
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
34
|
+
VALUES ('YFI002','Volkswagen','Golf','Dark Blue',2018);
|
|
35
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
36
|
+
VALUES ('HGT5677','Skoda','Octavia','Graphite',2009);
|
|
37
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
38
|
+
VALUES ('PPF9276','Skoda','Octavia','Graphite',2021);
|
|
39
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
40
|
+
VALUES ('J893FT','Toyota','Corolla','Red',2015);
|
|
41
|
+
INSERT INTO Vehicles (Registration, Make, Model, Colour, Year)
|
|
42
|
+
VALUES ('MJK776','Honda','HR-V','Silver',2015);
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
INSERT INTO ServiceLog (Description, VehicleId, ServiceDate, Category, Mileage)
|
|
46
|
+
VALUES ('Change front brakes', 1, '2021-05-04', 'Brakes', 20667);
|
|
47
|
+
INSERT INTO ServiceLog (Description, VehicleId, ServiceDate, Category, Mileage)
|
|
48
|
+
VALUES ('Tyres - full set', 1, '2021-05-04', 'Brakes', 20667);
|
|
49
|
+
INSERT INTO ServiceLog (Description, VehicleId, ServiceDate, Category, Mileage)
|
|
50
|
+
VALUES ('Engine tune up', 2, '2021-07-14', 'Brakes', 50889);
|
|
51
|
+
INSERT INTO ServiceLog (Description, VehicleId, ServiceDate, Category, Mileage)
|
|
52
|
+
VALUES ('Replace transmission', 3, '2021-09-26', 'Transmission', 98002);
|
|
@@ -51,7 +51,7 @@ exports.buildSchemaFromDb = async function (ctx) {
|
|
|
51
51
|
await connector.buildSchema(datasource._id, datasource.entities)
|
|
52
52
|
datasource.entities = connector.tables
|
|
53
53
|
|
|
54
|
-
const response = await db.
|
|
54
|
+
const response = await db.put(datasource)
|
|
55
55
|
datasource._rev = response.rev
|
|
56
56
|
|
|
57
57
|
ctx.body = datasource
|
|
@@ -89,7 +89,7 @@ exports.save = async function (ctx) {
|
|
|
89
89
|
...ctx.request.body,
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
const response = await db.
|
|
92
|
+
const response = await db.put(datasource)
|
|
93
93
|
datasource._rev = response.rev
|
|
94
94
|
|
|
95
95
|
// Drain connection pools when configuration is changed
|
|
@@ -437,7 +437,11 @@ module External {
|
|
|
437
437
|
for (let [colName, { isMany, rows, tableId }] of Object.entries(
|
|
438
438
|
related
|
|
439
439
|
)) {
|
|
440
|
-
const table = this.getTable(tableId)
|
|
440
|
+
const table: Table = this.getTable(tableId)
|
|
441
|
+
// if its not the foreign key skip it, nothing to do
|
|
442
|
+
if (table.primary && table.primary.indexOf(colName) !== -1) {
|
|
443
|
+
continue
|
|
444
|
+
}
|
|
441
445
|
for (let row of rows) {
|
|
442
446
|
const filters = buildFilters(generateIdForRow(row, table), {}, table)
|
|
443
447
|
// safety check, if there are no filters on deletion bad things happen
|
|
@@ -5,17 +5,22 @@ const {
|
|
|
5
5
|
generateRowID,
|
|
6
6
|
DocumentTypes,
|
|
7
7
|
InternalTables,
|
|
8
|
+
generateMemoryViewID,
|
|
8
9
|
} = require("../../../db/utils")
|
|
9
10
|
const userController = require("../user")
|
|
10
11
|
const {
|
|
11
12
|
inputProcessing,
|
|
12
13
|
outputProcessing,
|
|
14
|
+
processAutoColumn,
|
|
13
15
|
} = require("../../../utilities/rowProcessor")
|
|
14
16
|
const { FieldTypes } = require("../../../constants")
|
|
15
17
|
const { isEqual } = require("lodash")
|
|
16
18
|
const { validate, findRow } = require("./utils")
|
|
17
19
|
const { fullSearch, paginatedSearch } = require("./internalSearch")
|
|
18
20
|
const { getGlobalUsersFromMetadata } = require("../../../utilities/global")
|
|
21
|
+
const inMemoryViews = require("../../../db/inMemoryView")
|
|
22
|
+
const env = require("../../../environment")
|
|
23
|
+
const { migrateToInMemoryView } = require("../view/utils")
|
|
19
24
|
|
|
20
25
|
const CALCULATION_TYPES = {
|
|
21
26
|
SUM: "sum",
|
|
@@ -25,17 +30,84 @@ const CALCULATION_TYPES = {
|
|
|
25
30
|
|
|
26
31
|
async function storeResponse(ctx, db, row, oldTable, table) {
|
|
27
32
|
row.type = "row"
|
|
28
|
-
const response = await db.put(row)
|
|
29
33
|
// don't worry about rev, tables handle rev/lastID updates
|
|
34
|
+
// if another row has been written since processing this will
|
|
35
|
+
// handle the auto ID clash
|
|
30
36
|
if (!isEqual(oldTable, table)) {
|
|
31
|
-
|
|
37
|
+
try {
|
|
38
|
+
await db.put(table)
|
|
39
|
+
} catch (err) {
|
|
40
|
+
if (err.status === 409) {
|
|
41
|
+
const updatedTable = await db.get(table._id)
|
|
42
|
+
let response = processAutoColumn(null, updatedTable, row, {
|
|
43
|
+
reprocessing: true,
|
|
44
|
+
})
|
|
45
|
+
await db.put(response.table)
|
|
46
|
+
row = response.row
|
|
47
|
+
} else {
|
|
48
|
+
throw err
|
|
49
|
+
}
|
|
50
|
+
}
|
|
32
51
|
}
|
|
52
|
+
const response = await db.put(row)
|
|
33
53
|
row._rev = response.rev
|
|
34
54
|
// process the row before return, to include relationships
|
|
35
55
|
row = await outputProcessing(ctx, table, row, { squash: false })
|
|
36
56
|
return { row, table }
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
// doesn't do the outputProcessing
|
|
60
|
+
async function getRawTableData(ctx, db, tableId) {
|
|
61
|
+
let rows
|
|
62
|
+
if (tableId === InternalTables.USER_METADATA) {
|
|
63
|
+
await userController.fetchMetadata(ctx)
|
|
64
|
+
rows = ctx.body
|
|
65
|
+
} else {
|
|
66
|
+
const response = await db.allDocs(
|
|
67
|
+
getRowParams(tableId, null, {
|
|
68
|
+
include_docs: true,
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
rows = response.rows.map(row => row.doc)
|
|
72
|
+
}
|
|
73
|
+
return rows
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function getView(db, viewName) {
|
|
77
|
+
let viewInfo
|
|
78
|
+
async function getFromDesignDoc() {
|
|
79
|
+
const designDoc = await db.get("_design/database")
|
|
80
|
+
viewInfo = designDoc.views[viewName]
|
|
81
|
+
return viewInfo
|
|
82
|
+
}
|
|
83
|
+
let migrate = false
|
|
84
|
+
if (env.SELF_HOSTED) {
|
|
85
|
+
viewInfo = await getFromDesignDoc()
|
|
86
|
+
} else {
|
|
87
|
+
try {
|
|
88
|
+
viewInfo = await db.get(generateMemoryViewID(viewName))
|
|
89
|
+
if (viewInfo) {
|
|
90
|
+
viewInfo = viewInfo.view
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
// check if it can be retrieved from design doc (needs migrated)
|
|
94
|
+
if (err.status !== 404) {
|
|
95
|
+
viewInfo = null
|
|
96
|
+
} else {
|
|
97
|
+
viewInfo = await getFromDesignDoc()
|
|
98
|
+
migrate = !!viewInfo
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (migrate) {
|
|
103
|
+
await migrateToInMemoryView(db, viewName)
|
|
104
|
+
}
|
|
105
|
+
if (!viewInfo) {
|
|
106
|
+
throw "View does not exist."
|
|
107
|
+
}
|
|
108
|
+
return viewInfo
|
|
109
|
+
}
|
|
110
|
+
|
|
39
111
|
exports.patch = async ctx => {
|
|
40
112
|
const appId = ctx.appId
|
|
41
113
|
const db = new CouchDB(appId)
|
|
@@ -139,15 +211,18 @@ exports.fetchView = async ctx => {
|
|
|
139
211
|
|
|
140
212
|
const db = new CouchDB(appId)
|
|
141
213
|
const { calculation, group, field } = ctx.query
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
if (
|
|
145
|
-
|
|
214
|
+
const viewInfo = await getView(db, viewName)
|
|
215
|
+
let response
|
|
216
|
+
if (env.SELF_HOSTED) {
|
|
217
|
+
response = await db.query(`database/${viewName}`, {
|
|
218
|
+
include_docs: !calculation,
|
|
219
|
+
group: !!group,
|
|
220
|
+
})
|
|
221
|
+
} else {
|
|
222
|
+
const tableId = viewInfo.meta.tableId
|
|
223
|
+
const data = await getRawTableData(ctx, db, tableId)
|
|
224
|
+
response = await inMemoryViews.runView(viewInfo, calculation, group, data)
|
|
146
225
|
}
|
|
147
|
-
const response = await db.query(`database/${viewName}`, {
|
|
148
|
-
include_docs: !calculation,
|
|
149
|
-
group: !!group,
|
|
150
|
-
})
|
|
151
226
|
|
|
152
227
|
let rows
|
|
153
228
|
if (!calculation) {
|
|
@@ -191,19 +266,9 @@ exports.fetch = async ctx => {
|
|
|
191
266
|
const appId = ctx.appId
|
|
192
267
|
const db = new CouchDB(appId)
|
|
193
268
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
await userController.fetchMetadata(ctx)
|
|
198
|
-
rows = ctx.body
|
|
199
|
-
} else {
|
|
200
|
-
const response = await db.allDocs(
|
|
201
|
-
getRowParams(ctx.params.tableId, null, {
|
|
202
|
-
include_docs: true,
|
|
203
|
-
})
|
|
204
|
-
)
|
|
205
|
-
rows = response.rows.map(row => row.doc)
|
|
206
|
-
}
|
|
269
|
+
const tableId = ctx.params.tableId
|
|
270
|
+
let table = await db.get(tableId)
|
|
271
|
+
let rows = await getRawTableData(ctx, db, tableId)
|
|
207
272
|
return outputProcessing(ctx, table, rows)
|
|
208
273
|
}
|
|
209
274
|
|
|
@@ -145,7 +145,7 @@ exports.save = async function (ctx) {
|
|
|
145
145
|
if (updatedRows && updatedRows.length !== 0) {
|
|
146
146
|
await db.bulkDocs(updatedRows)
|
|
147
147
|
}
|
|
148
|
-
const result = await db.
|
|
148
|
+
const result = await db.put(tableToSave)
|
|
149
149
|
tableToSave._rev = result.rev
|
|
150
150
|
|
|
151
151
|
tableToSave = await tableSaveFunctions.after(tableToSave)
|
|
@@ -68,23 +68,17 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
|
|
68
68
|
// Populate the table with rows imported from CSV in a bulk update
|
|
69
69
|
const data = await csvParser.transform(dataImport)
|
|
70
70
|
|
|
71
|
+
let finalData = []
|
|
71
72
|
for (let i = 0; i < data.length; i++) {
|
|
72
73
|
let row = data[i]
|
|
73
74
|
row._id = generateRowID(table._id)
|
|
74
75
|
row.tableId = table._id
|
|
75
|
-
const processed = inputProcessing(user, table, row
|
|
76
|
+
const processed = inputProcessing(user, table, row, {
|
|
77
|
+
noAutoRelationships: true,
|
|
78
|
+
})
|
|
76
79
|
table = processed.table
|
|
77
80
|
row = processed.row
|
|
78
81
|
|
|
79
|
-
// make sure link rows are up to date
|
|
80
|
-
row = await linkRows.updateLinks({
|
|
81
|
-
appId,
|
|
82
|
-
eventType: linkRows.EventType.ROW_SAVE,
|
|
83
|
-
row,
|
|
84
|
-
tableId: row.tableId,
|
|
85
|
-
table,
|
|
86
|
-
})
|
|
87
|
-
|
|
88
82
|
for (let [fieldName, schema] of Object.entries(table.schema)) {
|
|
89
83
|
// check whether the options need to be updated for inclusion as part of the data import
|
|
90
84
|
if (
|
|
@@ -98,10 +92,20 @@ exports.handleDataImport = async (appId, user, table, dataImport) => {
|
|
|
98
92
|
]
|
|
99
93
|
}
|
|
100
94
|
}
|
|
101
|
-
|
|
95
|
+
|
|
96
|
+
// make sure link rows are up to date
|
|
97
|
+
finalData.push(
|
|
98
|
+
linkRows.updateLinks({
|
|
99
|
+
appId,
|
|
100
|
+
eventType: linkRows.EventType.ROW_SAVE,
|
|
101
|
+
row,
|
|
102
|
+
tableId: row.tableId,
|
|
103
|
+
table,
|
|
104
|
+
})
|
|
105
|
+
)
|
|
102
106
|
}
|
|
103
107
|
|
|
104
|
-
await db.bulkDocs(
|
|
108
|
+
await db.bulkDocs(await Promise.all(finalData))
|
|
105
109
|
let response = await db.put(table)
|
|
106
110
|
table._rev = response._rev
|
|
107
111
|
}
|
|
@@ -2,127 +2,93 @@ const CouchDB = require("../../../db")
|
|
|
2
2
|
const viewTemplate = require("./viewBuilder")
|
|
3
3
|
const { apiFileReturn } = require("../../../utilities/fileSystem")
|
|
4
4
|
const exporters = require("./exporters")
|
|
5
|
+
const { saveView, getView, getViews, deleteView } = require("./utils")
|
|
5
6
|
const { fetchView } = require("../row")
|
|
6
|
-
const { ViewNames } = require("../../../db/utils")
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const response = []
|
|
13
|
-
|
|
14
|
-
for (let name of Object.keys(designDoc.views)) {
|
|
15
|
-
// Only return custom views, not built ins
|
|
16
|
-
if (Object.values(ViewNames).indexOf(name) !== -1) {
|
|
17
|
-
continue
|
|
18
|
-
}
|
|
19
|
-
response.push({
|
|
20
|
-
name,
|
|
21
|
-
...designDoc.views[name],
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
ctx.body = response
|
|
26
|
-
},
|
|
27
|
-
save: async ctx => {
|
|
28
|
-
const db = new CouchDB(ctx.appId)
|
|
29
|
-
const { originalName, ...viewToSave } = ctx.request.body
|
|
30
|
-
const designDoc = await db.get("_design/database")
|
|
31
|
-
const view = viewTemplate(viewToSave)
|
|
32
|
-
|
|
33
|
-
if (!viewToSave.name) {
|
|
34
|
-
ctx.throw(400, "Cannot create view without a name")
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
designDoc.views = {
|
|
38
|
-
...designDoc.views,
|
|
39
|
-
[viewToSave.name]: view,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// view has been renamed
|
|
43
|
-
if (originalName) {
|
|
44
|
-
delete designDoc.views[originalName]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
await db.put(designDoc)
|
|
48
|
-
|
|
49
|
-
// add views to table document
|
|
50
|
-
const table = await db.get(ctx.request.body.tableId)
|
|
51
|
-
if (!table.views) table.views = {}
|
|
52
|
-
if (!view.meta.schema) {
|
|
53
|
-
view.meta.schema = table.schema
|
|
54
|
-
}
|
|
55
|
-
table.views[viewToSave.name] = view.meta
|
|
56
|
-
|
|
57
|
-
if (originalName) {
|
|
58
|
-
delete table.views[originalName]
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
await db.put(table)
|
|
62
|
-
|
|
63
|
-
ctx.body = {
|
|
64
|
-
...table.views[viewToSave.name],
|
|
65
|
-
name: viewToSave.name,
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
destroy: async ctx => {
|
|
69
|
-
const db = new CouchDB(ctx.appId)
|
|
70
|
-
const designDoc = await db.get("_design/database")
|
|
71
|
-
const viewName = decodeURI(ctx.params.viewName)
|
|
72
|
-
const view = designDoc.views[viewName]
|
|
73
|
-
delete designDoc.views[viewName]
|
|
74
|
-
|
|
75
|
-
await db.put(designDoc)
|
|
76
|
-
|
|
77
|
-
const table = await db.get(view.meta.tableId)
|
|
78
|
-
delete table.views[viewName]
|
|
79
|
-
await db.put(table)
|
|
80
|
-
|
|
81
|
-
ctx.body = view
|
|
82
|
-
},
|
|
83
|
-
exportView: async ctx => {
|
|
84
|
-
const db = new CouchDB(ctx.appId)
|
|
85
|
-
const designDoc = await db.get("_design/database")
|
|
86
|
-
const viewName = decodeURI(ctx.query.view)
|
|
8
|
+
exports.fetch = async ctx => {
|
|
9
|
+
const db = new CouchDB(ctx.appId)
|
|
10
|
+
ctx.body = await getViews(db)
|
|
11
|
+
}
|
|
87
12
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
13
|
+
exports.save = async ctx => {
|
|
14
|
+
const db = new CouchDB(ctx.appId)
|
|
15
|
+
const { originalName, ...viewToSave } = ctx.request.body
|
|
16
|
+
const view = viewTemplate(viewToSave)
|
|
17
|
+
|
|
18
|
+
if (!viewToSave.name) {
|
|
19
|
+
ctx.throw(400, "Cannot create view without a name")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
await saveView(db, originalName, viewToSave.name, view)
|
|
23
|
+
|
|
24
|
+
// add views to table document
|
|
25
|
+
const table = await db.get(ctx.request.body.tableId)
|
|
26
|
+
if (!table.views) table.views = {}
|
|
27
|
+
if (!view.meta.schema) {
|
|
28
|
+
view.meta.schema = table.schema
|
|
29
|
+
}
|
|
30
|
+
table.views[viewToSave.name] = view.meta
|
|
31
|
+
if (originalName) {
|
|
32
|
+
delete table.views[originalName]
|
|
33
|
+
}
|
|
34
|
+
await db.put(table)
|
|
35
|
+
|
|
36
|
+
ctx.body = {
|
|
37
|
+
...table.views[viewToSave.name],
|
|
38
|
+
name: viewToSave.name,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
93
41
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
field: view.meta.field,
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
// table all_ view
|
|
105
|
-
/* istanbul ignore next */
|
|
106
|
-
ctx.params.viewName = viewName
|
|
107
|
-
}
|
|
42
|
+
exports.destroy = async ctx => {
|
|
43
|
+
const db = new CouchDB(ctx.appId)
|
|
44
|
+
const viewName = decodeURI(ctx.params.viewName)
|
|
45
|
+
const view = await deleteView(db, viewName)
|
|
46
|
+
const table = await db.get(view.meta.tableId)
|
|
47
|
+
delete table.views[viewName]
|
|
48
|
+
await db.put(table)
|
|
108
49
|
|
|
109
|
-
|
|
50
|
+
ctx.body = view
|
|
51
|
+
}
|
|
110
52
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
53
|
+
exports.exportView = async ctx => {
|
|
54
|
+
const db = new CouchDB(ctx.appId)
|
|
55
|
+
const viewName = decodeURI(ctx.query.view)
|
|
56
|
+
const view = await getView(db, viewName)
|
|
57
|
+
|
|
58
|
+
const format = ctx.query.format
|
|
59
|
+
if (!format) {
|
|
60
|
+
ctx.throw(400, "Format must be specified, either csv or json")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (view) {
|
|
64
|
+
ctx.params.viewName = viewName
|
|
65
|
+
// Fetch view rows
|
|
66
|
+
ctx.query = {
|
|
67
|
+
group: view.meta.groupBy,
|
|
68
|
+
calculation: view.meta.calculation,
|
|
69
|
+
stats: !!view.meta.field,
|
|
70
|
+
field: view.meta.field,
|
|
116
71
|
}
|
|
117
|
-
|
|
118
|
-
//
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
72
|
+
} else {
|
|
73
|
+
// table all_ view
|
|
74
|
+
/* istanbul ignore next */
|
|
75
|
+
ctx.params.viewName = viewName
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await fetchView(ctx)
|
|
79
|
+
|
|
80
|
+
let schema = view && view.meta && view.meta.schema
|
|
81
|
+
if (!schema) {
|
|
82
|
+
const tableId = ctx.params.tableId || view.meta.tableId
|
|
83
|
+
const table = await db.get(tableId)
|
|
84
|
+
schema = table.schema
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Export part
|
|
88
|
+
let headers = Object.keys(schema)
|
|
89
|
+
const exporter = exporters[format]
|
|
90
|
+
const filename = `${viewName}.${format}`
|
|
91
|
+
// send down the file
|
|
92
|
+
ctx.attachment(filename)
|
|
93
|
+
ctx.body = apiFileReturn(exporter(headers, ctx.body))
|
|
126
94
|
}
|
|
127
|
-
|
|
128
|
-
module.exports = controller
|