@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.
Files changed (200) hide show
  1. package/builder/assets/{index.2bcd18f5.js → index.80d850d1.js} +1 -1
  2. package/builder/index.html +1 -1
  3. package/coverage/clover.xml +646 -528
  4. package/coverage/coverage-final.json +17 -15
  5. package/coverage/lcov-report/api/controllers/analytics.js.html +1 -1
  6. package/coverage/lcov-report/api/controllers/apikeys.js.html +1 -1
  7. package/coverage/lcov-report/api/controllers/application.js.html +1 -1
  8. package/coverage/lcov-report/api/controllers/auth.js.html +1 -1
  9. package/coverage/lcov-report/api/controllers/automation.js.html +1 -1
  10. package/coverage/lcov-report/api/controllers/backup.js.html +1 -1
  11. package/coverage/lcov-report/api/controllers/component.js.html +1 -1
  12. package/coverage/lcov-report/api/controllers/datasource.js.html +3 -3
  13. package/coverage/lcov-report/api/controllers/dev.js.html +1 -1
  14. package/coverage/lcov-report/api/controllers/hosting.js.html +1 -1
  15. package/coverage/lcov-report/api/controllers/index.html +1 -1
  16. package/coverage/lcov-report/api/controllers/integration.js.html +1 -1
  17. package/coverage/lcov-report/api/controllers/layout.js.html +1 -1
  18. package/coverage/lcov-report/api/controllers/metadata.js.html +1 -1
  19. package/coverage/lcov-report/api/controllers/permission.js.html +1 -1
  20. package/coverage/lcov-report/api/controllers/query.js.html +1 -1
  21. package/coverage/lcov-report/api/controllers/role.js.html +1 -1
  22. package/coverage/lcov-report/api/controllers/routing.js.html +1 -1
  23. package/coverage/lcov-report/api/controllers/row/external.js.html +1 -1
  24. package/coverage/lcov-report/api/controllers/row/index.html +19 -19
  25. package/coverage/lcov-report/api/controllers/row/index.js.html +1 -1
  26. package/coverage/lcov-report/api/controllers/row/internal.js.html +242 -47
  27. package/coverage/lcov-report/api/controllers/row/internalSearch.js.html +1 -1
  28. package/coverage/lcov-report/api/controllers/row/utils.js.html +1 -1
  29. package/coverage/lcov-report/api/controllers/screen.js.html +1 -1
  30. package/coverage/lcov-report/api/controllers/script.js.html +1 -1
  31. package/coverage/lcov-report/api/controllers/table/index.html +1 -1
  32. package/coverage/lcov-report/api/controllers/table/index.js.html +2 -2
  33. package/coverage/lcov-report/api/controllers/table/utils.js.html +31 -19
  34. package/coverage/lcov-report/api/controllers/templates.js.html +1 -1
  35. package/coverage/lcov-report/api/controllers/user.js.html +1 -1
  36. package/coverage/lcov-report/api/controllers/view/exporters.js.html +1 -1
  37. package/coverage/lcov-report/api/controllers/view/index.html +32 -17
  38. package/coverage/lcov-report/api/controllers/view/index.js.html +84 -186
  39. package/coverage/lcov-report/api/controllers/view/utils.js.html +407 -0
  40. package/coverage/lcov-report/api/controllers/view/viewBuilder.js.html +1 -1
  41. package/coverage/lcov-report/api/controllers/webhook.js.html +1 -1
  42. package/coverage/lcov-report/api/index.html +1 -1
  43. package/coverage/lcov-report/api/index.js.html +1 -1
  44. package/coverage/lcov-report/api/routes/analytics.js.html +1 -1
  45. package/coverage/lcov-report/api/routes/apikeys.js.html +1 -1
  46. package/coverage/lcov-report/api/routes/application.js.html +1 -1
  47. package/coverage/lcov-report/api/routes/auth.js.html +1 -1
  48. package/coverage/lcov-report/api/routes/automation.js.html +1 -1
  49. package/coverage/lcov-report/api/routes/backup.js.html +1 -1
  50. package/coverage/lcov-report/api/routes/component.js.html +1 -1
  51. package/coverage/lcov-report/api/routes/datasource.js.html +1 -1
  52. package/coverage/lcov-report/api/routes/deploy.js.html +1 -1
  53. package/coverage/lcov-report/api/routes/dev.js.html +1 -1
  54. package/coverage/lcov-report/api/routes/hosting.js.html +1 -1
  55. package/coverage/lcov-report/api/routes/index.html +1 -1
  56. package/coverage/lcov-report/api/routes/index.js.html +1 -1
  57. package/coverage/lcov-report/api/routes/integration.js.html +1 -1
  58. package/coverage/lcov-report/api/routes/layout.js.html +1 -1
  59. package/coverage/lcov-report/api/routes/metadata.js.html +1 -1
  60. package/coverage/lcov-report/api/routes/permission.js.html +1 -1
  61. package/coverage/lcov-report/api/routes/query.js.html +1 -1
  62. package/coverage/lcov-report/api/routes/role.js.html +1 -1
  63. package/coverage/lcov-report/api/routes/routing.js.html +1 -1
  64. package/coverage/lcov-report/api/routes/row.js.html +1 -1
  65. package/coverage/lcov-report/api/routes/screen.js.html +1 -1
  66. package/coverage/lcov-report/api/routes/script.js.html +1 -1
  67. package/coverage/lcov-report/api/routes/static.js.html +1 -1
  68. package/coverage/lcov-report/api/routes/table.js.html +1 -1
  69. package/coverage/lcov-report/api/routes/templates.js.html +1 -1
  70. package/coverage/lcov-report/api/routes/user.js.html +1 -1
  71. package/coverage/lcov-report/api/routes/view.js.html +1 -1
  72. package/coverage/lcov-report/api/routes/webhook.js.html +1 -1
  73. package/coverage/lcov-report/automations/actions.js.html +1 -1
  74. package/coverage/lcov-report/automations/automationUtils.js.html +1 -1
  75. package/coverage/lcov-report/automations/bullboard.js.html +1 -1
  76. package/coverage/lcov-report/automations/index.html +1 -1
  77. package/coverage/lcov-report/automations/index.js.html +1 -1
  78. package/coverage/lcov-report/automations/steps/bash.js.html +1 -1
  79. package/coverage/lcov-report/automations/steps/createRow.js.html +10 -19
  80. package/coverage/lcov-report/automations/steps/delay.js.html +1 -1
  81. package/coverage/lcov-report/automations/steps/deleteRow.js.html +14 -20
  82. package/coverage/lcov-report/automations/steps/discord.js.html +1 -1
  83. package/coverage/lcov-report/automations/steps/executeQuery.js.html +1 -1
  84. package/coverage/lcov-report/automations/steps/executeScript.js.html +1 -1
  85. package/coverage/lcov-report/automations/steps/filter.js.html +1 -1
  86. package/coverage/lcov-report/automations/steps/index.html +31 -31
  87. package/coverage/lcov-report/automations/steps/integromat.js.html +1 -1
  88. package/coverage/lcov-report/automations/steps/outgoingWebhook.js.html +1 -1
  89. package/coverage/lcov-report/automations/steps/queryRows.js.html +18 -27
  90. package/coverage/lcov-report/automations/steps/sendSmtpEmail.js.html +1 -1
  91. package/coverage/lcov-report/automations/steps/serverLog.js.html +1 -1
  92. package/coverage/lcov-report/automations/steps/slack.js.html +1 -1
  93. package/coverage/lcov-report/automations/steps/updateRow.js.html +12 -21
  94. package/coverage/lcov-report/automations/steps/utils.js.html +23 -23
  95. package/coverage/lcov-report/automations/steps/zapier.js.html +1 -1
  96. package/coverage/lcov-report/automations/thread.js.html +1 -1
  97. package/coverage/lcov-report/automations/triggerInfo/app.js.html +1 -1
  98. package/coverage/lcov-report/automations/triggerInfo/cron.js.html +1 -1
  99. package/coverage/lcov-report/automations/triggerInfo/index.html +1 -1
  100. package/coverage/lcov-report/automations/triggerInfo/index.js.html +1 -1
  101. package/coverage/lcov-report/automations/triggerInfo/rowDeleted.js.html +1 -1
  102. package/coverage/lcov-report/automations/triggerInfo/rowSaved.js.html +1 -1
  103. package/coverage/lcov-report/automations/triggerInfo/rowUpdated.js.html +1 -1
  104. package/coverage/lcov-report/automations/triggerInfo/webhook.js.html +1 -1
  105. package/coverage/lcov-report/automations/triggers.js.html +1 -1
  106. package/coverage/lcov-report/automations/utils.js.html +1 -1
  107. package/coverage/lcov-report/constants/index.html +1 -1
  108. package/coverage/lcov-report/constants/index.js.html +1 -1
  109. package/coverage/lcov-report/constants/layouts.js.html +1 -1
  110. package/coverage/lcov-report/constants/screens.js.html +1 -1
  111. package/coverage/lcov-report/db/client.js.html +1 -1
  112. package/coverage/lcov-report/db/inMemoryView.js.html +224 -0
  113. package/coverage/lcov-report/db/index.html +34 -19
  114. package/coverage/lcov-report/db/index.js.html +1 -1
  115. package/coverage/lcov-report/db/linkedRows/LinkController.js.html +4 -4
  116. package/coverage/lcov-report/db/linkedRows/index.html +14 -14
  117. package/coverage/lcov-report/db/linkedRows/index.js.html +18 -9
  118. package/coverage/lcov-report/db/linkedRows/linkUtils.js.html +1 -1
  119. package/coverage/lcov-report/db/newid.js.html +1 -1
  120. package/coverage/lcov-report/db/utils.js.html +37 -10
  121. package/coverage/lcov-report/events/AutomationEmitter.js.html +1 -1
  122. package/coverage/lcov-report/events/index.html +1 -1
  123. package/coverage/lcov-report/events/index.js.html +1 -1
  124. package/coverage/lcov-report/events/utils.js.html +1 -1
  125. package/coverage/lcov-report/index.html +65 -65
  126. package/coverage/lcov-report/integrations/tests/TestConfiguration.js.html +1 -1
  127. package/coverage/lcov-report/integrations/tests/index.html +1 -1
  128. package/coverage/lcov-report/middleware/appInfo.js.html +1 -1
  129. package/coverage/lcov-report/middleware/authorized.js.html +1 -1
  130. package/coverage/lcov-report/middleware/builder.js.html +1 -1
  131. package/coverage/lcov-report/middleware/currentapp.js.html +1 -1
  132. package/coverage/lcov-report/middleware/index.html +1 -1
  133. package/coverage/lcov-report/middleware/joi-validator.js.html +1 -1
  134. package/coverage/lcov-report/middleware/resourceId.js.html +1 -1
  135. package/coverage/lcov-report/middleware/selfhost.js.html +1 -1
  136. package/coverage/lcov-report/middleware/usageQuota.js.html +1 -1
  137. package/coverage/lcov-report/utilities/bcrypt.js.html +1 -1
  138. package/coverage/lcov-report/utilities/budibaseDir.js.html +1 -1
  139. package/coverage/lcov-report/utilities/centralPath.js.html +1 -1
  140. package/coverage/lcov-report/utilities/csvParser.js.html +1 -1
  141. package/coverage/lcov-report/utilities/global.js.html +1 -1
  142. package/coverage/lcov-report/utilities/index.html +1 -1
  143. package/coverage/lcov-report/utilities/index.js.html +1 -1
  144. package/coverage/lcov-report/utilities/queue/inMemoryQueue.js.html +1 -1
  145. package/coverage/lcov-report/utilities/queue/index.html +1 -1
  146. package/coverage/lcov-report/utilities/routing/index.html +1 -1
  147. package/coverage/lcov-report/utilities/routing/index.js.html +1 -1
  148. package/coverage/lcov-report/utilities/rowProcessor/index.html +15 -15
  149. package/coverage/lcov-report/utilities/rowProcessor/index.js.html +58 -13
  150. package/coverage/lcov-report/utilities/rowProcessor/utils.js.html +1 -1
  151. package/coverage/lcov-report/utilities/security.js.html +2 -2
  152. package/coverage/lcov-report/utilities/statusCodes.js.html +1 -1
  153. package/coverage/lcov-report/utilities/users.js.html +1 -1
  154. package/coverage/lcov-report/utilities/workerRequests.js.html +1 -1
  155. package/coverage/lcov.info +1093 -883
  156. package/dist/api/controllers/datasource.js +2 -2
  157. package/dist/api/controllers/row/ExternalRequest.js +4 -0
  158. package/dist/api/controllers/row/internal.js +97 -23
  159. package/dist/api/controllers/table/index.js +1 -1
  160. package/dist/api/controllers/table/utils.js +13 -11
  161. package/dist/api/controllers/view/index.js +74 -96
  162. package/dist/api/controllers/view/utils.js +102 -0
  163. package/dist/automations/steps/createRow.js +5 -8
  164. package/dist/automations/steps/deleteRow.js +7 -10
  165. package/dist/automations/steps/queryRows.js +11 -14
  166. package/dist/automations/steps/updateRow.js +4 -7
  167. package/dist/db/inMemoryView.js +51 -0
  168. package/dist/db/linkedRows/index.js +5 -2
  169. package/dist/db/utils.js +7 -0
  170. package/dist/environment.js +7 -1
  171. package/dist/integrations/mysql.js +2 -13
  172. package/dist/integrations/postgres.js +8 -14
  173. package/dist/integrations/utils.js +19 -1
  174. package/dist/package.json +5 -5
  175. package/dist/tsconfig.tsbuildinfo +1 -1
  176. package/dist/utilities/rowProcessor/index.js +10 -5
  177. package/package.json +6 -6
  178. package/scripts/integrations/service-vehicles/docker-compose.yml +28 -0
  179. package/scripts/integrations/service-vehicles/init.sql +52 -0
  180. package/scripts/integrations/service-vehicles/reset.sh +3 -0
  181. package/src/api/controllers/datasource.js +2 -2
  182. package/src/api/controllers/row/ExternalRequest.ts +5 -1
  183. package/src/api/controllers/row/internal.js +88 -23
  184. package/src/api/controllers/table/index.js +1 -1
  185. package/src/api/controllers/table/utils.js +16 -12
  186. package/src/api/controllers/view/index.js +82 -116
  187. package/src/api/controllers/view/utils.js +109 -0
  188. package/src/api/routes/tests/view.spec.js +1 -1
  189. package/src/automations/steps/createRow.js +5 -8
  190. package/src/automations/steps/deleteRow.js +8 -10
  191. package/src/automations/steps/queryRows.js +11 -14
  192. package/src/automations/steps/updateRow.js +7 -10
  193. package/src/db/inMemoryView.js +48 -0
  194. package/src/db/linkedRows/index.js +5 -2
  195. package/src/db/utils.js +9 -0
  196. package/src/environment.js +8 -1
  197. package/src/integrations/mysql.ts +2 -13
  198. package/src/integrations/postgres.ts +9 -16
  199. package/src/integrations/utils.ts +18 -0
  200. 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
- row[key] = [user.userId];
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",
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.4",
66
- "@budibase/client": "^0.9.140-alpha.4",
67
- "@budibase/string-templates": "^0.9.140-alpha.4",
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": "0c9203d539e1f542fab6f2671a2cf612c9e609c1"
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);
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ docker-compose down
3
+ docker volume prune -f
@@ -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.post(datasource)
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.post(datasource)
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
- await db.put(table)
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 designDoc = await db.get("_design/database")
143
- const viewInfo = designDoc.views[viewName]
144
- if (!viewInfo) {
145
- throw "View does not exist."
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
- let rows,
195
- table = await db.get(ctx.params.tableId)
196
- if (ctx.params.tableId === InternalTables.USER_METADATA) {
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.post(tableToSave)
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
- data[i] = row
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(data)
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
- const controller = {
9
- fetch: async ctx => {
10
- const db = new CouchDB(ctx.appId)
11
- const designDoc = await db.get("_design/database")
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
- const view = designDoc.views[viewName]
89
- const format = ctx.query.format
90
- if (!format) {
91
- ctx.throw(400, "Format must be specified, either csv or json")
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
- if (view) {
95
- ctx.params.viewName = viewName
96
- // Fetch view rows
97
- ctx.query = {
98
- group: view.meta.groupBy,
99
- calculation: view.meta.calculation,
100
- stats: !!view.meta.field,
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
- await fetchView(ctx)
50
+ ctx.body = view
51
+ }
110
52
 
111
- let schema = view && view.meta && view.meta.schema
112
- if (!schema) {
113
- const tableId = ctx.params.tableId || view.meta.tableId
114
- const table = await db.get(tableId)
115
- schema = table.schema
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
- // Export part
119
- let headers = Object.keys(schema)
120
- const exporter = exporters[format]
121
- const filename = `${viewName}.${format}`
122
- // send down the file
123
- ctx.attachment(filename)
124
- ctx.body = apiFileReturn(exporter(headers, ctx.body))
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