@saltcorn/data 0.7.1-beta.3 → 0.7.2-beta.2

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 (260) hide show
  1. package/dist/app-locales/en.json +6 -0
  2. package/dist/app-locales/public/da.json +3 -0
  3. package/dist/app-locales/public/tlh.json +3 -0
  4. package/dist/base-plugin/actions.d.ts.map +1 -1
  5. package/dist/base-plugin/actions.js +4 -1
  6. package/dist/base-plugin/actions.js.map +1 -1
  7. package/dist/base-plugin/fieldviews.d.ts +29 -0
  8. package/dist/base-plugin/fieldviews.d.ts.map +1 -1
  9. package/dist/base-plugin/fieldviews.js +60 -5
  10. package/dist/base-plugin/fieldviews.js.map +1 -1
  11. package/dist/base-plugin/index.d.ts +245 -20
  12. package/dist/base-plugin/index.d.ts.map +1 -1
  13. package/dist/base-plugin/types.d.ts +127 -65
  14. package/dist/base-plugin/types.d.ts.map +1 -1
  15. package/dist/base-plugin/types.js +152 -36
  16. package/dist/base-plugin/types.js.map +1 -1
  17. package/dist/base-plugin/viewtemplates/edit.d.ts +46 -8
  18. package/dist/base-plugin/viewtemplates/edit.d.ts.map +1 -1
  19. package/dist/base-plugin/viewtemplates/edit.js +258 -112
  20. package/dist/base-plugin/viewtemplates/edit.js.map +1 -1
  21. package/dist/base-plugin/viewtemplates/feed.d.ts +14 -1
  22. package/dist/base-plugin/viewtemplates/feed.d.ts.map +1 -1
  23. package/dist/base-plugin/viewtemplates/feed.js +20 -8
  24. package/dist/base-plugin/viewtemplates/feed.js.map +1 -1
  25. package/dist/base-plugin/viewtemplates/filter.d.ts +17 -1
  26. package/dist/base-plugin/viewtemplates/filter.d.ts.map +1 -1
  27. package/dist/base-plugin/viewtemplates/filter.js +64 -45
  28. package/dist/base-plugin/viewtemplates/filter.js.map +1 -1
  29. package/dist/base-plugin/viewtemplates/list.d.ts +21 -1
  30. package/dist/base-plugin/viewtemplates/list.d.ts.map +1 -1
  31. package/dist/base-plugin/viewtemplates/list.js +63 -40
  32. package/dist/base-plugin/viewtemplates/list.js.map +1 -1
  33. package/dist/base-plugin/viewtemplates/listshowlist.d.ts +14 -1
  34. package/dist/base-plugin/viewtemplates/listshowlist.d.ts.map +1 -1
  35. package/dist/base-plugin/viewtemplates/listshowlist.js +15 -4
  36. package/dist/base-plugin/viewtemplates/listshowlist.js.map +1 -1
  37. package/dist/base-plugin/viewtemplates/room.d.ts +41 -1
  38. package/dist/base-plugin/viewtemplates/room.d.ts.map +1 -1
  39. package/dist/base-plugin/viewtemplates/room.js +107 -80
  40. package/dist/base-plugin/viewtemplates/room.js.map +1 -1
  41. package/dist/base-plugin/viewtemplates/show.d.ts +38 -4
  42. package/dist/base-plugin/viewtemplates/show.d.ts.map +1 -1
  43. package/dist/base-plugin/viewtemplates/show.js +120 -75
  44. package/dist/base-plugin/viewtemplates/show.js.map +1 -1
  45. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts +26 -7
  46. package/dist/base-plugin/viewtemplates/viewable_fields.d.ts.map +1 -1
  47. package/dist/base-plugin/viewtemplates/viewable_fields.js +60 -48
  48. package/dist/base-plugin/viewtemplates/viewable_fields.js.map +1 -1
  49. package/dist/coverage/coverage-final.json +46 -0
  50. package/dist/coverage/lcov-report/block-navigation.d.ts +2 -0
  51. package/dist/coverage/lcov-report/block-navigation.d.ts.map +1 -0
  52. package/dist/coverage/lcov-report/block-navigation.js +71 -0
  53. package/dist/coverage/lcov-report/block-navigation.js.map +1 -0
  54. package/dist/coverage/lcov-report/prettify.d.ts +1 -0
  55. package/dist/coverage/lcov-report/prettify.d.ts.map +1 -0
  56. package/dist/coverage/lcov-report/prettify.js +478 -0
  57. package/dist/coverage/lcov-report/prettify.js.map +1 -0
  58. package/dist/coverage/lcov-report/sorter.d.ts +2 -0
  59. package/dist/coverage/lcov-report/sorter.d.ts.map +1 -0
  60. package/dist/coverage/lcov-report/sorter.js +164 -0
  61. package/dist/coverage/lcov-report/sorter.js.map +1 -0
  62. package/dist/db/connect.d.ts.map +1 -1
  63. package/dist/db/connect.js +8 -1
  64. package/dist/db/connect.js.map +1 -1
  65. package/dist/db/connect_mobile.d.ts +9 -0
  66. package/dist/db/connect_mobile.d.ts.map +1 -0
  67. package/dist/db/connect_mobile.js +15 -0
  68. package/dist/db/connect_mobile.js.map +1 -0
  69. package/dist/db/fixtures.d.ts.map +1 -1
  70. package/dist/db/fixtures.js +6 -1
  71. package/dist/db/fixtures.js.map +1 -1
  72. package/dist/db/index.d.ts.map +1 -1
  73. package/dist/db/index.js +16 -2
  74. package/dist/db/index.js.map +1 -1
  75. package/dist/db/state.d.ts +207 -52
  76. package/dist/db/state.d.ts.map +1 -1
  77. package/dist/db/state.js +87 -84
  78. package/dist/db/state.js.map +1 -1
  79. package/dist/index.d.ts +8 -0
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +27 -2
  82. package/dist/index.js.map +1 -1
  83. package/dist/migrate.d.ts.map +1 -1
  84. package/dist/migrate.js +54 -40
  85. package/dist/migrate.js.map +1 -1
  86. package/dist/mobile-mocks/db/postgres.d.ts +1 -0
  87. package/dist/mobile-mocks/db/postgres.d.ts.map +1 -0
  88. package/dist/mobile-mocks/db/postgres.js +2 -0
  89. package/dist/mobile-mocks/db/postgres.js.map +1 -0
  90. package/dist/mobile-mocks/db/sqlite.d.ts +1 -0
  91. package/dist/mobile-mocks/db/sqlite.d.ts.map +1 -0
  92. package/dist/mobile-mocks/db/sqlite.js +2 -0
  93. package/dist/mobile-mocks/db/sqlite.js.map +1 -0
  94. package/dist/mobile-mocks/models/email.d.ts +1 -0
  95. package/dist/mobile-mocks/models/email.d.ts.map +1 -0
  96. package/dist/mobile-mocks/models/email.js +2 -0
  97. package/dist/mobile-mocks/models/email.js.map +1 -0
  98. package/dist/mobile-mocks/node/async_hooks.d.ts +4 -0
  99. package/dist/mobile-mocks/node/async_hooks.d.ts.map +1 -0
  100. package/dist/mobile-mocks/node/async_hooks.js +8 -0
  101. package/dist/mobile-mocks/node/async_hooks.js.map +1 -0
  102. package/dist/mobile-mocks/node/child_process.d.ts +3 -0
  103. package/dist/mobile-mocks/node/child_process.d.ts.map +1 -0
  104. package/dist/mobile-mocks/node/child_process.js +6 -0
  105. package/dist/mobile-mocks/node/child_process.js.map +1 -0
  106. package/dist/mobile-mocks/node/fs/promises.d.ts +6 -0
  107. package/dist/mobile-mocks/node/fs/promises.d.ts.map +1 -0
  108. package/dist/mobile-mocks/node/fs/promises.js +16 -0
  109. package/dist/mobile-mocks/node/fs/promises.js.map +1 -0
  110. package/dist/mobile-mocks/node/fs.d.ts +4 -0
  111. package/dist/mobile-mocks/node/fs.d.ts.map +1 -0
  112. package/dist/mobile-mocks/node/fs.js +15 -0
  113. package/dist/mobile-mocks/node/fs.js.map +1 -0
  114. package/dist/mobile-mocks/node/latest-version.d.ts +2 -0
  115. package/dist/mobile-mocks/node/latest-version.d.ts.map +1 -0
  116. package/dist/mobile-mocks/node/latest-version.js +7 -0
  117. package/dist/mobile-mocks/node/latest-version.js.map +1 -0
  118. package/dist/mobile-mocks/node/v8.d.ts +3 -0
  119. package/dist/mobile-mocks/node/v8.d.ts.map +1 -0
  120. package/dist/mobile-mocks/node/v8.js +8 -0
  121. package/dist/mobile-mocks/node/v8.js.map +1 -0
  122. package/dist/mobile-mocks/npm/env-paths.d.ts +6 -0
  123. package/dist/mobile-mocks/npm/env-paths.d.ts.map +1 -0
  124. package/dist/mobile-mocks/npm/env-paths.js +9 -0
  125. package/dist/mobile-mocks/npm/env-paths.js.map +1 -0
  126. package/dist/mobile-mocks/saltcorn/plugin-testing.d.ts +1 -0
  127. package/dist/mobile-mocks/saltcorn/plugin-testing.d.ts.map +1 -0
  128. package/dist/mobile-mocks/saltcorn/plugin-testing.js +2 -0
  129. package/dist/mobile-mocks/saltcorn/plugin-testing.js.map +1 -0
  130. package/dist/models/config.d.ts +9 -10
  131. package/dist/models/config.d.ts.map +1 -1
  132. package/dist/models/config.js +8 -7
  133. package/dist/models/config.js.map +1 -1
  134. package/dist/models/discovery.d.ts.map +1 -1
  135. package/dist/models/discovery.js +5 -1
  136. package/dist/models/discovery.js.map +1 -1
  137. package/dist/models/email.d.ts +2 -0
  138. package/dist/models/email.d.ts.map +1 -1
  139. package/dist/models/field.d.ts +6 -4
  140. package/dist/models/field.d.ts.map +1 -1
  141. package/dist/models/field.js +40 -21
  142. package/dist/models/field.js.map +1 -1
  143. package/dist/models/fieldrepeat.d.ts +5 -0
  144. package/dist/models/fieldrepeat.d.ts.map +1 -1
  145. package/dist/models/fieldrepeat.js +2 -0
  146. package/dist/models/fieldrepeat.js.map +1 -1
  147. package/dist/models/form.d.ts +2 -0
  148. package/dist/models/form.d.ts.map +1 -1
  149. package/dist/models/form.js +1 -0
  150. package/dist/models/form.js.map +1 -1
  151. package/dist/models/index.d.ts +2 -13
  152. package/dist/models/index.d.ts.map +1 -1
  153. package/dist/models/layout.d.ts.map +1 -1
  154. package/dist/models/layout.js +12 -2
  155. package/dist/models/layout.js.map +1 -1
  156. package/dist/models/page.d.ts +1 -1
  157. package/dist/models/page.d.ts.map +1 -1
  158. package/dist/models/page.js +17 -9
  159. package/dist/models/page.js.map +1 -1
  160. package/dist/models/scheduler.d.ts.map +1 -1
  161. package/dist/models/scheduler.js +3 -1
  162. package/dist/models/scheduler.js.map +1 -1
  163. package/dist/models/table.d.ts +2 -1
  164. package/dist/models/table.d.ts.map +1 -1
  165. package/dist/models/table.js +32 -11
  166. package/dist/models/table.js.map +1 -1
  167. package/dist/models/trigger.d.ts +3 -3
  168. package/dist/models/trigger.d.ts.map +1 -1
  169. package/dist/models/trigger.js +4 -5
  170. package/dist/models/trigger.js.map +1 -1
  171. package/dist/models/user.d.ts +1 -1
  172. package/dist/models/user.d.ts.map +1 -1
  173. package/dist/models/user.js +7 -15
  174. package/dist/models/user.js.map +1 -1
  175. package/dist/models/view.d.ts +16 -12
  176. package/dist/models/view.d.ts.map +1 -1
  177. package/dist/models/view.js +63 -15
  178. package/dist/models/view.js.map +1 -1
  179. package/dist/models/workflow.d.ts +1 -0
  180. package/dist/models/workflow.d.ts.map +1 -1
  181. package/dist/models/workflow.js +58 -2
  182. package/dist/models/workflow.js.map +1 -1
  183. package/dist/package.json +127 -0
  184. package/dist/plugin-helper.d.ts +17 -13
  185. package/dist/plugin-helper.d.ts.map +1 -1
  186. package/dist/plugin-helper.js +122 -74
  187. package/dist/plugin-helper.js.map +1 -1
  188. package/dist/plugin-testing.d.ts +1 -0
  189. package/dist/plugin-testing.d.ts.map +1 -1
  190. package/dist/plugin-testing.js +84 -1
  191. package/dist/plugin-testing.js.map +1 -1
  192. package/dist/tests/actions.test.js +30 -5
  193. package/dist/tests/actions.test.js.map +1 -1
  194. package/dist/tests/db.test.d.ts +2 -0
  195. package/dist/tests/db.test.d.ts.map +1 -0
  196. package/dist/tests/db.test.js +32 -0
  197. package/dist/tests/db.test.js.map +1 -0
  198. package/dist/tests/exact_views.test.js +274 -19
  199. package/dist/tests/exact_views.test.js.map +1 -1
  200. package/dist/tests/field.test.js +36 -0
  201. package/dist/tests/field.test.js.map +1 -1
  202. package/dist/tests/mocks.d.ts +2 -0
  203. package/dist/tests/mocks.d.ts.map +1 -1
  204. package/dist/tests/mocks.js +2 -0
  205. package/dist/tests/mocks.js.map +1 -1
  206. package/dist/tests/models.test.js +46 -1
  207. package/dist/tests/models.test.js.map +1 -1
  208. package/dist/tests/remote_query_helper.d.ts +341 -0
  209. package/dist/tests/remote_query_helper.d.ts.map +1 -0
  210. package/dist/tests/remote_query_helper.js +446 -0
  211. package/dist/tests/remote_query_helper.js.map +1 -0
  212. package/dist/tests/state.test.d.ts +2 -0
  213. package/dist/tests/state.test.d.ts.map +1 -0
  214. package/dist/tests/state.test.js +78 -0
  215. package/dist/tests/state.test.js.map +1 -0
  216. package/dist/tests/table.test.js +19 -0
  217. package/dist/tests/table.test.js.map +1 -1
  218. package/dist/tests/view.test.js +29 -0
  219. package/dist/tests/view.test.js.map +1 -1
  220. package/dist/tsconfig.json +24 -0
  221. package/dist/tsconfig.ref.json +9 -0
  222. package/dist/tsconfig.ref.tsbuildinfo +1 -1
  223. package/dist/utils.d.ts +3 -1
  224. package/dist/utils.d.ts.map +1 -1
  225. package/dist/utils.js +14 -23
  226. package/dist/utils.js.map +1 -1
  227. package/dist/webpack.config.d.ts +57 -0
  228. package/dist/webpack.config.d.ts.map +1 -0
  229. package/dist/webpack.config.js +75 -0
  230. package/dist/webpack.config.js.map +1 -0
  231. package/package.json +38 -13
  232. package/CHANGELOG.md +0 -8
  233. package/dist/models/backup.d.ts +0 -9
  234. package/dist/models/backup.d.ts.map +0 -1
  235. package/dist/models/backup.js +0 -278
  236. package/dist/models/backup.js.map +0 -1
  237. package/dist/models/pack.d.ts +0 -42
  238. package/dist/models/pack.d.ts.map +0 -1
  239. package/dist/models/pack.js +0 -419
  240. package/dist/models/pack.js.map +0 -1
  241. package/dist/models/tenant.d.ts +0 -17
  242. package/dist/models/tenant.d.ts.map +0 -1
  243. package/dist/models/tenant.js +0 -152
  244. package/dist/models/tenant.js.map +0 -1
  245. package/dist/tests/backup.test.d.ts +0 -2
  246. package/dist/tests/backup.test.d.ts.map +0 -1
  247. package/dist/tests/backup.test.js +0 -101
  248. package/dist/tests/backup.test.js.map +0 -1
  249. package/dist/tests/pack.test.d.ts +0 -2
  250. package/dist/tests/pack.test.d.ts.map +0 -1
  251. package/dist/tests/pack.test.js +0 -338
  252. package/dist/tests/pack.test.js.map +0 -1
  253. package/dist/tests/random.test.d.ts +0 -2
  254. package/dist/tests/random.test.d.ts.map +0 -1
  255. package/dist/tests/random.test.js +0 -149
  256. package/dist/tests/random.test.js.map +0 -1
  257. package/dist/tests/tenant.test.d.ts +0 -2
  258. package/dist/tests/tenant.test.d.ts.map +0 -1
  259. package/dist/tests/tenant.test.js +0 -52
  260. package/dist/tests/tenant.test.js.map +0 -1
@@ -10,12 +10,12 @@ const Table = require("./models/table");
10
10
  const Trigger = require("./models/trigger");
11
11
  const { getState } = require("./db/state");
12
12
  const db = require("./db");
13
- const { contract, is } = require("contractis");
14
- const { fieldlike, is_table_query, is_column, is_tablely, } = require("./contracts");
15
13
  const { link } = require("@saltcorn/markup");
16
14
  const { button, a, label, text, i } = require("@saltcorn/markup/tags");
17
15
  const { applyAsync, InvalidConfiguration } = require("./utils");
18
16
  const { jsexprToWhere, freeVariables } = require("./models/expression");
17
+ const { traverse } = require("./models/layout");
18
+ const { isNode } = require("./utils");
19
19
  /**
20
20
  *
21
21
  * @param {string} url
@@ -51,7 +51,7 @@ const link_view = (url0, label, popup, link_style = "", link_size = "", link_ico
51
51
  extraClass,
52
52
  ],
53
53
  type: "button",
54
- onClick: `ajax_modal('${url}')`,
54
+ onClick: isNode() ? `ajax_modal('${url}')` : `mobile_modal('${url}')`,
55
55
  style,
56
56
  }, link_icon ? i({ class: link_icon }) + " " : "", label);
57
57
  }
@@ -67,30 +67,30 @@ const link_view = (url0, label, popup, link_style = "", link_size = "", link_ico
67
67
  * @param {object} [state]
68
68
  * @returns {string}
69
69
  */
70
- const stateToQueryString = contract(is.fun(is.maybe(is.obj()), is.str), (state) => {
70
+ const stateToQueryString = (state) => {
71
71
  if (!state || Object.keys(state).length === 0)
72
72
  return "";
73
73
  return ("?" +
74
74
  Object.entries(state)
75
- .map(([k, v]) => k === "id"
76
- ? null
77
- : `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
75
+ .map(([k, v]) => k === "id" ? null : `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
78
76
  .filter((s) => !!s)
79
77
  .join("&"));
80
- });
78
+ };
81
79
  /**
82
80
  * @function
83
81
  * @param {Field[]} fields
84
82
  * @param {boolean}
85
83
  * @returns {object}
86
84
  */
87
- const calcfldViewOptions = contract(is.fun([is.array(is.class("Field")), is.str], is.obj({ field_view_options: is.objVals(is.array(is.str)) })), (fields, mode) => {
85
+ const calcfldViewOptions = (fields, mode) => {
88
86
  const isEdit = mode === "edit";
89
87
  const isFilter = mode === "filter";
90
88
  let fvs = {};
91
89
  const handlesTextStyle = {};
90
+ const blockDisplay = {};
92
91
  fields.forEach((f) => {
93
92
  handlesTextStyle[f.name] = [];
93
+ blockDisplay[f.name] = [];
94
94
  if (f.type === "File") {
95
95
  if (!isEdit && !isFilter)
96
96
  fvs[f.name] = Object.keys(getState().fileviews);
@@ -135,6 +135,8 @@ const calcfldViewOptions = contract(is.fun([is.array(is.class("Field")), is.str]
135
135
  Object.entries(getState().keyFieldviews).forEach(([k, v]) => {
136
136
  if (v && v.handlesTextStyle)
137
137
  handlesTextStyle[f.name].push(k);
138
+ if (v && v.blockDisplay)
139
+ blockDisplay[f.name].push(k);
138
140
  });
139
141
  }
140
142
  else if (f.type && f.type.fieldviews) {
@@ -158,19 +160,21 @@ const calcfldViewOptions = contract(is.fun([is.array(is.class("Field")), is.str]
158
160
  fvs[f.name] = tfvs_ordered.map(([k, fv]) => {
159
161
  if (fv && fv.handlesTextStyle)
160
162
  handlesTextStyle[f.name].push(k);
163
+ if (fv && fv.blockDisplay)
164
+ blockDisplay[f.name].push(k);
161
165
  return k;
162
166
  });
163
167
  }
164
168
  });
165
- return { field_view_options: fvs, handlesTextStyle };
166
- });
169
+ return { field_view_options: fvs, handlesTextStyle, blockDisplay };
170
+ };
167
171
  /**
168
172
  * @function
169
173
  * @param {Field[]} fields
170
174
  * @param {boolean}
171
175
  * @returns {Promise<object>}
172
176
  */
173
- const calcfldViewConfig = contract(is.fun([is.array(is.class("Field")), is.bool], is.promise(is.obj())), async (fields, isEdit, nrecurse = 2) => {
177
+ const calcfldViewConfig = async (fields, isEdit, nrecurse = 2) => {
174
178
  const fieldViewConfigForms = {};
175
179
  for (const f of fields) {
176
180
  f.fill_table();
@@ -195,7 +199,7 @@ const calcfldViewConfig = contract(is.fun([is.array(is.class("Field")), is.bool]
195
199
  }
196
200
  }
197
201
  return fieldViewConfigForms;
198
- });
202
+ };
199
203
  /**
200
204
  * @function
201
205
  * @param {Table|object} table
@@ -203,7 +207,7 @@ const calcfldViewConfig = contract(is.fun([is.array(is.class("Field")), is.bool]
203
207
  * @param {boolean}
204
208
  * @returns {Promise<object[]>}
205
209
  */
206
- const get_link_view_opts = contract(is.fun([is_tablely, is.str], is.promise(is.array(is.obj({ label: is.str, name: is.str })))), async (table, viewname) => {
210
+ const get_link_view_opts = async (table, viewname) => {
207
211
  const own_link_views = await View.find_possible_links_to_table(table);
208
212
  const link_view_opts = own_link_views
209
213
  .filter((v) => v.name !== viewname)
@@ -211,22 +215,21 @@ const get_link_view_opts = contract(is.fun([is_tablely, is.str], is.promise(is.a
211
215
  label: `${v.name} [${v.viewtemplate} ${table.name}]`,
212
216
  name: `Own:${v.name}`,
213
217
  }));
214
- const link_view_names = new Set();
218
+ const link_view_opts_push = (o) => {
219
+ if (!link_view_opts.map((v) => v.name).includes(o.name))
220
+ link_view_opts.push(o);
221
+ };
215
222
  const child_views = await get_child_views(table, viewname);
216
223
  for (const { relation, related_table, through, throughTable, views, } of child_views) {
217
224
  for (const view of views) {
218
225
  if (through && throughTable) {
219
- const name = `${view.name}.${related_table.name}.${relation.name}.${throughTable.name}.${through.name}`;
220
- link_view_names.add(name);
221
- link_view_opts.push({
222
- name: `ChildList:${view.name}.${related_table.name}.${relation.name}.${throughTable.name}.${through.name}`,
226
+ link_view_opts_push({
227
+ name: `ChildList:${view.name}.${throughTable.name}.${through.name}.${related_table.name}.${relation.name}`,
223
228
  label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.name}.${through.name}]`,
224
229
  });
225
230
  }
226
231
  else {
227
- const name = `${view.name}.${related_table.name}.${relation.name}`;
228
- link_view_names.add(name);
229
- link_view_opts.push({
232
+ link_view_opts_push({
230
233
  name: `ChildList:${view.name}.${related_table.name}.${relation.name}`,
231
234
  label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.name}]`,
232
235
  });
@@ -236,7 +239,7 @@ const get_link_view_opts = contract(is.fun([is_tablely, is.str], is.promise(is.a
236
239
  const parent_views = await get_parent_views(table, viewname);
237
240
  for (const { relation, related_table, views } of parent_views) {
238
241
  for (const view of views) {
239
- link_view_opts.push({
242
+ link_view_opts_push({
240
243
  name: `ParentShow:${view.name}.${related_table.name}.${relation.name}`,
241
244
  label: `${view.name} [${view.viewtemplate} ${relation.name}.${related_table.name}]`,
242
245
  });
@@ -245,23 +248,21 @@ const get_link_view_opts = contract(is.fun([is_tablely, is.str], is.promise(is.a
245
248
  const onetoone_views = await get_onetoone_views(table, viewname);
246
249
  for (const { relation, related_table, views } of onetoone_views) {
247
250
  for (const view of views) {
248
- const name = `${view.name}.${related_table.name}.${relation.name}`;
249
- if (!link_view_names.has(name))
250
- link_view_opts.push({
251
- name: `OneToOneShow:${view.name}.${related_table.name}.${relation.name}`,
252
- label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.label}]`,
253
- });
251
+ link_view_opts_push({
252
+ name: `OneToOneShow:${view.name}.${related_table.name}.${relation.name}`,
253
+ label: `${view.name} [${view.viewtemplate} ${related_table.name}.${relation.label}]`,
254
+ });
254
255
  }
255
256
  }
256
257
  const independent_views = await View.find_all_views_where(({ state_fields }) => !state_fields.some((sf) => sf.required));
257
258
  independent_views.forEach((view) => {
258
- link_view_opts.push({
259
+ link_view_opts_push({
259
260
  label: `${view.name} [${view.viewtemplate}]`,
260
261
  name: `Independent:${view.name}`,
261
262
  });
262
263
  });
263
264
  return link_view_opts;
264
- });
265
+ };
265
266
  /**
266
267
  * Get Action configuration fields
267
268
  * @param {object} action
@@ -278,7 +279,7 @@ const getActionConfigFields = async (action, table) => typeof action.configField
278
279
  * @param {object} req
279
280
  * @returns {Promise<object[]>}
280
281
  */
281
- const field_picker_fields = contract(is.fun(is.obj({ table: is_tablely, viewname: is.str }), is.promise(is.array(fieldlike))), async ({ table, viewname, req }) => {
282
+ const field_picker_fields = async ({ table, viewname, req }) => {
282
283
  const __ = (...s) => (req ? req.__(...s) : s.join(""));
283
284
  const fields = await table.getFields();
284
285
  for (const field of fields) {
@@ -697,7 +698,7 @@ const field_picker_fields = contract(is.fun(is.obj({ table: is_tablely, viewname
697
698
  },
698
699
  },
699
700
  ];
700
- });
701
+ };
701
702
  /**
702
703
  * get_child_views Contract
703
704
  * @function
@@ -705,11 +706,7 @@ const field_picker_fields = contract(is.fun(is.obj({ table: is_tablely, viewname
705
706
  * @param {string} viewname
706
707
  * @returns {Promise<object[]>}
707
708
  */
708
- const get_child_views = contract(is.fun([is_tablely, is.maybe(is.str)], is.promise(is.array(is.obj({
709
- relation: is.class("Field"),
710
- related_table: is.class("Table"),
711
- views: is.array(is.class("View")),
712
- })))), async (table, viewname, nrecurse = 2) => {
709
+ const get_child_views = async (table, viewname, nrecurse = 2) => {
713
710
  const rels = await Field.find({ reftable_name: table.name });
714
711
  const possibleThroughTables = new Set();
715
712
  var child_views = [];
@@ -736,7 +733,7 @@ const get_child_views = contract(is.fun([is_tablely, is.maybe(is.str)], is.promi
736
733
  });
737
734
  }
738
735
  return child_views;
739
- });
736
+ };
740
737
  /**
741
738
  * get_parent_views Contract
742
739
  * @function
@@ -744,35 +741,26 @@ const get_child_views = contract(is.fun([is_tablely, is.maybe(is.str)], is.promi
744
741
  * @param {string} viewname
745
742
  * @returns {Promise<object[]>}
746
743
  */
747
- const get_parent_views = contract(is.fun([is_tablely, is.str], is.promise(is.array(is.obj({
748
- relation: is.class("Field"),
749
- related_table: is.class("Table"),
750
- views: is.array(is.class("View")),
751
- })))), async (table, viewname) => {
744
+ const get_parent_views = async (table, viewname) => {
752
745
  var parent_views = [];
753
746
  const parentrels = (await table.getFields()).filter((f) => f.is_fkey && f.type !== "File");
754
747
  for (const relation of parentrels) {
755
748
  const related_table = await Table.findOne({
756
749
  name: relation.reftable_name,
757
750
  });
758
- const views = await View.find_table_views_where(related_table, ({ state_fields, viewrow }) => viewrow.name !== viewname &&
759
- state_fields.some((sf) => sf.name === "id"));
751
+ const views = await View.find_table_views_where(related_table, ({ state_fields, viewrow }) => viewrow.name !== viewname && state_fields.some((sf) => sf.name === "id"));
760
752
  parent_views.push({ relation, related_table, views });
761
753
  }
762
754
  return parent_views;
763
- });
755
+ };
764
756
  /**
765
757
  * get_onetoone_views Contract
766
758
  * @function
767
- * @param {Table|is_tablely} table
759
+ * @param {Table} table
768
760
  * @param {string} viewname
769
761
  * @returns {Promise<object[]>}
770
762
  */
771
- const get_onetoone_views = contract(is.fun([is_tablely, is.str], is.promise(is.array(is.obj({
772
- relation: is.class("Field"),
773
- related_table: is.class("Table"),
774
- views: is.array(is.class("View")),
775
- })))), async (table, viewname) => {
763
+ const get_onetoone_views = async (table, viewname) => {
776
764
  const rels = await Field.find({
777
765
  reftable_name: table.name,
778
766
  is_unique: true,
@@ -780,12 +768,11 @@ const get_onetoone_views = contract(is.fun([is_tablely, is.str], is.promise(is.a
780
768
  var child_views = [];
781
769
  for (const relation of rels) {
782
770
  const related_table = await Table.findOne({ id: relation.table_id });
783
- const views = await View.find_table_views_where(related_table.id, ({ state_fields, viewrow }) => viewrow.name !== viewname &&
784
- state_fields.some((sf) => sf.name === "id"));
771
+ const views = await View.find_table_views_where(related_table.id, ({ state_fields, viewrow }) => viewrow.name !== viewname && state_fields.some((sf) => sf.name === "id"));
785
772
  child_views.push({ relation, related_table, views });
786
773
  }
787
774
  return child_views;
788
- });
775
+ };
789
776
  /**
790
777
  * picked_fields_to_query Contract
791
778
  * @function
@@ -794,7 +781,7 @@ const get_onetoone_views = contract(is.fun([is_tablely, is.str], is.promise(is.a
794
781
  * @throws {InvalidConfiguration}
795
782
  * @returns {object}
796
783
  */
797
- const picked_fields_to_query = contract(is.fun([is.array(is_column), is.array(is.class("Field"))], is_table_query), (columns, fields) => {
784
+ const picked_fields_to_query = (columns, fields, layout) => {
798
785
  var joinFields = {};
799
786
  var aggregations = {};
800
787
  let freeVars = new Set(); // for join fields
@@ -844,9 +831,11 @@ const picked_fields_to_query = contract(is.fun([is.array(is_column), is.array(is
844
831
  }
845
832
  else if (column.type === "ViewLink") {
846
833
  if (column.view_label_formula)
834
+ freeVars = new Set([...freeVars, ...freeVariables(column.view_label)]);
835
+ if (column.extra_state_fml)
847
836
  freeVars = new Set([
848
837
  ...freeVars,
849
- ...freeVariables(column.view_label),
838
+ ...freeVariables(column.extra_state_fml),
850
839
  ]);
851
840
  if (column.view && column.view.split) {
852
841
  const [vtype, vrest] = column.view.split(":");
@@ -888,12 +877,20 @@ const picked_fields_to_query = contract(is.fun([is.array(is_column), is.array(is
888
877
  freeVars = new Set([...freeVars, ...freeVariables(column.link_url)]);
889
878
  }
890
879
  else if (column.type === "Action" && column.action_label_formula) {
891
- freeVars = new Set([
892
- ...freeVars,
893
- ...freeVariables(column.action_label),
894
- ]);
880
+ freeVars = new Set([...freeVars, ...freeVariables(column.action_label)]);
895
881
  }
896
882
  });
883
+ if (layout) {
884
+ traverse(layout, {
885
+ view(v) {
886
+ if (v.extra_state_fml)
887
+ freeVars = new Set([
888
+ ...freeVars,
889
+ ...freeVariables(v.extra_state_fml),
890
+ ]);
891
+ },
892
+ });
893
+ }
897
894
  [...freeVars]
898
895
  .filter((v) => v.includes("."))
899
896
  .map((v) => {
@@ -927,7 +924,7 @@ const picked_fields_to_query = contract(is.fun([is.array(is_column), is.array(is
927
924
  }
928
925
  });
929
926
  return { joinFields, aggregations };
930
- });
927
+ };
931
928
  /**
932
929
  * @function
933
930
  * @param {object}
@@ -935,7 +932,7 @@ const picked_fields_to_query = contract(is.fun([is.array(is_column), is.array(is
935
932
  * @param {string} - missing in contract
936
933
  * @returns {object}
937
934
  */
938
- const stateFieldsToQuery = contract(is.fun(is.obj(), is.obj()), ({ state, fields, prefix = "" }) => {
935
+ const stateFieldsToQuery = ({ state, fields, prefix = "" }) => {
939
936
  let q = {};
940
937
  const stateKeys = Object.keys(state);
941
938
  if (state._sortby) {
@@ -960,7 +957,7 @@ const stateFieldsToQuery = contract(is.fun(is.obj(), is.obj()), ({ state, fields
960
957
  q.orderBy = { distance: { lat, long, latField, longField } };
961
958
  }
962
959
  return q;
963
- });
960
+ };
964
961
  /**
965
962
  *
966
963
  * @param {object} container
@@ -982,14 +979,15 @@ const addOrCreateList = (container, key, x) => {
982
979
  * @param {boolean} [opts.approximate = true]
983
980
  * @returns {object}
984
981
  */
985
- const stateFieldsToWhere = contract(is.fun(is.obj({
986
- fields: is.array(is.class("Field")),
987
- approximate: is.maybe(is.bool),
988
- }), is.obj()), ({ fields, state, approximate = true }) => {
982
+ const stateFieldsToWhere = ({ fields, state, approximate = true }) => {
989
983
  var qstate = {};
990
984
  Object.entries(state).forEach(([k, v]) => {
991
985
  if (k === "_fts") {
992
- qstate[k] = { searchTerm: v.replace(/\0/g, ""), fields };
986
+ qstate[k] = {
987
+ searchTerm: v.replace(/\0/g, ""),
988
+ fields,
989
+ schema: db.getTenantSchema(),
990
+ };
993
991
  return;
994
992
  }
995
993
  const field = fields.find((fld) => fld.name == k);
@@ -1029,12 +1027,47 @@ const stateFieldsToWhere = contract(is.fun(is.obj({
1029
1027
  else if (field && field.type.name === "Bool" && state[k] === "?") {
1030
1028
  // omit
1031
1029
  }
1030
+ else if (typeof v === "object" &&
1031
+ Object.keys(v).length === 1 &&
1032
+ field?.type?.name === "JSON") {
1033
+ qstate[k] = [
1034
+ ...(qstate[k] ? [qstate[k]] : []),
1035
+ {
1036
+ // where jFieldNm in (select id from jtnm where lblField=v)
1037
+ json: [Object.keys(v)[0], Object.values(v)[0]],
1038
+ },
1039
+ ];
1040
+ }
1032
1041
  else if (field && field.type && field.type.read)
1033
1042
  qstate[k] = Array.isArray(v)
1034
1043
  ? { or: v.map(field.type.read) }
1035
1044
  : field.type.read(v);
1036
1045
  else if (field)
1037
1046
  qstate[k] = v;
1047
+ else if (k.includes("->")) {
1048
+ // jFieldNm.jtnm->lblField
1049
+ // where jFieldNm in (select id from jtnm where lblField=v)
1050
+ const [jFieldNm, krest] = k.split(".");
1051
+ const [jtNm, lblField] = krest.split("->");
1052
+ let where = { [db.sqlsanitize(lblField)]: v };
1053
+ const jTable = Table.findOne({ name: jtNm });
1054
+ const lblFld = (jTable.fields || []).find((f) => f.name === lblField);
1055
+ if (lblFld &&
1056
+ lblFld.type?.name === "String" &&
1057
+ !lblFld.attributes?.options)
1058
+ where = { [db.sqlsanitize(lblField)]: { ilike: v } };
1059
+ qstate[jFieldNm] = [
1060
+ ...(qstate[jFieldNm] ? [qstate[jFieldNm]] : []),
1061
+ {
1062
+ // where jFieldNm in (select id from jtnm where lblField=v)
1063
+ inSelect: {
1064
+ table: `${db.getTenantSchemaPrefix()}"${db.sqlsanitize(jtNm)}"`,
1065
+ field: "id",
1066
+ where,
1067
+ },
1068
+ },
1069
+ ];
1070
+ }
1038
1071
  else if (k.includes(".")) {
1039
1072
  const kpath = k.split(".");
1040
1073
  if (kpath.length === 3) {
@@ -1051,17 +1084,33 @@ const stateFieldsToWhere = contract(is.fun(is.obj({
1051
1084
  },
1052
1085
  ];
1053
1086
  }
1087
+ else if (kpath.length === 4) {
1088
+ const [jtNm, jFieldNm, tblName, lblField] = kpath;
1089
+ qstate.id = [
1090
+ ...(qstate.id ? [qstate.id] : []),
1091
+ {
1092
+ // where id in (select jFieldNm from jtnm where lblField=v)
1093
+ inSelect: {
1094
+ table: `${db.getTenantSchemaPrefix()}"${db.sqlsanitize(jtNm)}"`,
1095
+ field: db.sqlsanitize(jFieldNm),
1096
+ valField: "id",
1097
+ through: `${db.getTenantSchemaPrefix()}"${db.sqlsanitize(tblName)}"`,
1098
+ where: { [db.sqlsanitize(lblField)]: v },
1099
+ },
1100
+ },
1101
+ ];
1102
+ }
1054
1103
  }
1055
1104
  });
1056
1105
  return qstate;
1057
- });
1106
+ };
1058
1107
  /**
1059
1108
  * initial_config_all_fields Contract
1060
1109
  * @function
1061
1110
  * @param {boolean}
1062
1111
  * @returns {function}
1063
1112
  */
1064
- const initial_config_all_fields = contract(is.fun(is.bool, is.fun(is.obj({ table_id: is.posint }), is.promise(is.obj({ columns: is.array(is.obj()), layout: is.obj() })))), (isEdit) => async ({ table_id, exttable_name }) => {
1113
+ const initial_config_all_fields = (isEdit) => async ({ table_id, exttable_name }) => {
1065
1114
  const table = await Table.findOne(table_id ? { id: table_id } : { name: exttable_name });
1066
1115
  const fields = (await table.getFields()).filter((f) => !f.primary_key && (!isEdit || !f.calculated));
1067
1116
  var cfg = { columns: [] };
@@ -1153,7 +1202,7 @@ const initial_config_all_fields = contract(is.fun(is.bool, is.fun(is.obj({ table
1153
1202
  });
1154
1203
  cfg.layout = { above: aboves };
1155
1204
  return cfg;
1156
- });
1205
+ };
1157
1206
  /**
1158
1207
  *
1159
1208
  * @param {string} x
@@ -1328,7 +1377,6 @@ module.exports = {
1328
1377
  initial_config_all_fields,
1329
1378
  calcfldViewOptions,
1330
1379
  get_link_view_opts,
1331
- is_column,
1332
1380
  readState,
1333
1381
  readStateStrict,
1334
1382
  stateToQueryString,