adminizer 4.1.0-commit.ad1476a → 4.1.1

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 (292) hide show
  1. package/Readme.md +46 -0
  2. package/assets/{VanillaJSONEditor-FUe77pIA.js → VanillaJSONEditor-DfRefswH.js} +104 -104
  3. package/assets/add-CJ1-zeA1.js +1 -0
  4. package/assets/add-form-CbNl0wdS.js +1 -0
  5. package/assets/add-group-form-Bt_Dx9wm.js +1 -0
  6. package/assets/add-group-pIFJV5qL.js +1 -0
  7. package/assets/add-user-D2US8hL_.js +1 -0
  8. package/assets/add-user-form-Bt8Jy6S2.js +1 -0
  9. package/assets/{app-DMmad2-f.css → app-B6cCPfWk.css} +1 -1
  10. package/assets/app-layout-B86jl9bH.js +1 -0
  11. package/assets/app-shell-CiGyzQ0C.js +1 -0
  12. package/assets/app-sidebar-Bz-SRwBg.js +1 -0
  13. package/assets/app-sidebar-header-7CNCx7Rs.js +11 -0
  14. package/assets/app.js +45 -37
  15. package/assets/breadcrumbs-_jhtTcOi.js +1 -0
  16. package/assets/catalog-CON6moaA.js +16 -0
  17. package/assets/catalog-Cc6Mk9sX.css +1 -0
  18. package/assets/checkbox-CQdZw5mb.js +1 -0
  19. package/assets/dashboard-BOltB2Hq.css +1 -0
  20. package/assets/dashboard-es9ZT8qk.js +3 -0
  21. package/assets/{date-picker-B__dVVqj.js → date-picker-Dz-d-YWX.js} +2 -2
  22. package/assets/debounce-qdyXyOeG.js +1 -0
  23. package/assets/del-modal-D0mrZvki.js +11 -0
  24. package/assets/dialog-stack-BiMbfm58.js +1 -0
  25. package/assets/dropdown-menu-BSBcRiXx.js +1 -0
  26. package/assets/{field-renderer-CapylJU9.js → field-renderer-B6hFAeiU.js} +3 -3
  27. package/assets/form-Buslty7y.js +1 -0
  28. package/assets/form-aqiRmPix.js +1 -0
  29. package/assets/{geo-json-CwteYDGB.js → geo-json-BKmYmu3d.js} +2 -2
  30. package/assets/{handsontable-BCnjOpBr.js → handsontable-B8xVeMAQ.js} +5 -5
  31. package/assets/home-Dr72Jk-w.js +2 -0
  32. package/assets/icon-B-a7xg54.js +1 -0
  33. package/assets/index-B68_akQe.js +1 -0
  34. package/assets/index-B7-xTDyy.js +1 -0
  35. package/assets/index-BJFFlCSo.js +1 -0
  36. package/assets/{index-DTRTjOmh.js → index-BOuMo_nl.js} +3 -3
  37. package/assets/index-BzOcGsBq.js +1 -0
  38. package/assets/index-CFbQ2Rv0.js +1 -0
  39. package/assets/{index-D5ir9iUV.js → index-Cq31rrfZ.js} +1 -1
  40. package/assets/{index-BcE9FUM6.js → index-D5UDXTFs.js} +1 -1
  41. package/assets/index-oxIQWAdI.js +41 -0
  42. package/assets/init-user-5H689LP0.js +1 -0
  43. package/assets/input-CSJjrf2i.js +1 -0
  44. package/assets/input-error-CK92Shhm.js +1 -0
  45. package/assets/label-Muj0-Efy.js +1 -0
  46. package/assets/list-Cvh7zbyG.js +1 -0
  47. package/assets/list-table-Bs_vbQiV.js +52 -0
  48. package/assets/login-DliJrjMQ.js +6 -0
  49. package/assets/manifest.json +589 -666
  50. package/assets/material-icon-BRS58Qpk.js +1 -0
  51. package/assets/module-CjG21VCT.js +1 -0
  52. package/assets/{monaco-editor-DqAqwxw4.js → monaco-editor-9fDiyfuW.js} +2 -2
  53. package/assets/{multi-select-oabtVhUP.js → multi-select-CMQIJ0JT.js} +2 -2
  54. package/assets/nav-footer-IGMn9NiE.js +1 -0
  55. package/assets/nav-main-DBE4rMiZ.js +1 -0
  56. package/assets/nav-user-CjyLRyq-.js +1 -0
  57. package/assets/pagination-render-DUAq2klc.js +1 -0
  58. package/assets/popover-C_cww-4_.js +1 -0
  59. package/assets/register-UzQn3J0g.js +1 -0
  60. package/assets/{select-D1N8zRPY.js → select-DzBno-dc.js} +2 -2
  61. package/assets/{sidebar-4D-sX2l4.js → sidebar-Dc4iqfu-.js} +2 -2
  62. package/assets/skeleton-Dkmj2o2Z.js +1 -0
  63. package/assets/sonner-De1t71Gj.js +1 -0
  64. package/assets/{toast-editor-FbrFd1ft.js → toast-editor-1Pul3oMs.js} +2 -2
  65. package/assets/tooltip-CwPrC-HD.js +1 -0
  66. package/assets/use-appearance-J8J2w43p.js +1 -0
  67. package/assets/use-window-size-DLSEoR6e.js +1 -0
  68. package/assets/{user-info-DBYoAJYJ.js → user-info-8RyDk7qh.js} +2 -2
  69. package/assets/user-menu-content-CpxTLH56.js +6 -0
  70. package/assets/welcome-BYKI6yO-.js +1 -0
  71. package/controllers/add.js +10 -10
  72. package/controllers/addGroup.js +2 -4
  73. package/controllers/addUser.js +4 -6
  74. package/controllers/catalog/Catalog.d.ts +1 -1
  75. package/controllers/catalog/Catalog.js +42 -37
  76. package/controllers/catalog/FrontentCatalogAdapter.d.ts +36 -26
  77. package/controllers/catalog/FrontentCatalogAdapter.js +71 -73
  78. package/controllers/ckeditorUpload.js +2 -3
  79. package/controllers/dashboard.js +16 -2
  80. package/controllers/edit.js +10 -14
  81. package/controllers/editGroup.js +2 -4
  82. package/controllers/editUser.js +3 -5
  83. package/controllers/form.js +2 -3
  84. package/controllers/getAllWidgets.js +3 -3
  85. package/controllers/initUser.js +1 -2
  86. package/controllers/list.js +6 -6
  87. package/controllers/login.js +43 -18
  88. package/controllers/media-manager/mediaManagerAdapter.js +1 -2
  89. package/controllers/media-manager/mediaManagerApi.js +2 -2
  90. package/controllers/navigation/edit.js +2 -2
  91. package/controllers/register.js +1 -4
  92. package/controllers/remove.js +3 -3
  93. package/controllers/timezones.js +1 -1
  94. package/controllers/view.js +3 -3
  95. package/controllers/welcome.js +1 -1
  96. package/controllers/widgets/Action.js +2 -2
  97. package/controllers/widgets/Custom.js +2 -2
  98. package/controllers/widgets/Info.js +2 -2
  99. package/controllers/widgets/switch.js +2 -2
  100. package/controllers/widgetsDB.js +5 -5
  101. package/helpers/JsUtils.d.ts +1 -0
  102. package/helpers/JsUtils.js +3 -0
  103. package/helpers/accessRightsHelper.d.ts +6 -2
  104. package/helpers/accessRightsHelper.js +28 -5
  105. package/helpers/configHelper.js +2 -1
  106. package/helpers/controllerHelper.js +39 -18
  107. package/helpers/fieldsHelper.d.ts +4 -3
  108. package/helpers/fieldsHelper.js +5 -1
  109. package/helpers/inertiaActionsHelper.js +1 -1
  110. package/helpers/inertiaAddHelper.d.ts +3 -4
  111. package/helpers/inertiaAddHelper.js +27 -7
  112. package/helpers/inertiaFromHelper.js +2 -0
  113. package/helpers/inertiaGroupHelper.d.ts +4 -2
  114. package/helpers/inertiaGroupHelper.js +1 -1
  115. package/helpers/inertiaListHelper.js +5 -5
  116. package/helpers/inertiaMenuHelper.d.ts +1 -1
  117. package/helpers/inertiaMenuHelper.js +2 -2
  118. package/helpers/inertiaUserHelper.d.ts +7 -1
  119. package/helpers/inertiaUserHelper.js +5 -1
  120. package/helpers/menuHelper.d.ts +8 -3
  121. package/helpers/menuHelper.js +26 -17
  122. package/index.d.ts +6 -3
  123. package/index.js +9 -3
  124. package/interfaces/adminpanelConfig.d.ts +41 -32
  125. package/interfaces/global.d.ts +10 -28
  126. package/interfaces/types.d.ts +1 -1
  127. package/lib/Adminizer.d.ts +11 -3
  128. package/lib/Adminizer.js +49 -17
  129. package/lib/media-manager/AbstractMediaManager.d.ts +2 -2
  130. package/lib/media-manager/AbstractMediaManager.js +1 -1
  131. package/lib/media-manager/Items.js +0 -3
  132. package/lib/requestProcessor.js +10 -3
  133. package/lib/v4/DataAccessor.d.ts +5 -2
  134. package/lib/v4/DataAccessor.js +44 -19
  135. package/lib/v4/I18n.js +2 -0
  136. package/lib/v4/POWCaptcha.js +0 -1
  137. package/lib/v4/PolicyManager.js +0 -1
  138. package/lib/{catalog → v4/catalog}/AbstractCatalog.d.ts +89 -60
  139. package/lib/{catalog → v4/catalog}/AbstractCatalog.js +59 -55
  140. package/lib/v4/catalog/Navigation.d.ts +43 -0
  141. package/lib/v4/catalog/Navigation.js +457 -0
  142. package/lib/{controls → v4/controls}/AbstractControls.d.ts +1 -1
  143. package/lib/{controls → v4/controls}/codeEditor/MonacoEditor.d.ts +1 -1
  144. package/lib/{controls → v4/controls}/geojsoneditor/GeoEditor.d.ts +1 -1
  145. package/lib/{controls → v4/controls}/jsoneditor/JsonEditor.d.ts +1 -1
  146. package/lib/{controls → v4/controls}/markdown/ToastUiEditor.d.ts +1 -1
  147. package/lib/{controls → v4/controls}/table/Handsontable.d.ts +1 -1
  148. package/lib/{controls → v4/controls}/wysiwyg/CKeditor.d.ts +1 -1
  149. package/lib/{datatable → v4/datatable}/NodeTable.d.ts +3 -3
  150. package/lib/{datatable → v4/datatable}/NodeTable.js +8 -8
  151. package/lib/v4/helper/jwt.d.ts +10 -0
  152. package/lib/v4/helper/jwt.js +18 -0
  153. package/lib/{inertia → v4/inertia}/inertiaAdapter.js +0 -1
  154. package/lib/v4/model/AbstractModel.d.ts +5 -1
  155. package/lib/v4/model/AbstractModel.js +2 -3
  156. package/lib/v4/model/ModelHandler.js +1 -4
  157. package/lib/v4/model/adapter/sequelize.d.ts +11 -2
  158. package/lib/v4/model/adapter/sequelize.js +451 -118
  159. package/lib/v4/model/adapter/waterline.js +5 -3
  160. package/lib/{widgets → v4/widgets}/abstractAction.d.ts +1 -1
  161. package/lib/v4/widgets/abstractCustom.d.ts +28 -0
  162. package/lib/v4/widgets/abstractCustom.js +9 -0
  163. package/lib/{widgets → v4/widgets}/abstractInfo.d.ts +1 -1
  164. package/lib/{widgets → v4/widgets}/abstractInfo.js +1 -1
  165. package/lib/{widgets → v4/widgets}/abstractLink.d.ts +2 -1
  166. package/lib/{widgets → v4/widgets}/abstractSwitch.d.ts +1 -1
  167. package/lib/{widgets → v4/widgets}/abstractWidgetBase.d.ts +2 -2
  168. package/lib/{widgets → v4/widgets}/widgetHandler.d.ts +29 -5
  169. package/lib/{widgets → v4/widgets}/widgetHandler.js +25 -25
  170. package/models/GroupAP.d.ts +8 -0
  171. package/models/NavigationAP.d.ts +7 -3
  172. package/models/NavigationAP.js +5 -6
  173. package/models/UserAP.d.ts +24 -2
  174. package/models/UserAP.js +2 -2
  175. package/package.json +29 -11
  176. package/policies/checkAuth.js +4 -3
  177. package/policies/setLocale.js +2 -2
  178. package/system/Router.js +14 -17
  179. package/system/bindAccessRights.js +0 -4
  180. package/system/bindAuthorization.js +4 -5
  181. package/system/bindControls.js +6 -6
  182. package/system/bindDev.js +1 -0
  183. package/system/bindInertia.js +17 -12
  184. package/system/bindMediaManager.js +0 -1
  185. package/system/bindModels.js +9 -6
  186. package/system/bindNavigation.d.ts +2 -0
  187. package/system/bindNavigation.js +42 -42
  188. package/system/bindReqFunctions.js +15 -0
  189. package/system/defaults.js +13 -6
  190. package/translations/ar.json +70 -1
  191. package/translations/cn.json +70 -1
  192. package/translations/de.json +71 -3
  193. package/translations/en.json +70 -102
  194. package/translations/es.json +70 -1
  195. package/translations/fr.json +70 -1
  196. package/translations/hi.json +70 -1
  197. package/translations/jp.json +70 -1
  198. package/translations/ko.json +70 -1
  199. package/translations/pt.json +70 -1
  200. package/translations/ru.json +71 -94
  201. package/translations/ua.json +70 -1
  202. package/translations/uz.json +72 -0
  203. package/translations/vi.json +70 -1
  204. package/assets/add-ZITr43GJ.js +0 -1
  205. package/assets/add-form-CYOfr0Ef.js +0 -1
  206. package/assets/add-group-B332wN8K.js +0 -1
  207. package/assets/add-group-form-dzadPSfL.js +0 -1
  208. package/assets/add-user-TC-mYdsB.js +0 -1
  209. package/assets/add-user-form-y2f_1_lM.js +0 -1
  210. package/assets/app-layout-D1m9Kvxq.js +0 -1
  211. package/assets/app-shell-BWMRMkHM.js +0 -1
  212. package/assets/app-sidebar-BCtaEFGb.js +0 -1
  213. package/assets/app-sidebar-header-DLAFi13E.js +0 -11
  214. package/assets/breadcrumbs-CQNon4Vl.js +0 -1
  215. package/assets/button-CQ9t1kLz.js +0 -1
  216. package/assets/checkbox-W0nGAXIj.js +0 -1
  217. package/assets/compiler-runtime-tM4jBQ-T.js +0 -9
  218. package/assets/dashboard-BR602KhL.js +0 -1
  219. package/assets/dropdown-menu-SEBnEIiL.js +0 -1
  220. package/assets/form-DOUNk3o2.js +0 -1
  221. package/assets/form-lOKv4Qbw.js +0 -1
  222. package/assets/home-Ch6QfTIt.js +0 -2
  223. package/assets/icon-Bz9BMaD0.js +0 -1
  224. package/assets/index-BC0yfOHo.js +0 -1
  225. package/assets/index-BbXEMx9n.js +0 -1
  226. package/assets/index-C0SL3SHw.js +0 -41
  227. package/assets/index-Cdb9ACvz.js +0 -1
  228. package/assets/index-DEk3sC8d.js +0 -1
  229. package/assets/index-DrWfGwtf.js +0 -1
  230. package/assets/index-K81GbF6O.js +0 -1
  231. package/assets/init-user-D9mW-g14.js +0 -1
  232. package/assets/input-DF7Ue23C.js +0 -1
  233. package/assets/input-error-BBygona6.js +0 -1
  234. package/assets/label-Z506NKsW.js +0 -1
  235. package/assets/list-Qyd7ecQH.js +0 -1
  236. package/assets/list-table-DB1sEQLF.js +0 -62
  237. package/assets/login-DrGaTWhY.js +0 -6
  238. package/assets/material-icon-CItZiB53.js +0 -1
  239. package/assets/module-DBaykv8l.js +0 -1
  240. package/assets/nav-footer-CM-yHiRs.js +0 -1
  241. package/assets/nav-main-Q3xofGRT.js +0 -1
  242. package/assets/nav-user-Ds8i0Pa2.js +0 -1
  243. package/assets/pagination-render-B57pOpFy.js +0 -1
  244. package/assets/popover-I249Gg2O.js +0 -1
  245. package/assets/register-C9FQIDtS.js +0 -1
  246. package/assets/sonner-Dzckw3U3.js +0 -1
  247. package/assets/tooltip-D2ehgLlB.js +0 -1
  248. package/assets/use-appearance-Co6mO0dV.js +0 -1
  249. package/assets/use-window-size-B8l6Bpkf.js +0 -1
  250. package/assets/user-menu-content-qkvdkUVd.js +0 -6
  251. package/assets/utils-DjqsqOe8.js +0 -1
  252. package/assets/welcome-D2adQ8EU.js +0 -1
  253. package/controllers/processInstallFinalize.d.ts +0 -1
  254. package/controllers/processInstallFinalize.js +0 -16
  255. package/controllers/processInstallStep.d.ts +0 -1
  256. package/controllers/processInstallStep.js +0 -132
  257. package/lib/catalog/Navigation.d.ts +0 -0
  258. package/lib/catalog/Navigation.js +0 -532
  259. package/lib/installStepper/InstallStepAbstract.d.ts +0 -52
  260. package/lib/installStepper/InstallStepAbstract.js +0 -69
  261. package/lib/installStepper/finalizeStep.d.ts +0 -21
  262. package/lib/installStepper/finalizeStep.js +0 -48
  263. package/lib/installStepper/installStepper.d.ts +0 -40
  264. package/lib/installStepper/installStepper.js +0 -195
  265. package/lib/widgets/abstractCustom.d.ts +0 -13
  266. package/lib/widgets/abstractCustom.js +0 -3
  267. package/models/MediaManagerAP.d.ts +0 -46
  268. package/models/MediaManagerAP.js +0 -45
  269. package/models/MediaManagerAssociationsAP.d.ts +0 -28
  270. package/models/MediaManagerAssociationsAP.js +0 -27
  271. package/models/MediaManagerMetaAP.d.ts +0 -22
  272. package/models/MediaManagerMetaAP.js +0 -21
  273. package/system/bindInstallStepper.d.ts +0 -2
  274. package/system/bindInstallStepper.js +0 -23
  275. /package/lib/{catalog → v4/catalog}/CatalogHandler.d.ts +0 -0
  276. /package/lib/{catalog → v4/catalog}/CatalogHandler.js +0 -0
  277. /package/lib/{controls → v4/controls}/AbstractControls.js +0 -0
  278. /package/lib/{controls → v4/controls}/ControlsHandler.d.ts +0 -0
  279. /package/lib/{controls → v4/controls}/ControlsHandler.js +0 -0
  280. /package/lib/{controls → v4/controls}/codeEditor/MonacoEditor.js +0 -0
  281. /package/lib/{controls → v4/controls}/geojsoneditor/GeoEditor.js +0 -0
  282. /package/lib/{controls → v4/controls}/jsoneditor/JsonEditor.js +0 -0
  283. /package/lib/{controls → v4/controls}/markdown/ToastUiEditor.js +0 -0
  284. /package/lib/{controls → v4/controls}/table/Handsontable.js +0 -0
  285. /package/lib/{controls → v4/controls}/wysiwyg/CKeditor.js +0 -0
  286. /package/lib/{inertia → v4/inertia}/flash.d.ts +0 -0
  287. /package/lib/{inertia → v4/inertia}/flash.js +0 -0
  288. /package/lib/{inertia → v4/inertia}/inertiaAdapter.d.ts +0 -0
  289. /package/lib/{widgets → v4/widgets}/abstractAction.js +0 -0
  290. /package/lib/{widgets → v4/widgets}/abstractLink.js +0 -0
  291. /package/lib/{widgets → v4/widgets}/abstractSwitch.js +0 -0
  292. /package/lib/{widgets → v4/widgets}/abstractWidgetBase.js +0 -0
@@ -3,162 +3,456 @@ import { AbstractAdapter, AbstractModel } from "../AbstractModel";
3
3
  import path from "path";
4
4
  import fs from "fs";
5
5
  import { pathToFileURL } from "url";
6
- function mapSequelizeAttributesToAbstract(attrs) {
7
- const result = {};
8
- for (const key in attrs) {
9
- const attr = attrs[key];
10
- const resolvedType = resolveType(attr.type);
11
- result[key] = {
12
- type: resolvedType,
13
- required: !attr.allowNull,
14
- primaryKey: !!attr.primaryKey,
15
- unique: !!attr.unique,
16
- };
6
+ function generateAssociationsFromSchema(models, schemas) {
7
+ for (const modelName in schemas) {
8
+ const schema = schemas[modelName];
9
+ const model = models[modelName];
10
+ if (!model)
11
+ continue;
12
+ for (const fieldName in schema) {
13
+ const field = schema[fieldName];
14
+ if (field.collection && field.via) {
15
+ const targetModel = models[field.collection];
16
+ const targetSchema = schemas[field.collection];
17
+ const inverseField = targetSchema?.[field.via];
18
+ const throughTableName = [modelName, field.collection].sort().join("");
19
+ // 💡 M:N связь
20
+ if (inverseField && inverseField.collection === modelName) {
21
+ model.belongsToMany(targetModel, {
22
+ through: throughTableName,
23
+ as: fieldName,
24
+ foreignKey: `${modelName}Id`,
25
+ otherKey: `${field.collection}Id`
26
+ });
27
+ }
28
+ // 💡 O:M связь (один ко многим)
29
+ else {
30
+ model.hasMany(targetModel, {
31
+ as: fieldName,
32
+ foreignKey: `${modelName}Id`,
33
+ });
34
+ targetModel.belongsTo(model, {
35
+ as: field.via,
36
+ foreignKey: `${modelName}Id`,
37
+ });
38
+ }
39
+ }
40
+ // 💡 O:1 или 1:1 (belongsTo)
41
+ if (field.model) {
42
+ const targetModel = models[field.model];
43
+ if (!targetModel)
44
+ continue;
45
+ // Avoid naming collision by making FK explicit: `${fieldName}Id`
46
+ const foreignKey = `${fieldName}Id`;
47
+ const alias = fieldName;
48
+ // Если поле уже существует — избегаем конфликта
49
+ if (model.rawAttributes[alias]) {
50
+ model.belongsTo(targetModel, {
51
+ as: alias,
52
+ foreignKey,
53
+ });
54
+ }
55
+ else {
56
+ model.belongsTo(targetModel, {
57
+ foreignKey: alias, // если нет конфликта, можно использовать alias как FK
58
+ });
59
+ }
60
+ }
61
+ }
17
62
  }
18
- return result;
19
63
  }
20
64
  function resolveType(type) {
21
- try {
22
- const sqlType = typeof type.toString === "function"
23
- ? type.toString().toLowerCase()
24
- : "";
25
- if (sqlType.includes("string"))
26
- return "string";
27
- if (sqlType.includes("uuid"))
28
- return "string";
29
- if (sqlType.includes("int") || sqlType.includes("float") || sqlType.includes("decimal"))
30
- return "number";
31
- if (sqlType.includes("bool"))
32
- return "boolean";
33
- if (sqlType.includes("json"))
34
- return "json";
35
- if (sqlType.includes("date"))
36
- return "string"; // 👈 фикс: дата как строка
37
- return "ref";
38
- }
39
- catch {
40
- return "ref";
41
- }
65
+ const sqlType = typeof type.toString === "function"
66
+ ? type.toString().toLowerCase()
67
+ : "";
68
+ if (sqlType.includes("string") || sqlType.includes("uuid"))
69
+ return "string";
70
+ if (sqlType.includes("int") || sqlType.includes("float") || sqlType.includes("decimal"))
71
+ return "number";
72
+ if (sqlType.includes("bool"))
73
+ return "boolean";
74
+ if (sqlType.includes("json"))
75
+ return "json";
76
+ if (sqlType.includes("date"))
77
+ return "string";
78
+ return "ref";
42
79
  }
43
- /** SequelizeModel реализация модели, совместимая с AbstractModel */
44
- function convertCriteriaToSequelize(criteria) {
45
- console.log("waterline criteria", criteria);
80
+ export function mapSequelizeToWaterline(model) {
46
81
  const result = {};
47
- for (const key in criteria) {
48
- const value = criteria[key];
49
- if (value === undefined ||
50
- value === null ||
51
- (typeof value === "object" && Object.keys(value).length === 0)) {
52
- continue; // пропускаем пустые условия
53
- }
54
- if (typeof value === "object" && !Array.isArray(value)) {
55
- const operatorEntries = Object.entries(value)
56
- .filter(([_, v]) => v !== undefined && v !== null)
57
- .map(([op, val]) => {
58
- switch (op) {
59
- case "contains": return [Op.like, `%${val}%`];
60
- case "startsWith": return [Op.startsWith, val];
61
- case "endsWith": return [Op.endsWith, val];
62
- case ">": return [Op.gt, val];
63
- case ">=": return [Op.gte, val];
64
- case "<": return [Op.lt, val];
65
- case "<=": return [Op.lte, val];
66
- case "!=": return [Op.ne, val];
67
- case "in": return [Op.in, val];
68
- case "nin": return [Op.notIn, val];
69
- default: return [Op.eq, val];
70
- }
71
- });
72
- if (operatorEntries.length > 0) {
73
- result[key] = Object.fromEntries(operatorEntries);
82
+ const rawAttrs = model.getAttributes();
83
+ for (const name in rawAttrs) {
84
+ const meta = rawAttrs[name];
85
+ result[name] = {
86
+ type: resolveType(meta.type),
87
+ required: meta.allowNull !== undefined ? !meta.allowNull : false,
88
+ allowNull: meta.allowNull,
89
+ unique: !!meta.unique,
90
+ defaultsTo: meta.defaultValue,
91
+ columnName: meta.field || name,
92
+ };
93
+ }
94
+ for (const alias in model.associations) {
95
+ const assoc = model.associations[alias];
96
+ switch (assoc.associationType) {
97
+ case "BelongsTo": {
98
+ const a = assoc;
99
+ result[a.foreignKey]["primaryKeyForAssociation"] = true;
100
+ result[alias] = {
101
+ type: "association",
102
+ model: a.target.name,
103
+ via: a.foreignKey,
104
+ };
105
+ break;
74
106
  }
75
- }
76
- else {
77
- result[key] = value;
107
+ case "HasOne": {
108
+ const a = assoc;
109
+ result[a.foreignKey]["primaryKeyForAssociation"] = true;
110
+ result[alias] = {
111
+ type: "association",
112
+ model: a.target.name,
113
+ via: a.foreignKey,
114
+ };
115
+ break;
116
+ }
117
+ case "HasMany": {
118
+ const a = assoc;
119
+ result[alias] = {
120
+ type: "association-many",
121
+ collection: a.target.name,
122
+ via: a.foreignKey,
123
+ };
124
+ break;
125
+ }
126
+ case "BelongsToMany": {
127
+ const a = assoc;
128
+ result[alias] = {
129
+ type: "association-many",
130
+ collection: a.target.name,
131
+ via: a.otherKey,
132
+ };
133
+ break;
134
+ }
135
+ default:
136
+ break;
78
137
  }
79
138
  }
80
139
  return result;
81
140
  }
82
- function convertWaterlineCriteriaToSequelizeOptions(criteria) {
83
- console.log("WATERLINE CRITERIA", criteria);
84
- const { where = {}, skip, limit, sort } = criteria;
85
- const result = {
86
- where: convertCriteriaToSequelize(where),
87
- };
88
- if (typeof skip === "number") {
89
- result.offset = skip;
90
- }
91
- if (typeof limit === "number") {
92
- result.limit = limit;
93
- }
94
- if (typeof sort === "string") {
95
- const [field, direction] = sort.trim().split(/\s+/);
96
- result.order = [[field, direction?.toUpperCase() === "DESC" ? "DESC" : "ASC"]];
97
- }
98
- return result;
141
+ function capitalize(str) {
142
+ return str.charAt(0).toUpperCase() + str.slice(1);
99
143
  }
100
144
  export class SequelizeModel extends AbstractModel {
101
145
  model;
102
146
  constructor(modelName, model) {
103
- super(modelName, mapSequelizeAttributesToAbstract(model.getAttributes()), model.primaryKeyAttribute, model.name);
147
+ super(modelName, mapSequelizeToWaterline(model), model.primaryKeyAttribute, model.name);
104
148
  this.model = model;
105
149
  }
150
+ _convertCriteriaToSequelize(criteria) {
151
+ const result = {};
152
+ for (const key in criteria) {
153
+ const value = criteria[key];
154
+ if (value === undefined ||
155
+ value === null ||
156
+ (typeof value === "object" && Object.keys(value).length === 0)) {
157
+ continue;
158
+ }
159
+ // 🧠 Заменяем ключ на `via`, если это ассоциация
160
+ const attr = this.attributes?.[key];
161
+ let targetKey = key;
162
+ if (attr?.type === "association" && attr.via) {
163
+ targetKey = attr.via;
164
+ }
165
+ if (typeof value === "object" && !Array.isArray(value)) {
166
+ const operatorEntries = Object.entries(value)
167
+ .filter(([_, v]) => v !== undefined && v !== null)
168
+ .map(([op, val]) => {
169
+ switch (op) {
170
+ case "contains": return [Op.like, `%${val}%`];
171
+ case "startsWith": return [Op.startsWith, val];
172
+ case "endsWith": return [Op.endsWith, val];
173
+ case ">": return [Op.gt, val];
174
+ case ">=": return [Op.gte, val];
175
+ case "<": return [Op.lt, val];
176
+ case "<=": return [Op.lte, val];
177
+ case "!=": return [Op.ne, val];
178
+ case "in": return [Op.in, val];
179
+ case "nin": return [Op.notIn, val];
180
+ default: return [Op.eq, val];
181
+ }
182
+ });
183
+ if (operatorEntries.length > 0) {
184
+ result[targetKey] = Object.fromEntries(operatorEntries);
185
+ }
186
+ }
187
+ else {
188
+ result[targetKey] = value;
189
+ }
190
+ }
191
+ return result;
192
+ }
193
+ _convertWaterlineCriteriaToSequelizeOptions(criteria) {
194
+ // console.debug("WATERLINE CRITERIA (raw):", criteria);
195
+ const { where: nestedWhere, skip, limit, sort, ...rest } = criteria;
196
+ const rawWhere = (nestedWhere && Object.keys(nestedWhere).length > 0)
197
+ ? nestedWhere
198
+ : rest;
199
+ // console.debug("WATERLINE CRITERIA: using rawWhere =", rawWhere);
200
+ const where = this._convertCriteriaToSequelize(rawWhere);
201
+ const result = { where };
202
+ if (typeof skip === "number") {
203
+ result.offset = skip;
204
+ // console.debug("→ offset =", skip);
205
+ }
206
+ if (typeof limit === "number") {
207
+ result.limit = limit;
208
+ // console.debug("→ limit =", limit);
209
+ }
210
+ if (typeof sort === "string") {
211
+ const [field, dir] = sort.trim().split(/\s+/);
212
+ result.order = [[field, dir?.toUpperCase() === "DESC" ? "DESC" : "ASC"]];
213
+ // console.debug("→ order =", result.order);
214
+ }
215
+ return result;
216
+ }
217
+ async _assignAssociations(instance, assocData) {
218
+ for (const [alias, ids] of Object.entries(assocData)) {
219
+ const assoc = this.model.associations[alias];
220
+ if (!assoc)
221
+ continue;
222
+ //@ts-ignore
223
+ const { set: setAccessor, add: addAccessor } = assoc.accessors;
224
+ if (Array.isArray(ids)) {
225
+ if (typeof instance[setAccessor] === 'function') {
226
+ await instance[setAccessor](ids);
227
+ continue;
228
+ }
229
+ if (typeof instance[addAccessor] === 'function') {
230
+ for (const id of ids) {
231
+ await instance[addAccessor](id);
232
+ }
233
+ continue;
234
+ }
235
+ }
236
+ if (typeof instance[setAccessor] === 'function') {
237
+ await instance[setAccessor](ids);
238
+ }
239
+ else if (typeof instance[addAccessor] === 'function') {
240
+ await instance[addAccessor](ids);
241
+ }
242
+ }
243
+ }
106
244
  // --- CREATE ---
107
245
  async _create(data) {
108
- const created = await this.model.create(data);
109
- const result = await this.model.findByPk(created.get(this.primaryKey), { raw: true });
110
- return result;
246
+ // console.clear()
247
+ const assocNames = Object.keys(this.model.associations);
248
+ const plainData = {};
249
+ const assocData = {};
250
+ // console.debug(">> _create: входные данные:", data);
251
+ // console.debug(">> Доступные ассоциации:", assocNames);
252
+ for (const [key, val] of Object.entries(data)) {
253
+ if (assocNames.includes(key)) {
254
+ assocData[key] = val;
255
+ }
256
+ else {
257
+ plainData[key] = val;
258
+ }
259
+ }
260
+ // console.debug(">> Обычные поля для create():", plainData);
261
+ // console.debug(">> Данные ассоциаций:", assocData);
262
+ let instance;
263
+ try {
264
+ instance = await this.model.create(plainData);
265
+ // console.debug(">> Создан экземпляр (без ассоциаций):", instance.toJSON());
266
+ }
267
+ catch (err) {
268
+ // console.error("!! Ошибка при create(plainData):", err);
269
+ throw err;
270
+ }
271
+ // assocData = { example: 5, userAPs: [1,2,3], category: 7, tags: [11,22] }
272
+ // this.model.associations — ваш объект ассоциаций
273
+ for (const [alias, ids] of Object.entries(assocData)) {
274
+ const assoc = this.model.associations[alias];
275
+ if (!assoc) {
276
+ // console.warn(`Association "${alias}" not defined on model`);
277
+ continue;
278
+ }
279
+ // @ts-ignore accessors is present
280
+ const { set: setAccessor, add: addAccessor } = assoc.accessors;
281
+ if (Array.isArray(ids)) {
282
+ if (typeof instance[setAccessor] === 'function') {
283
+ await instance[setAccessor](ids);
284
+ continue;
285
+ }
286
+ if (typeof instance[addAccessor] === 'function') {
287
+ for (const id of ids) {
288
+ await instance[addAccessor](id);
289
+ }
290
+ continue;
291
+ }
292
+ }
293
+ if (typeof instance[setAccessor] === 'function') {
294
+ await instance[setAccessor](ids);
295
+ }
296
+ else if (typeof instance[addAccessor] === 'function') {
297
+ await instance[addAccessor](ids);
298
+ }
299
+ else {
300
+ // console.warn(`No suitable accessor for "${alias}": tried set=${setAccessor}, add=${addAccessor}`);
301
+ }
302
+ }
303
+ await instance.reload({ include: Object.values(this.model.associations) });
304
+ const pk = this.primaryKey;
305
+ const fresh = await this.model.findByPk(instance.get(pk), { include: assocNames.map(a => ({ association: a })) });
306
+ // console.debug(">> Результат после reload:", fresh?.toJSON());
307
+ return fresh;
111
308
  }
112
309
  // --- FIND ONE ---
113
310
  async _findOne(criteria) {
114
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
115
- const result = await this.model.findOne({
116
- where,
117
- include: this._buildIncludes(),
118
- raw: true,
119
- });
120
- return result;
311
+ // console.debug(">> _findOne: входные критерии:", criteria);
312
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
313
+ const includes = this._buildIncludes();
314
+ // console.debug(">> _findOne: преобразованные where:", where);
315
+ // console.debug(">> _findOne: includes:", includes);
316
+ let instance = null;
317
+ try {
318
+ instance = await this.model.findOne({ where, include: includes });
319
+ // console.debug(">> _findOne: сырое instance:", instance ? instance.toJSON() : null);
320
+ }
321
+ catch (err) {
322
+ // console.error("!! _findOne: ошибка при вызове findOne:", err);
323
+ throw err;
324
+ }
325
+ if (!instance) {
326
+ // console.debug(">> _findOne: ничего не найдено");
327
+ return null;
328
+ }
329
+ const plain = instance.get({ plain: true });
330
+ // console.debug(">> _findOne: plain результат:", plain);
331
+ return plain;
121
332
  }
122
333
  // --- FIND MANY ---
123
334
  async _find(criteria = {}, options = {}) {
124
- const { where, limit, offset, order } = convertWaterlineCriteriaToSequelizeOptions(criteria);
125
- const include = options.populate
335
+ const assocNames = Object.keys(this.model.associations);
336
+ // console.debug(">> _find: входные criteria:", criteria, "options:", options);
337
+ const { where, limit, offset, order } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
338
+ const includes = options.populate
126
339
  ? options.populate.map(([field, opts]) => ({ association: field, ...opts }))
127
- : this._buildIncludes();
128
- const result = await this.model.findAll({
340
+ : assocNames.map(a => ({ association: a }));
341
+ // console.debug(">> _find: where, limit, offset, order, includes:", {
342
+ // where,
343
+ // limit,
344
+ // offset,
345
+ // order,
346
+ // includes,
347
+ // });
348
+ let instances;
349
+ instances = await this.model.findAll({
129
350
  where,
130
351
  limit,
131
352
  offset,
132
353
  order,
133
- include,
134
- raw: true,
354
+ include: includes
135
355
  });
136
- return result;
356
+ for (const inst of instances) {
357
+ //For each association, we call getxxx () once again
358
+ for (const alias of assocNames) {
359
+ // @ts-ignore accessors is present
360
+ const getAccessor = this.model.associations[alias].accessors.get;
361
+ if (typeof inst[getAccessor] === "function") {
362
+ try {
363
+ const related = await inst[getAccessor]();
364
+ const mapped = Array.isArray(related)
365
+ ? related.map((r) => r.toJSON())
366
+ : related?.toJSON();
367
+ // console.debug(`---- get${alias}():`, mapped);
368
+ }
369
+ catch (e) {
370
+ // console.error(`!! ошибка при вызове ${getAccessor}():`, e);
371
+ }
372
+ }
373
+ }
374
+ }
375
+ const plain = instances.map(i => i.get({ plain: true }));
376
+ // console.debug(">> _find: plain результаты:", plain);
377
+ return plain;
137
378
  }
138
379
  // --- UPDATE ONE ---
139
380
  async _updateOne(criteria, data) {
140
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
381
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
141
382
  const record = await this.model.findOne({ where });
142
- if (!record) {
383
+ if (!record)
143
384
  return null;
385
+ const assocNames = Object.keys(this.model.associations);
386
+ const plainData = {};
387
+ const assocData = {};
388
+ for (const [key, val] of Object.entries(data)) {
389
+ if (assocNames.includes(key)) {
390
+ assocData[key] = val;
391
+ }
392
+ else {
393
+ plainData[key] = val;
394
+ }
144
395
  }
145
- await record.update(data);
146
- const result = await this.model.findByPk(record.get(this.primaryKey), { raw: true });
147
- return result;
396
+ await record.update(plainData);
397
+ await this._assignAssociations(record, assocData);
398
+ await record.reload({ include: Object.values(this.model.associations) });
399
+ return record.get({ plain: true });
148
400
  }
149
401
  // --- UPDATE MANY ---
150
402
  async _update(criteria, data) {
151
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
152
- await this.model.update(data, { where });
153
- const result = await this.model.findAll({ where, raw: true });
154
- return result;
403
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
404
+ const assocNames = Object.keys(this.model.associations);
405
+ const plainData = {};
406
+ const assocData = {};
407
+ for (const [key, val] of Object.entries(data)) {
408
+ if (assocNames.includes(key)) {
409
+ assocData[key] = val;
410
+ }
411
+ else {
412
+ plainData[key] = val;
413
+ }
414
+ }
415
+ const records = await this.model.findAll({ where });
416
+ for (const record of records) {
417
+ await record.update(plainData);
418
+ await this._assignAssociations(record, assocData);
419
+ }
420
+ const reloaded = await this.model.findAll({
421
+ where,
422
+ include: Object.values(this.model.associations)
423
+ });
424
+ return reloaded.map(r => r.get({ plain: true }));
155
425
  }
156
426
  // --- DESTROY ONE ---
157
427
  async _destroyOne(criteria) {
158
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
428
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
159
429
  const record = await this.model.findOne({ where });
160
- if (!record) {
430
+ if (!record)
161
431
  return null;
432
+ const assocNames = Object.keys(this.model.associations);
433
+ for (const alias of assocNames) {
434
+ const assoc = this.model.associations[alias];
435
+ // @ts-ignore: accessors should exist
436
+ const getAccessor = assoc.accessors?.get;
437
+ if (typeof record[getAccessor] === "function") {
438
+ try {
439
+ const related = await record[getAccessor]();
440
+ // 🧹 Удаляем связанные записи
441
+ if (Array.isArray(related)) {
442
+ for (const r of related) {
443
+ if (typeof r.destroy === "function") {
444
+ await r.destroy();
445
+ }
446
+ }
447
+ }
448
+ else if (related && typeof related.destroy === "function") {
449
+ await related.destroy();
450
+ }
451
+ }
452
+ catch (e) {
453
+ // console.warn(`Failed to fetch/delete relation "${alias}":`, e);
454
+ }
455
+ }
162
456
  }
163
457
  const raw = record.get({ plain: true });
164
458
  await record.destroy();
@@ -166,15 +460,44 @@ export class SequelizeModel extends AbstractModel {
166
460
  }
167
461
  // --- DESTROY MANY ---
168
462
  async _destroy(criteria) {
169
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
463
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
170
464
  const records = await this.model.findAll({ where });
465
+ const assocNames = Object.keys(this.model.associations);
466
+ for (const record of records) {
467
+ for (const alias of assocNames) {
468
+ const assoc = this.model.associations[alias];
469
+ // 🛑 Не трогаем родительские связи
470
+ if (assoc.associationType === "BelongsTo")
471
+ continue;
472
+ // @ts-ignore accessor exists
473
+ const getAccessor = assoc.accessors?.get;
474
+ if (typeof record[getAccessor] === "function") {
475
+ try {
476
+ const related = await record[getAccessor]();
477
+ if (Array.isArray(related)) {
478
+ for (const rel of related) {
479
+ if (typeof rel.destroy === "function") {
480
+ await rel.destroy();
481
+ }
482
+ }
483
+ }
484
+ else if (related && typeof related.destroy === "function") {
485
+ await related.destroy();
486
+ }
487
+ }
488
+ catch (e) {
489
+ // console.warn(`Failed to delete relation ${alias}:`, e);
490
+ }
491
+ }
492
+ }
493
+ }
171
494
  const raw = records.map(r => r.get({ plain: true }));
172
495
  await this.model.destroy({ where });
173
496
  return raw;
174
497
  }
175
498
  // --- COUNT ---
176
499
  async _count(criteria = {}) {
177
- const { where } = convertWaterlineCriteriaToSequelizeOptions(criteria);
500
+ const { where } = this._convertWaterlineCriteriaToSequelizeOptions(criteria);
178
501
  const result = await this.model.count({ where });
179
502
  return result;
180
503
  }
@@ -205,20 +528,30 @@ export class SequelizeAdapter extends AbstractAdapter {
205
528
  const model = this.getModel(modelName);
206
529
  return model?.getAttributes();
207
530
  }
208
- /** Регистрация системных моделей */
531
+ /**Registration of system models*/
209
532
  static async registerSystemModels(sequelize) {
210
533
  const modelsDir = path.resolve(import.meta.dirname, "../../../../models");
211
- const files = fs.readdirSync(modelsDir).filter(f => f.endsWith(".js"));
534
+ let files = fs.readdirSync(modelsDir).filter(f => f.endsWith(".js"));
535
+ if (!files.length) {
536
+ files = fs.readdirSync(modelsDir).filter(f => f.endsWith(".ts") && !f.endsWith(".d.ts"));
537
+ }
538
+ if (!files.length) {
539
+ throw `Model files not found in dir ${modelsDir}`;
540
+ }
541
+ const schemas = {};
212
542
  for (const file of files) {
213
543
  const modelName = path.basename(file, path.extname(file));
214
544
  const filePath = path.resolve(modelsDir, file);
215
- const definition = (await import(pathToFileURL(filePath).href)).default;
545
+ const mod = await import(pathToFileURL(filePath).href);
546
+ const definition = mod.default;
547
+ schemas[modelName] = definition;
216
548
  generateSequelizeModel(sequelize, modelName, definition);
217
549
  }
550
+ generateAssociationsFromSchema(sequelize.models, schemas);
218
551
  await sequelize.sync();
219
552
  }
220
553
  }
221
- /** Генерация модели Sequelize из определения, аналог WaterlineCollection.extend */
554
+ /**Generation of the SEQUELIZE model from the definition, analogue of Waterinecollection.extenD*/
222
555
  function generateSequelizeModel(sequelize, modelName, rawAttributes) {
223
556
  const attributes = {};
224
557
  let primaryKey = null;