nextly 0.0.1 → 0.0.2-alpha.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 (268) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +122 -0
  3. package/dist/_dts-chunks/collections-handler.d-DjgO74Wt.d.ts +20540 -0
  4. package/dist/_dts-chunks/config.d-DNwsDnjs.d.ts +2589 -0
  5. package/dist/_dts-chunks/define-component.d-BUgTHmt3.d.ts +1149 -0
  6. package/dist/_dts-chunks/image-processor.d-OO1PmMrv.d.ts +335 -0
  7. package/dist/_dts-chunks/index.d-axCAzZ7m.d.ts +17842 -0
  8. package/dist/_dts-chunks/media.d-DjDOZo4B.d.ts +117 -0
  9. package/dist/_dts-chunks/on-error.d-CHIKWNxd.d.ts +38 -0
  10. package/dist/_dts-chunks/storage.d-BUhQ2we_.d.ts +404 -0
  11. package/dist/actions/index.d.ts +239 -0
  12. package/dist/actions/index.mjs +281 -0
  13. package/dist/api/auth-state.d.ts +5 -0
  14. package/dist/api/auth-state.mjs +131 -0
  15. package/dist/api/collections-schema-detail.d.ts +56 -0
  16. package/dist/api/collections-schema-detail.mjs +244 -0
  17. package/dist/api/collections-schema-export.d.ts +56 -0
  18. package/dist/api/collections-schema-export.mjs +129 -0
  19. package/dist/api/collections-schema.d.ts +59 -0
  20. package/dist/api/collections-schema.mjs +207 -0
  21. package/dist/api/components-detail.d.ts +50 -0
  22. package/dist/api/components-detail.mjs +132 -0
  23. package/dist/api/components.d.ts +69 -0
  24. package/dist/api/components.mjs +144 -0
  25. package/dist/api/email-providers-default.d.ts +40 -0
  26. package/dist/api/email-providers-default.mjs +75 -0
  27. package/dist/api/email-providers-detail.d.ts +81 -0
  28. package/dist/api/email-providers-detail.mjs +109 -0
  29. package/dist/api/email-providers-test.d.ts +43 -0
  30. package/dist/api/email-providers-test.mjs +114 -0
  31. package/dist/api/email-providers.d.ts +69 -0
  32. package/dist/api/email-providers.mjs +110 -0
  33. package/dist/api/email-send-template.d.ts +41 -0
  34. package/dist/api/email-send-template.mjs +58 -0
  35. package/dist/api/email-send.d.ts +42 -0
  36. package/dist/api/email-send.mjs +58 -0
  37. package/dist/api/email-templates-detail.d.ts +74 -0
  38. package/dist/api/email-templates-detail.mjs +112 -0
  39. package/dist/api/email-templates-layout.d.ts +55 -0
  40. package/dist/api/email-templates-layout.mjs +92 -0
  41. package/dist/api/email-templates-preview.d.ts +48 -0
  42. package/dist/api/email-templates-preview.mjs +93 -0
  43. package/dist/api/email-templates.d.ts +61 -0
  44. package/dist/api/email-templates.mjs +118 -0
  45. package/dist/api/health.d.ts +68 -0
  46. package/dist/api/health.mjs +67 -0
  47. package/dist/api/index.d.ts +54 -0
  48. package/dist/api/index.mjs +16 -0
  49. package/dist/api/media-bulk.d.ts +74 -0
  50. package/dist/api/media-bulk.mjs +196 -0
  51. package/dist/api/media-folders.d.ts +112 -0
  52. package/dist/api/media-folders.mjs +187 -0
  53. package/dist/api/media-handlers.d.ts +102 -0
  54. package/dist/api/media-handlers.mjs +437 -0
  55. package/dist/api/media.d.ts +117 -0
  56. package/dist/api/media.mjs +242 -0
  57. package/dist/api/singles-detail.d.ts +87 -0
  58. package/dist/api/singles-detail.mjs +170 -0
  59. package/dist/api/singles-schema-detail.d.ts +54 -0
  60. package/dist/api/singles-schema-detail.mjs +182 -0
  61. package/dist/api/singles.d.ts +34 -0
  62. package/dist/api/singles.mjs +94 -0
  63. package/dist/api/storage-upload-url.d.ts +48 -0
  64. package/dist/api/storage-upload-url.mjs +202 -0
  65. package/dist/api/uploads.d.ts +109 -0
  66. package/dist/api/uploads.mjs +359 -0
  67. package/dist/auth/index.d.ts +425 -0
  68. package/dist/auth/index.mjs +199 -0
  69. package/dist/boot-apply-PQSYLDIN.mjs +7 -0
  70. package/dist/chunk-2OALJTK6.mjs +489 -0
  71. package/dist/chunk-2Q2SX2CS.mjs +365 -0
  72. package/dist/chunk-2TFX4ND3.mjs +13 -0
  73. package/dist/chunk-2TWPDSYD.mjs +87 -0
  74. package/dist/chunk-2W3DVD7S.mjs +647 -0
  75. package/dist/chunk-2ZFKXPQM.mjs +88 -0
  76. package/dist/chunk-3FA7FKAV.mjs +832 -0
  77. package/dist/chunk-3NZ2KMBL.mjs +58 -0
  78. package/dist/chunk-4MJLT6PZ.mjs +0 -0
  79. package/dist/chunk-56WO4WX7.mjs +0 -0
  80. package/dist/chunk-5APFUGAD.mjs +89 -0
  81. package/dist/chunk-5HMZ644B.mjs +108 -0
  82. package/dist/chunk-67GXH6PR.mjs +32 -0
  83. package/dist/chunk-6JNEPWRW.mjs +14368 -0
  84. package/dist/chunk-6NFHQIJD.mjs +45 -0
  85. package/dist/chunk-7P6ASYW6.mjs +9 -0
  86. package/dist/chunk-A3WPLSDT.mjs +1364 -0
  87. package/dist/chunk-AGJ6F2T3.mjs +144 -0
  88. package/dist/chunk-AK6Z23OX.mjs +1464 -0
  89. package/dist/chunk-APKKRD2G.mjs +102 -0
  90. package/dist/chunk-B2GV2BWH.mjs +73 -0
  91. package/dist/chunk-D5HQBNUB.mjs +74 -0
  92. package/dist/chunk-DNNG377Z.mjs +204 -0
  93. package/dist/chunk-DP3G27G5.mjs +135 -0
  94. package/dist/chunk-DV6WVX2Q.mjs +0 -0
  95. package/dist/chunk-DXGGXIUZ.mjs +57 -0
  96. package/dist/chunk-EGXBZCGC.mjs +943 -0
  97. package/dist/chunk-ERCNLX3V.mjs +176 -0
  98. package/dist/chunk-FQULBZ53.mjs +850 -0
  99. package/dist/chunk-G2AA4QLC.mjs +262 -0
  100. package/dist/chunk-GDBJ5JCU.mjs +488 -0
  101. package/dist/chunk-GJNSJU4S.mjs +19 -0
  102. package/dist/chunk-GZ6DCQKC.mjs +69 -0
  103. package/dist/chunk-H26B4FYG.mjs +167 -0
  104. package/dist/chunk-I4JMR3UR.mjs +21 -0
  105. package/dist/chunk-INV7QKLG.mjs +508 -0
  106. package/dist/chunk-IUDOC7N7.mjs +46 -0
  107. package/dist/chunk-IZWPRDC3.mjs +206 -0
  108. package/dist/chunk-KIMNCZGV.mjs +15 -0
  109. package/dist/chunk-L6HW2DA7.mjs +15 -0
  110. package/dist/chunk-LAZXX4HR.mjs +100 -0
  111. package/dist/chunk-LDKCUMHK.mjs +95 -0
  112. package/dist/chunk-LRXMECUA.mjs +0 -0
  113. package/dist/chunk-M52VMPGA.mjs +119 -0
  114. package/dist/chunk-MGUWEEI6.mjs +160 -0
  115. package/dist/chunk-NRUWQ5Z7.mjs +419 -0
  116. package/dist/chunk-NSEFNNU4.mjs +25360 -0
  117. package/dist/chunk-NTHVDFGO.mjs +138 -0
  118. package/dist/chunk-O3QHXMOX.mjs +3166 -0
  119. package/dist/chunk-P7NH2OSC.mjs +2605 -0
  120. package/dist/chunk-PKMABBB5.mjs +184 -0
  121. package/dist/chunk-PWS6XGJK.mjs +76 -0
  122. package/dist/chunk-R6JJQHFC.mjs +20 -0
  123. package/dist/chunk-RJLLGGPG.mjs +0 -0
  124. package/dist/chunk-SBACDPNX.mjs +689 -0
  125. package/dist/chunk-TO5AFLVQ.mjs +124 -0
  126. package/dist/chunk-TS7GHTG2.mjs +5436 -0
  127. package/dist/chunk-UJ2IMJ4W.mjs +133 -0
  128. package/dist/chunk-UOP63Q54.mjs +102 -0
  129. package/dist/chunk-UUOFWCM6.mjs +78 -0
  130. package/dist/chunk-V4EQTOA4.mjs +893 -0
  131. package/dist/chunk-VJ66NCL4.mjs +193 -0
  132. package/dist/chunk-VQJQHVEV.mjs +29 -0
  133. package/dist/chunk-VTJADRO3.mjs +141 -0
  134. package/dist/chunk-VWF3JO32.mjs +0 -0
  135. package/dist/chunk-W4MGXIRR.mjs +27 -0
  136. package/dist/chunk-W5KKPZT5.mjs +1204 -0
  137. package/dist/chunk-WD34YQ6T.mjs +381 -0
  138. package/dist/chunk-WZBYMYVW.mjs +14 -0
  139. package/dist/chunk-X23WKS3Z.mjs +50 -0
  140. package/dist/chunk-X7TXCYYN.mjs +6496 -0
  141. package/dist/chunk-XGI4EMS3.mjs +140 -0
  142. package/dist/chunk-XZKLBMN6.mjs +1153 -0
  143. package/dist/chunk-YB7INWPY.mjs +0 -0
  144. package/dist/chunk-YV4Y7SDL.mjs +83 -0
  145. package/dist/chunk-YZNBLFIW.mjs +1688 -0
  146. package/dist/chunk-YZZCTONM.mjs +263 -0
  147. package/dist/chunk-ZE6A3FYH.mjs +289 -0
  148. package/dist/cli/nextly.mjs +68 -0
  149. package/dist/cli/utils/index.d.ts +449 -0
  150. package/dist/cli/utils/index.mjs +49 -0
  151. package/dist/component-schema-service-5577KVW6.mjs +11 -0
  152. package/dist/config-loader-23YEMC3Z.mjs +23 -0
  153. package/dist/config.d.ts +44 -0
  154. package/dist/config.mjs +109 -0
  155. package/dist/container-ORGFGYSZ.mjs +9 -0
  156. package/dist/database/index.d.ts +12 -0
  157. package/dist/database/index.mjs +40 -0
  158. package/dist/database/seeders/index.d.ts +93 -0
  159. package/dist/database/seeders/index.mjs +47 -0
  160. package/dist/db-sync-demote-LJGKLB3S.mjs +117 -0
  161. package/dist/db-sync-promote-B26VSYQF.mjs +113 -0
  162. package/dist/dev-reload-broadcaster-B73IQ53V.mjs +25 -0
  163. package/dist/dist-M2NOU37V.mjs +19 -0
  164. package/dist/drizzle-kit-lazy-D2M2PXR2.mjs +13 -0
  165. package/dist/dynamic-collection-schema-service-IEXTPIZ7.mjs +8 -0
  166. package/dist/errors/index.d.ts +159 -0
  167. package/dist/errors/index.mjs +10 -0
  168. package/dist/factory-IWMBKUJM.mjs +15 -0
  169. package/dist/first-run-QIVKWJIF.mjs +63 -0
  170. package/dist/fresh-push-NR67DC3R.mjs +8 -0
  171. package/dist/index.d.ts +4175 -0
  172. package/dist/index.mjs +1336 -0
  173. package/dist/local-plugin-PTET4NAT.mjs +7 -0
  174. package/dist/logger-NU46DXNY.mjs +15 -0
  175. package/dist/logger-YE4TC7ZN.mjs +9 -0
  176. package/dist/migration-journal-EP532Y4L.mjs +139 -0
  177. package/dist/migrations/mysql/0000_eager_sentry.sql +174 -0
  178. package/dist/migrations/mysql/0001_soft_giant_girl.sql +27 -0
  179. package/dist/migrations/mysql/0002_media_table.sql +24 -0
  180. package/dist/migrations/mysql/0003_dynamic_singles.sql +37 -0
  181. package/dist/migrations/mysql/0004_dynamic_components.sql +35 -0
  182. package/dist/migrations/mysql/0005_user_management_tables.sql +92 -0
  183. package/dist/migrations/mysql/0006_api_keys.sql +36 -0
  184. package/dist/migrations/mysql/0007_general_settings.sql +20 -0
  185. package/dist/migrations/mysql/0008_site_settings_logo_url.sql +9 -0
  186. package/dist/migrations/mysql/0009_activity_log.sql +30 -0
  187. package/dist/migrations/mysql/0010_site_settings_sidebar.sql +13 -0
  188. package/dist/migrations/mysql/0011_missing_tables_and_columns.sql +54 -0
  189. package/dist/migrations/mysql/0012_image_sizes_and_focal_point.sql +30 -0
  190. package/dist/migrations/mysql/0012_media_folders.sql +43 -0
  191. package/dist/migrations/mysql/0013_user_brute_force_protection.sql +31 -0
  192. package/dist/migrations/mysql/0014_email_template_attachments.sql +12 -0
  193. package/dist/migrations/mysql/0015_media_uploaded_by_nullable.sql +15 -0
  194. package/dist/migrations/mysql/20260429_000000_000_initial_journal.sql +22 -0
  195. package/dist/migrations/mysql/20260501_000000_journal_batch.sql +17 -0
  196. package/dist/migrations/mysql/20260501_000001_audit_log.sql +24 -0
  197. package/dist/migrations/mysql/20260504_000000_nextly_meta.sql +21 -0
  198. package/dist/migrations/mysql/meta/0000_snapshot.json +1005 -0
  199. package/dist/migrations/mysql/meta/0001_snapshot.json +1099 -0
  200. package/dist/migrations/mysql/meta/_journal.json +41 -0
  201. package/dist/migrations/postgresql/0000_misty_king_bedlam.sql +169 -0
  202. package/dist/migrations/postgresql/0001_perpetual_captain_marvel.sql +8 -0
  203. package/dist/migrations/postgresql/0002_sad_spectrum.sql +16 -0
  204. package/dist/migrations/postgresql/0003_hesitant_ultron.sql +17 -0
  205. package/dist/migrations/postgresql/0004_media_table.sql +24 -0
  206. package/dist/migrations/postgresql/0005_media_folders.sql +36 -0
  207. package/dist/migrations/postgresql/0006_dynamic_collections_update.sql +50 -0
  208. package/dist/migrations/postgresql/0007_dynamic_singles.sql +38 -0
  209. package/dist/migrations/postgresql/0008_dynamic_components.sql +37 -0
  210. package/dist/migrations/postgresql/0009_user_management_tables.sql +95 -0
  211. package/dist/migrations/postgresql/0010_api_keys.sql +34 -0
  212. package/dist/migrations/postgresql/0011_general_settings.sql +20 -0
  213. package/dist/migrations/postgresql/0012_site_settings_logo_url.sql +9 -0
  214. package/dist/migrations/postgresql/0013_activity_log.sql +29 -0
  215. package/dist/migrations/postgresql/0014_image_sizes_and_focal_point.sql +33 -0
  216. package/dist/migrations/postgresql/0014_site_settings_sidebar.sql +13 -0
  217. package/dist/migrations/postgresql/0015_user_brute_force_protection.sql +29 -0
  218. package/dist/migrations/postgresql/0016_email_template_attachments.sql +12 -0
  219. package/dist/migrations/postgresql/0017_media_uploaded_by_nullable.sql +15 -0
  220. package/dist/migrations/postgresql/20260429_000000_000_initial_journal.sql +24 -0
  221. package/dist/migrations/postgresql/20260501_000000_journal_batch.sql +17 -0
  222. package/dist/migrations/postgresql/20260501_000001_audit_log.sql +24 -0
  223. package/dist/migrations/postgresql/20260504_000000_nextly_meta.sql +22 -0
  224. package/dist/migrations/postgresql/meta/0000_snapshot.json +1286 -0
  225. package/dist/migrations/postgresql/meta/0001_snapshot.json +1407 -0
  226. package/dist/migrations/postgresql/meta/0002_snapshot.json +1552 -0
  227. package/dist/migrations/postgresql/meta/0003_snapshot.json +1695 -0
  228. package/dist/migrations/postgresql/meta/0010_snapshot.json +2345 -0
  229. package/dist/migrations/postgresql/meta/_journal.json +90 -0
  230. package/dist/migrations/sqlite/0000_api_keys.sql +34 -0
  231. package/dist/migrations/sqlite/0001_general_settings.sql +20 -0
  232. package/dist/migrations/sqlite/0002_site_settings_logo_url.sql +9 -0
  233. package/dist/migrations/sqlite/0003_activity_log.sql +29 -0
  234. package/dist/migrations/sqlite/0004_image_sizes_and_focal_point.sql +29 -0
  235. package/dist/migrations/sqlite/0004_site_settings_sidebar.sql +11 -0
  236. package/dist/migrations/sqlite/0005_user_brute_force_protection.sql +29 -0
  237. package/dist/migrations/sqlite/0006_email_template_attachments.sql +12 -0
  238. package/dist/migrations/sqlite/0007_media_uploaded_by_nullable.sql +111 -0
  239. package/dist/migrations/sqlite/20260429_000000_000_initial_journal.sql +24 -0
  240. package/dist/migrations/sqlite/20260501_000000_journal_batch.sql +19 -0
  241. package/dist/migrations/sqlite/20260501_000001_audit_log.sql +24 -0
  242. package/dist/migrations/sqlite/20260504_000000_nextly_meta.sql +21 -0
  243. package/dist/migrations/sqlite/20260505_000000_user_management_tables.sql +77 -0
  244. package/dist/next.d.ts +57 -0
  245. package/dist/next.mjs +55 -0
  246. package/dist/observability/index.d.ts +87 -0
  247. package/dist/observability/index.mjs +57 -0
  248. package/dist/permissions-3DZZQZMI.mjs +39 -0
  249. package/dist/pipeline-YOML7SWF.mjs +29 -0
  250. package/dist/preview-ZZTR3QGS.mjs +9 -0
  251. package/dist/program-PW6UB2ZC.mjs +5934 -0
  252. package/dist/reconcile-single-tables-7ENVXJGB.mjs +7 -0
  253. package/dist/register-SF6E6FVU.mjs +49 -0
  254. package/dist/reload-config-HWQ4G5MM.mjs +23 -0
  255. package/dist/resolve-single-table-name-JSOMUB3R.mjs +7 -0
  256. package/dist/routeHandler-UNMMJIBM.mjs +77 -0
  257. package/dist/runtime-schema-generator-NRA6A6Z6.mjs +8 -0
  258. package/dist/runtime.d.ts +120 -0
  259. package/dist/runtime.mjs +73 -0
  260. package/dist/schema-hash-FMMG6VPJ.mjs +13 -0
  261. package/dist/schema-registry-EQ36FZDP.mjs +7 -0
  262. package/dist/scripts/load-env.mjs +42 -0
  263. package/dist/storage/index.d.ts +566 -0
  264. package/dist/storage/index.mjs +45 -0
  265. package/dist/super-admin-G5ZK5F4T.mjs +39 -0
  266. package/dist/system-table-service-WGSRVEGT.mjs +17 -0
  267. package/dist/users-7KELGRYJ.mjs +38 -0
  268. package/package.json +308 -9
@@ -0,0 +1,893 @@
1
+ import {
2
+ env
3
+ } from "./chunk-UJ2IMJ4W.mjs";
4
+ import {
5
+ isCheckboxField,
6
+ isCodeField,
7
+ isComponentField,
8
+ isDataField,
9
+ isDateField,
10
+ isEmailField,
11
+ isGroupField,
12
+ isJSONField,
13
+ isNumberField,
14
+ isPasswordField,
15
+ isRadioField,
16
+ isRelationshipField,
17
+ isRepeaterField,
18
+ isRichTextField,
19
+ isSelectField,
20
+ isTextField,
21
+ isTextareaField,
22
+ isUploadField
23
+ } from "./chunk-5APFUGAD.mjs";
24
+
25
+ // src/domains/components/services/component-schema-service.ts
26
+ import {
27
+ mysqlTable,
28
+ text as mysqlText,
29
+ int as mysqlInt,
30
+ boolean as mysqlBoolean,
31
+ timestamp as mysqlTimestamp,
32
+ json as mysqlJson,
33
+ varchar as mysqlVarchar,
34
+ double as mysqlDouble,
35
+ index as mysqlIndex
36
+ } from "drizzle-orm/mysql-core";
37
+ import {
38
+ pgTable,
39
+ text as pgText,
40
+ integer as pgInteger,
41
+ boolean as pgBoolean,
42
+ timestamp as pgTimestamp,
43
+ jsonb as pgJsonb,
44
+ varchar as pgVarchar,
45
+ doublePrecision as pgDoublePrecision,
46
+ index as pgIndex
47
+ } from "drizzle-orm/pg-core";
48
+ import {
49
+ sqliteTable,
50
+ text as sqliteText,
51
+ integer as sqliteInteger,
52
+ real as sqliteReal,
53
+ index as sqliteIndex
54
+ } from "drizzle-orm/sqlite-core";
55
+ var SQL_COLUMN_TYPES = {
56
+ postgresql: {
57
+ uuid: "UUID",
58
+ text: "TEXT",
59
+ varchar: (length) => `VARCHAR(${length})`,
60
+ boolean: "BOOLEAN",
61
+ integer: "INTEGER",
62
+ real: "REAL",
63
+ timestamp: "TIMESTAMP WITH TIME ZONE",
64
+ json: "JSONB"
65
+ },
66
+ mysql: {
67
+ uuid: "VARCHAR(36)",
68
+ text: "TEXT",
69
+ varchar: (length) => `VARCHAR(${length})`,
70
+ boolean: "BOOLEAN",
71
+ integer: "INT",
72
+ real: "DOUBLE",
73
+ timestamp: "DATETIME",
74
+ json: "JSON"
75
+ },
76
+ sqlite: {
77
+ uuid: "TEXT",
78
+ text: "TEXT",
79
+ varchar: () => "TEXT",
80
+ boolean: "INTEGER",
81
+ integer: "INTEGER",
82
+ real: "REAL",
83
+ timestamp: "INTEGER",
84
+ json: "TEXT"
85
+ }
86
+ };
87
+ var QUOTE_CHAR = {
88
+ postgresql: '"',
89
+ mysql: "`",
90
+ sqlite: '"'
91
+ };
92
+ var TIMESTAMP_DEFAULT = {
93
+ postgresql: "DEFAULT NOW()",
94
+ mysql: "DEFAULT CURRENT_TIMESTAMP",
95
+ sqlite: "DEFAULT (strftime('%s', 'now'))"
96
+ };
97
+ var ComponentSchemaService = class {
98
+ dialect;
99
+ q;
100
+ constructor(dialect) {
101
+ this.dialect = dialect || env.DB_DIALECT || "postgresql";
102
+ this.q = QUOTE_CHAR[this.dialect];
103
+ }
104
+ /**
105
+ * Generate SQL migration for creating a new component data table.
106
+ */
107
+ generateMigrationSQL(tableName, fields) {
108
+ const types = SQL_COLUMN_TYPES[this.dialect];
109
+ const tsDefault = TIMESTAMP_DEFAULT[this.dialect];
110
+ const lines = [];
111
+ lines.push(`-- Create component data table: ${tableName}`);
112
+ lines.push(`CREATE TABLE IF NOT EXISTS ${this.q}${tableName}${this.q} (`);
113
+ if (this.dialect === "mysql") {
114
+ lines.push(` ${this.q}id${this.q} varchar(36) PRIMARY KEY NOT NULL,`);
115
+ } else {
116
+ lines.push(` ${this.q}id${this.q} text PRIMARY KEY NOT NULL,`);
117
+ }
118
+ if (this.dialect === "mysql") {
119
+ lines.push(` ${this.q}_parent_id${this.q} varchar(36) NOT NULL,`);
120
+ } else {
121
+ lines.push(` ${this.q}_parent_id${this.q} text NOT NULL,`);
122
+ }
123
+ lines.push(
124
+ ` ${this.q}_parent_table${this.q} ${types.varchar(255)} NOT NULL,`
125
+ );
126
+ lines.push(
127
+ ` ${this.q}_parent_field${this.q} ${types.varchar(255)} NOT NULL,`
128
+ );
129
+ lines.push(` ${this.q}_order${this.q} ${types.integer} DEFAULT 0,`);
130
+ lines.push(` ${this.q}_component_type${this.q} ${types.varchar(255)},`);
131
+ for (const field of fields) {
132
+ if (!isDataField(field)) continue;
133
+ if (isComponentField(field)) continue;
134
+ const columnSQL = this.generateColumnSQL(field);
135
+ if (columnSQL) {
136
+ lines.push(` ${columnSQL},`);
137
+ }
138
+ }
139
+ lines.push(
140
+ ` ${this.q}created_at${this.q} ${types.timestamp} NOT NULL ${tsDefault},`
141
+ );
142
+ lines.push(
143
+ ` ${this.q}updated_at${this.q} ${types.timestamp} NOT NULL ${tsDefault}`
144
+ );
145
+ lines.push(");");
146
+ let sql = lines.join("\n");
147
+ const indexStatements = [];
148
+ const parentIndexName = `idx_${tableName}_parent`;
149
+ const parentColumns = [
150
+ `${this.q}_parent_id${this.q}`,
151
+ `${this.q}_parent_table${this.q}`,
152
+ `${this.q}_parent_field${this.q}`
153
+ ].join(", ");
154
+ if (this.dialect === "mysql") {
155
+ indexStatements.push(
156
+ `CREATE INDEX ${this.q}${parentIndexName}${this.q} ON ${this.q}${tableName}${this.q}(${parentColumns});`
157
+ );
158
+ } else {
159
+ indexStatements.push(
160
+ `CREATE INDEX IF NOT EXISTS ${this.q}${parentIndexName}${this.q} ON ${this.q}${tableName}${this.q}(${parentColumns});`
161
+ );
162
+ }
163
+ for (const field of fields) {
164
+ if (!isDataField(field)) continue;
165
+ if (isComponentField(field)) continue;
166
+ if (!("name" in field) || !field.name) continue;
167
+ if (!this.fieldHasForeignKey(field)) continue;
168
+ const columnName = this.toSnakeCase(field.name);
169
+ const indexName = `idx_${tableName}_${columnName}`;
170
+ if (this.dialect === "mysql") {
171
+ indexStatements.push(
172
+ `CREATE INDEX ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
173
+ );
174
+ } else {
175
+ indexStatements.push(
176
+ `CREATE INDEX IF NOT EXISTS ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
177
+ );
178
+ }
179
+ }
180
+ for (const field of fields) {
181
+ if (!isDataField(field)) continue;
182
+ if (isComponentField(field)) continue;
183
+ if (!("name" in field) || !field.name) continue;
184
+ if (!("index" in field && field.index)) continue;
185
+ if (this.fieldHasForeignKey(field)) continue;
186
+ const columnName = this.toSnakeCase(field.name);
187
+ const indexName = `idx_${tableName}_${columnName}`;
188
+ if (this.dialect === "mysql") {
189
+ indexStatements.push(
190
+ `CREATE INDEX ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
191
+ );
192
+ } else {
193
+ indexStatements.push(
194
+ `CREATE INDEX IF NOT EXISTS ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
195
+ );
196
+ }
197
+ }
198
+ for (const field of fields) {
199
+ if (!isDataField(field)) continue;
200
+ if (isComponentField(field)) continue;
201
+ if (!("name" in field) || !field.name) continue;
202
+ if (!("unique" in field && field.unique)) continue;
203
+ const columnName = this.toSnakeCase(field.name);
204
+ const indexName = `uq_${tableName}_${columnName}`;
205
+ if (this.dialect === "mysql") {
206
+ indexStatements.push(
207
+ `CREATE UNIQUE INDEX ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
208
+ );
209
+ } else {
210
+ indexStatements.push(
211
+ `CREATE UNIQUE INDEX IF NOT EXISTS ${this.q}${indexName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
212
+ );
213
+ }
214
+ }
215
+ if (indexStatements.length > 0) {
216
+ sql += "\n--> statement-breakpoint\n";
217
+ sql += indexStatements.join("\n--> statement-breakpoint\n");
218
+ }
219
+ return sql;
220
+ }
221
+ /**
222
+ * Generate ALTER TABLE migration for updating a component data table.
223
+ */
224
+ generateAlterTableMigration(tableName, oldFields, newFields) {
225
+ const statements = [
226
+ `-- Update component data table: ${tableName}`
227
+ ];
228
+ const oldFieldMap = this.buildFieldMap(oldFields);
229
+ const newFieldMap = this.buildFieldMap(newFields);
230
+ for (const [name, field] of newFieldMap) {
231
+ if (oldFieldMap.has(name)) continue;
232
+ const columnType = this.getColumnType(field);
233
+ if (!columnType) continue;
234
+ const columnName = this.toSnakeCase(name);
235
+ const nullable = "required" in field && field.required ? "NOT NULL" : "";
236
+ let defaultVal = "";
237
+ if ("defaultValue" in field && field.defaultValue !== void 0) {
238
+ defaultVal = `DEFAULT ${this.formatDefaultValue(field.defaultValue, field.type)}`;
239
+ } else if ("required" in field && field.required) {
240
+ defaultVal = `DEFAULT ${this.getDefaultValueForType(field.type)}`;
241
+ }
242
+ statements.push(
243
+ `ALTER TABLE ${this.q}${tableName}${this.q} ADD COLUMN ${this.q}${columnName}${this.q} ${columnType} ${nullable} ${defaultVal};`.trim()
244
+ );
245
+ if ("unique" in field && field.unique) {
246
+ if (this.dialect === "sqlite") {
247
+ statements.push(
248
+ `CREATE UNIQUE INDEX IF NOT EXISTS ${this.q}uq_${tableName}_${columnName}${this.q} ON ${this.q}${tableName}${this.q}(${this.q}${columnName}${this.q});`
249
+ );
250
+ } else {
251
+ statements.push(
252
+ `ALTER TABLE ${this.q}${tableName}${this.q} ADD CONSTRAINT ${this.q}uq_${tableName}_${columnName}${this.q} UNIQUE (${this.q}${columnName}${this.q});`
253
+ );
254
+ }
255
+ }
256
+ }
257
+ for (const [name] of oldFieldMap) {
258
+ if (newFieldMap.has(name)) continue;
259
+ const columnName = this.toSnakeCase(name);
260
+ if (this.dialect === "sqlite") {
261
+ statements.push(
262
+ `ALTER TABLE ${this.q}${tableName}${this.q} DROP COLUMN ${this.q}${columnName}${this.q};`
263
+ );
264
+ } else {
265
+ statements.push(
266
+ `ALTER TABLE ${this.q}${tableName}${this.q} DROP COLUMN IF EXISTS ${this.q}${columnName}${this.q};`
267
+ );
268
+ }
269
+ }
270
+ if (this.dialect !== "sqlite") {
271
+ for (const [name, newField] of newFieldMap) {
272
+ const oldField = oldFieldMap.get(name);
273
+ if (!oldField) continue;
274
+ if (!this.isFieldModified(oldField, newField)) continue;
275
+ const columnName = this.toSnakeCase(name);
276
+ const newType = this.getColumnType(newField);
277
+ if (!newType) continue;
278
+ statements.push(
279
+ `ALTER TABLE ${this.q}${tableName}${this.q} ALTER COLUMN ${this.q}${columnName}${this.q} TYPE ${newType};`
280
+ );
281
+ const oldRequired = "required" in oldField && oldField.required;
282
+ const newRequired = "required" in newField && newField.required;
283
+ if (oldRequired !== newRequired) {
284
+ if (newRequired) {
285
+ statements.push(
286
+ `ALTER TABLE ${this.q}${tableName}${this.q} ALTER COLUMN ${this.q}${columnName}${this.q} SET NOT NULL;`
287
+ );
288
+ } else {
289
+ statements.push(
290
+ `ALTER TABLE ${this.q}${tableName}${this.q} ALTER COLUMN ${this.q}${columnName}${this.q} DROP NOT NULL;`
291
+ );
292
+ }
293
+ }
294
+ }
295
+ }
296
+ return statements.join("\n--> statement-breakpoint\n");
297
+ }
298
+ /**
299
+ * Generate DROP TABLE migration for a component data table.
300
+ */
301
+ generateDropTableMigration(tableName) {
302
+ const dropStatement = this.dialect === "sqlite" ? `DROP TABLE IF EXISTS ${this.q}${tableName}${this.q};` : `DROP TABLE IF EXISTS ${this.q}${tableName}${this.q} CASCADE;`;
303
+ const componentSlug = tableName.replace(/^comp_/, "");
304
+ const migrationSQL = `-- Drop component data table: ${tableName}
305
+ ${dropStatement}`;
306
+ return {
307
+ migrationSQL,
308
+ migrationFileName: `${Date.now()}_drop_comp_${componentSlug}.sql`
309
+ };
310
+ }
311
+ /**
312
+ * Generate a Drizzle table object at runtime for querying component data.
313
+ */
314
+ // Returns an opaque Drizzle table object (PgTable | MySqlTable | SQLiteTable).
315
+ // Typed as `unknown` because the column shape is dynamic at compile time;
316
+ // callers cast at the use site.
317
+ generateRuntimeSchema(tableName, fields) {
318
+ switch (this.dialect) {
319
+ case "postgresql":
320
+ return this.generatePostgresSchema(tableName, fields);
321
+ case "mysql":
322
+ return this.generateMySQLSchema(tableName, fields);
323
+ case "sqlite":
324
+ return this.generateSQLiteSchema(tableName, fields);
325
+ default:
326
+ throw new Error(`Unsupported dialect: ${String(this.dialect)}`);
327
+ }
328
+ }
329
+ generatePostgresSchema(tableName, fields) {
330
+ const columns = {
331
+ id: pgText("id").primaryKey(),
332
+ _parent_id: pgText("_parent_id").notNull(),
333
+ _parent_table: pgVarchar("_parent_table", { length: 255 }).notNull(),
334
+ _parent_field: pgVarchar("_parent_field", { length: 255 }).notNull(),
335
+ _order: pgInteger("_order").default(0),
336
+ _component_type: pgVarchar("_component_type", { length: 255 }),
337
+ created_at: pgTimestamp("created_at").defaultNow().notNull(),
338
+ updated_at: pgTimestamp("updated_at").defaultNow().notNull()
339
+ };
340
+ for (const field of fields) {
341
+ if (!isDataField(field)) continue;
342
+ if (isComponentField(field)) continue;
343
+ if (!("name" in field) || !field.name) continue;
344
+ const column = this.mapFieldToPostgresColumn(field);
345
+ if (column) {
346
+ columns[field.name] = column;
347
+ }
348
+ }
349
+ return pgTable(
350
+ tableName,
351
+ columns,
352
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Drizzle table column accessor is dialect-typed
353
+ (table) => ({
354
+ parentIdx: pgIndex(`idx_${tableName}_parent`).on(
355
+ table._parent_id,
356
+ table._parent_table,
357
+ table._parent_field
358
+ )
359
+ })
360
+ );
361
+ }
362
+ generateMySQLSchema(tableName, fields) {
363
+ const columns = {
364
+ id: mysqlVarchar("id", { length: 36 }).primaryKey(),
365
+ _parent_id: mysqlVarchar("_parent_id", { length: 36 }).notNull(),
366
+ _parent_table: mysqlVarchar("_parent_table", { length: 255 }).notNull(),
367
+ _parent_field: mysqlVarchar("_parent_field", { length: 255 }).notNull(),
368
+ _order: mysqlInt("_order").default(0),
369
+ _component_type: mysqlVarchar("_component_type", { length: 255 }),
370
+ created_at: mysqlTimestamp("created_at").defaultNow().notNull(),
371
+ updated_at: mysqlTimestamp("updated_at").defaultNow().notNull()
372
+ };
373
+ for (const field of fields) {
374
+ if (!isDataField(field)) continue;
375
+ if (isComponentField(field)) continue;
376
+ if (!("name" in field) || !field.name) continue;
377
+ const column = this.mapFieldToMySQLColumn(field);
378
+ if (column) {
379
+ columns[field.name] = column;
380
+ }
381
+ }
382
+ return mysqlTable(
383
+ tableName,
384
+ columns,
385
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Drizzle table column accessor is dialect-typed
386
+ (table) => ({
387
+ parentIdx: mysqlIndex(`idx_${tableName}_parent`).on(
388
+ table._parent_id,
389
+ table._parent_table,
390
+ table._parent_field
391
+ )
392
+ })
393
+ );
394
+ }
395
+ generateSQLiteSchema(tableName, fields) {
396
+ const columns = {
397
+ id: sqliteText("id").primaryKey(),
398
+ _parent_id: sqliteText("_parent_id").notNull(),
399
+ _parent_table: sqliteText("_parent_table").notNull(),
400
+ _parent_field: sqliteText("_parent_field").notNull(),
401
+ _order: sqliteInteger("_order").default(0),
402
+ _component_type: sqliteText("_component_type"),
403
+ created_at: sqliteInteger("created_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date()),
404
+ updated_at: sqliteInteger("updated_at", { mode: "timestamp" }).notNull().$defaultFn(() => /* @__PURE__ */ new Date())
405
+ };
406
+ for (const field of fields) {
407
+ if (!isDataField(field)) continue;
408
+ if (isComponentField(field)) continue;
409
+ if (!("name" in field) || !field.name) continue;
410
+ const column = this.mapFieldToSQLiteColumn(field);
411
+ if (column) {
412
+ columns[field.name] = column;
413
+ }
414
+ }
415
+ return sqliteTable(
416
+ tableName,
417
+ columns,
418
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Drizzle table column accessor is dialect-typed
419
+ (table) => ({
420
+ parentIdx: sqliteIndex(`idx_${tableName}_parent`).on(
421
+ table._parent_id,
422
+ table._parent_table,
423
+ table._parent_field
424
+ )
425
+ })
426
+ );
427
+ }
428
+ /**
429
+ * Generate TypeScript/Drizzle schema code for a component data table.
430
+ */
431
+ generateSchemaCode(tableName, componentSlug, fields) {
432
+ const dialectConfig = this.getDialectConfig();
433
+ const baseImports = this.collectRequiredImports(fields);
434
+ const imports = `import { ${dialectConfig.tableFunction}, ${baseImports.join(", ")} } from '${dialectConfig.importPath}';`;
435
+ const fieldColumns = fields.filter(
436
+ (f) => isDataField(f) && !isComponentField(f)
437
+ ).map((f) => {
438
+ const drizzleType = this.mapFieldToDrizzleCode(f);
439
+ const modifiers = [];
440
+ if ("required" in f && f.required) modifiers.push(".notNull()");
441
+ if ("unique" in f && f.unique) modifiers.push(".unique()");
442
+ const defaultValue = "defaultValue" in f ? f.defaultValue : void 0;
443
+ if (defaultValue !== void 0 && defaultValue !== null) {
444
+ if (f.type === "json" || f.type === "repeater" || f.type === "group") {
445
+ modifiers.push(`.default(${JSON.stringify(defaultValue)})`);
446
+ } else if (typeof defaultValue === "string") {
447
+ modifiers.push(`.default('${defaultValue}')`);
448
+ } else {
449
+ modifiers.push(`.default(${String(defaultValue)})`);
450
+ }
451
+ }
452
+ return ` ${f.name}: ${drizzleType}${modifiers.join("")},`;
453
+ }).join("\n");
454
+ const timestampColumns = this.generateTimestampColumnsCode();
455
+ const fieldIndexes = fields.filter(
456
+ (f) => isDataField(f) && !isComponentField(f)
457
+ ).filter(
458
+ (f) => !!f.name && !!("index" in f && f.index || this.fieldHasForeignKey(f))
459
+ ).map(
460
+ (f) => ` ${f.name}Idx: index('idx_${tableName}_${this.toSnakeCase(f.name)}').on(table.${f.name}),`
461
+ ).join("\n");
462
+ const allIndexes = fieldIndexes ? ` parentIdx: index('idx_${tableName}_parent').on(table._parent_id, table._parent_table, table._parent_field),
463
+ ${fieldIndexes}` : ` parentIdx: index('idx_${tableName}_parent').on(table._parent_id, table._parent_table, table._parent_field),`;
464
+ const baseColumnsCode = this.generateBaseColumnsCode();
465
+ return `${imports}
466
+
467
+ /**
468
+ * Component data table: ${componentSlug}
469
+ * Generated by nextly
470
+ */
471
+ export const ${tableName} = ${dialectConfig.tableFunction}('${tableName}', {
472
+ ${baseColumnsCode}
473
+ ${fieldColumns}
474
+ ${timestampColumns}
475
+ }, (table) => ({
476
+ ${allIndexes}
477
+ }));
478
+
479
+ export type ${this.toPascalCase(componentSlug)}Component = typeof ${tableName}.$inferSelect;
480
+ export type New${this.toPascalCase(componentSlug)}Component = typeof ${tableName}.$inferInsert;
481
+ `;
482
+ }
483
+ generateColumnSQL(field) {
484
+ if (!("name" in field) || !field.name) return null;
485
+ const columnName = this.toSnakeCase(field.name);
486
+ const columnType = this.getColumnType(field);
487
+ if (!columnType) return null;
488
+ const parts = [`${this.q}${columnName}${this.q}`, columnType];
489
+ if ("required" in field && field.required) {
490
+ parts.push("NOT NULL");
491
+ }
492
+ if (isCheckboxField(field) && field.defaultValue !== void 0) {
493
+ const defaultVal = this.dialect === "sqlite" ? field.defaultValue ? 1 : 0 : field.defaultValue;
494
+ parts.push(`DEFAULT ${String(defaultVal)}`);
495
+ }
496
+ return parts.join(" ");
497
+ }
498
+ getColumnType(field) {
499
+ const types = SQL_COLUMN_TYPES[this.dialect];
500
+ if (isTextField(field)) {
501
+ return field.maxLength ? types.varchar(field.maxLength) : types.text;
502
+ }
503
+ if (isTextareaField(field) || isRichTextField(field) || isCodeField(field)) {
504
+ return types.text;
505
+ }
506
+ if (isEmailField(field)) {
507
+ return types.varchar(255);
508
+ }
509
+ if (isPasswordField(field)) {
510
+ return types.varchar(255);
511
+ }
512
+ if (isNumberField(field)) {
513
+ return types.real;
514
+ }
515
+ if (isCheckboxField(field)) {
516
+ return types.boolean;
517
+ }
518
+ if (isDateField(field)) {
519
+ return types.timestamp;
520
+ }
521
+ if (isSelectField(field)) {
522
+ return field.hasMany ? types.json : types.varchar(255);
523
+ }
524
+ if (isRadioField(field)) {
525
+ return types.varchar(255);
526
+ }
527
+ if (isUploadField(field) || isRelationshipField(field)) {
528
+ if (Array.isArray(field.relationTo) || field.hasMany) {
529
+ return types.json;
530
+ }
531
+ return types.uuid;
532
+ }
533
+ if (isRepeaterField(field) || isGroupField(field)) {
534
+ return types.json;
535
+ }
536
+ if (isJSONField(field)) {
537
+ return types.json;
538
+ }
539
+ return null;
540
+ }
541
+ // Returns a Drizzle column builder — typed as `unknown` to avoid
542
+ // depending on Drizzle's internal column builder types from the public API.
543
+ mapFieldToPostgresColumn(field) {
544
+ if (!("name" in field) || !field.name) return null;
545
+ const isRequired = "required" in field && field.required === true;
546
+ const colName = this.toSnakeCase(field.name);
547
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field)) {
548
+ return isRequired ? pgText(colName).notNull() : pgText(colName);
549
+ }
550
+ if (isTextareaField(field) || isRichTextField(field) || isCodeField(field)) {
551
+ return isRequired ? pgText(colName).notNull() : pgText(colName);
552
+ }
553
+ if (isNumberField(field)) {
554
+ return isRequired ? pgDoublePrecision(colName).notNull() : pgDoublePrecision(colName);
555
+ }
556
+ if (isCheckboxField(field)) {
557
+ return isRequired ? pgBoolean(colName).notNull() : pgBoolean(colName);
558
+ }
559
+ if (isDateField(field)) {
560
+ return isRequired ? pgTimestamp(colName).notNull() : pgTimestamp(colName);
561
+ }
562
+ if (isSelectField(field) || isRadioField(field)) {
563
+ return isRequired ? pgText(colName).notNull() : pgText(colName);
564
+ }
565
+ if (isRelationshipField(field) || isUploadField(field)) {
566
+ return pgText(colName);
567
+ }
568
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
569
+ return isRequired ? pgJsonb(colName).notNull() : pgJsonb(colName);
570
+ }
571
+ return pgText(colName);
572
+ }
573
+ mapFieldToMySQLColumn(field) {
574
+ if (!("name" in field) || !field.name) return null;
575
+ const isRequired = "required" in field && field.required === true;
576
+ const colName = this.toSnakeCase(field.name);
577
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field)) {
578
+ return isRequired ? mysqlVarchar(colName, { length: 255 }).notNull() : mysqlVarchar(colName, { length: 255 });
579
+ }
580
+ if (isTextareaField(field) || isRichTextField(field) || isCodeField(field)) {
581
+ return isRequired ? mysqlText(colName).notNull() : mysqlText(colName);
582
+ }
583
+ if (isNumberField(field)) {
584
+ return isRequired ? mysqlDouble(colName).notNull() : mysqlDouble(colName);
585
+ }
586
+ if (isCheckboxField(field)) {
587
+ return isRequired ? mysqlBoolean(colName).notNull() : mysqlBoolean(colName);
588
+ }
589
+ if (isDateField(field)) {
590
+ return isRequired ? mysqlTimestamp(colName).notNull() : mysqlTimestamp(colName);
591
+ }
592
+ if (isSelectField(field) || isRadioField(field)) {
593
+ return isRequired ? mysqlVarchar(colName, { length: 255 }).notNull() : mysqlVarchar(colName, { length: 255 });
594
+ }
595
+ if (isRelationshipField(field) || isUploadField(field)) {
596
+ return mysqlVarchar(colName, { length: 36 });
597
+ }
598
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
599
+ return isRequired ? mysqlJson(colName).notNull() : mysqlJson(colName);
600
+ }
601
+ return mysqlVarchar(colName, { length: 255 });
602
+ }
603
+ mapFieldToSQLiteColumn(field) {
604
+ if (!("name" in field) || !field.name) return null;
605
+ const isRequired = "required" in field && field.required === true;
606
+ const colName = this.toSnakeCase(field.name);
607
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field) || isTextareaField(field) || isRichTextField(field) || isCodeField(field) || isSelectField(field) || isRadioField(field)) {
608
+ return isRequired ? sqliteText(colName).notNull() : sqliteText(colName);
609
+ }
610
+ if (isNumberField(field)) {
611
+ return isRequired ? sqliteReal(colName).notNull() : sqliteReal(colName);
612
+ }
613
+ if (isCheckboxField(field)) {
614
+ return isRequired ? sqliteInteger(colName, { mode: "boolean" }).notNull() : sqliteInteger(colName, { mode: "boolean" });
615
+ }
616
+ if (isDateField(field)) {
617
+ return isRequired ? sqliteInteger(colName, { mode: "timestamp" }).notNull() : sqliteInteger(colName, { mode: "timestamp" });
618
+ }
619
+ if (isRelationshipField(field) || isUploadField(field)) {
620
+ return sqliteText(colName);
621
+ }
622
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
623
+ return isRequired ? sqliteText(colName).notNull() : sqliteText(colName);
624
+ }
625
+ return sqliteText(colName);
626
+ }
627
+ mapFieldToDrizzleCode(field) {
628
+ if (!("name" in field) || !field.name) return "";
629
+ const colName = this.toSnakeCase(field.name);
630
+ if (this.dialect === "sqlite") {
631
+ return this.mapFieldToSQLiteCode(field, colName);
632
+ }
633
+ if (this.dialect === "mysql") {
634
+ return this.mapFieldToMySQLCode(field, colName);
635
+ }
636
+ return this.mapFieldToPostgresCode(field, colName);
637
+ }
638
+ mapFieldToPostgresCode(field, colName) {
639
+ if (isTextField(field)) {
640
+ return field.maxLength ? `varchar('${colName}', { length: ${field.maxLength} })` : `text('${colName}')`;
641
+ }
642
+ if (isTextareaField(field) || isRichTextField(field) || isCodeField(field)) {
643
+ return `text('${colName}')`;
644
+ }
645
+ if (isEmailField(field) || isPasswordField(field)) {
646
+ return `varchar('${colName}', { length: 255 })`;
647
+ }
648
+ if (isNumberField(field)) {
649
+ return `doublePrecision('${colName}')`;
650
+ }
651
+ if (isCheckboxField(field)) {
652
+ return `boolean('${colName}')`;
653
+ }
654
+ if (isDateField(field)) {
655
+ return `timestamp('${colName}')`;
656
+ }
657
+ if (isSelectField(field) || isRadioField(field)) {
658
+ return `text('${colName}')`;
659
+ }
660
+ if (isRelationshipField(field) || isUploadField(field)) {
661
+ return `text('${colName}')`;
662
+ }
663
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
664
+ return `jsonb('${colName}')`;
665
+ }
666
+ return `text('${colName}')`;
667
+ }
668
+ mapFieldToMySQLCode(field, colName) {
669
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field) || isSelectField(field) || isRadioField(field)) {
670
+ return `varchar('${colName}', { length: 255 })`;
671
+ }
672
+ if (isTextareaField(field) || isRichTextField(field) || isCodeField(field)) {
673
+ return `text('${colName}')`;
674
+ }
675
+ if (isNumberField(field)) {
676
+ return `double('${colName}')`;
677
+ }
678
+ if (isCheckboxField(field)) {
679
+ return `boolean('${colName}')`;
680
+ }
681
+ if (isDateField(field)) {
682
+ return `timestamp('${colName}')`;
683
+ }
684
+ if (isRelationshipField(field) || isUploadField(field)) {
685
+ return `varchar('${colName}', { length: 36 })`;
686
+ }
687
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
688
+ return `json('${colName}')`;
689
+ }
690
+ return `varchar('${colName}', { length: 255 })`;
691
+ }
692
+ mapFieldToSQLiteCode(field, colName) {
693
+ if (isNumberField(field)) {
694
+ return `real('${colName}')`;
695
+ }
696
+ if (isCheckboxField(field)) {
697
+ return `integer('${colName}', { mode: 'boolean' })`;
698
+ }
699
+ if (isDateField(field)) {
700
+ return `integer('${colName}', { mode: 'timestamp' })`;
701
+ }
702
+ return `text('${colName}')`;
703
+ }
704
+ getDialectConfig() {
705
+ switch (this.dialect) {
706
+ case "mysql":
707
+ return {
708
+ tableFunction: "mysqlTable",
709
+ importPath: "drizzle-orm/mysql-core"
710
+ };
711
+ case "sqlite":
712
+ return {
713
+ tableFunction: "sqliteTable",
714
+ importPath: "drizzle-orm/sqlite-core"
715
+ };
716
+ case "postgresql":
717
+ default:
718
+ return {
719
+ tableFunction: "pgTable",
720
+ importPath: "drizzle-orm/pg-core"
721
+ };
722
+ }
723
+ }
724
+ collectRequiredImports(fields) {
725
+ const imports = /* @__PURE__ */ new Set(["text", "index"]);
726
+ if (this.dialect === "sqlite") {
727
+ imports.add("integer");
728
+ imports.add("real");
729
+ } else {
730
+ imports.add("varchar");
731
+ imports.add("integer");
732
+ imports.add("timestamp");
733
+ }
734
+ for (const field of fields) {
735
+ if (!isDataField(field) || isComponentField(field)) continue;
736
+ if (this.dialect === "sqlite") {
737
+ if (isNumberField(field)) imports.add("real");
738
+ if (isCheckboxField(field)) imports.add("integer");
739
+ if (isDateField(field)) imports.add("integer");
740
+ } else if (this.dialect === "mysql") {
741
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field) || isSelectField(field) || isRadioField(field) || isRelationshipField(field) || isUploadField(field)) {
742
+ imports.add("varchar");
743
+ }
744
+ if (isNumberField(field)) imports.add("double");
745
+ if (isCheckboxField(field)) imports.add("boolean");
746
+ if (isDateField(field)) imports.add("timestamp");
747
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
748
+ imports.add("json");
749
+ }
750
+ } else {
751
+ if (isTextField(field) || isEmailField(field) || isPasswordField(field)) {
752
+ if (isTextField(field) && field.maxLength) {
753
+ imports.add("varchar");
754
+ }
755
+ }
756
+ if (isNumberField(field)) imports.add("doublePrecision");
757
+ if (isCheckboxField(field)) imports.add("boolean");
758
+ if (isDateField(field)) imports.add("timestamp");
759
+ if (isRepeaterField(field) || isGroupField(field) || isJSONField(field)) {
760
+ imports.add("jsonb");
761
+ }
762
+ }
763
+ }
764
+ return Array.from(imports);
765
+ }
766
+ generateBaseColumnsCode() {
767
+ if (this.dialect === "sqlite") {
768
+ return ` id: text('id').primaryKey().notNull(),
769
+ _parent_id: text('_parent_id').notNull(),
770
+ _parent_table: text('_parent_table').notNull(),
771
+ _parent_field: text('_parent_field').notNull(),
772
+ _order: integer('_order').default(0),
773
+ _component_type: text('_component_type'),`;
774
+ }
775
+ if (this.dialect === "mysql") {
776
+ return ` id: varchar('id', { length: 36 }).primaryKey().notNull(),
777
+ _parent_id: varchar('_parent_id', { length: 36 }).notNull(),
778
+ _parent_table: varchar('_parent_table', { length: 255 }).notNull(),
779
+ _parent_field: varchar('_parent_field', { length: 255 }).notNull(),
780
+ _order: integer('_order').default(0),
781
+ _component_type: varchar('_component_type', { length: 255 }),`;
782
+ }
783
+ return ` id: text('id').primaryKey().notNull(),
784
+ _parent_id: text('_parent_id').notNull(),
785
+ _parent_table: varchar('_parent_table', { length: 255 }).notNull(),
786
+ _parent_field: varchar('_parent_field', { length: 255 }).notNull(),
787
+ _order: integer('_order').default(0),
788
+ _component_type: varchar('_component_type', { length: 255 }),`;
789
+ }
790
+ generateTimestampColumnsCode() {
791
+ if (this.dialect === "sqlite") {
792
+ return ` createdAt: integer('created_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()),
793
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull().$defaultFn(() => new Date()).$onUpdate(() => new Date()),`;
794
+ }
795
+ return ` createdAt: timestamp('created_at').defaultNow().notNull(),
796
+ updatedAt: timestamp('updated_at').defaultNow().notNull(),`;
797
+ }
798
+ fieldHasForeignKey(field) {
799
+ if (!isRelationshipField(field) && !isUploadField(field)) return false;
800
+ return !Array.isArray(field.relationTo) && !field.hasMany && typeof field.relationTo === "string";
801
+ }
802
+ isFieldModified(oldField, newField) {
803
+ if (oldField.type !== newField.type) return true;
804
+ const oldRequired = "required" in oldField && oldField.required;
805
+ const newRequired = "required" in newField && newField.required;
806
+ if (oldRequired !== newRequired) return true;
807
+ const oldUnique = "unique" in oldField && oldField.unique;
808
+ const newUnique = "unique" in newField && newField.unique;
809
+ if (oldUnique !== newUnique) return true;
810
+ if (isTextField(oldField) && isTextField(newField)) {
811
+ if (oldField.maxLength !== newField.maxLength) return true;
812
+ }
813
+ if (isSelectField(oldField) && isSelectField(newField) || isRelationshipField(oldField) && isRelationshipField(newField) || isUploadField(oldField) && isUploadField(newField)) {
814
+ if (oldField.hasMany !== newField.hasMany) return true;
815
+ }
816
+ return false;
817
+ }
818
+ buildFieldMap(fields) {
819
+ const map = /* @__PURE__ */ new Map();
820
+ for (const field of fields) {
821
+ if (!isDataField(field)) continue;
822
+ if (isComponentField(field)) continue;
823
+ if (!("name" in field) || !field.name) continue;
824
+ map.set(field.name, field);
825
+ }
826
+ return map;
827
+ }
828
+ // Used when adding NOT NULL columns to existing tables.
829
+ getDefaultValueForType(type) {
830
+ switch (type) {
831
+ case "text":
832
+ case "textarea":
833
+ case "email":
834
+ case "password":
835
+ case "richText":
836
+ case "code":
837
+ case "select":
838
+ case "radio":
839
+ return "''";
840
+ case "number":
841
+ return "0";
842
+ case "checkbox":
843
+ case "boolean":
844
+ return this.dialect === "sqlite" ? "0" : "FALSE";
845
+ case "date":
846
+ if (this.dialect === "sqlite") {
847
+ return String(Math.floor(Date.now() / 1e3));
848
+ }
849
+ return "NOW()";
850
+ case "json":
851
+ case "repeater":
852
+ case "group":
853
+ return "'{}'";
854
+ case "relationship":
855
+ case "upload":
856
+ return "NULL";
857
+ default:
858
+ return "''";
859
+ }
860
+ }
861
+ formatDefaultValue(value, type) {
862
+ if (type === "text" || type === "textarea" || type === "email" || type === "password" || type === "richText" || type === "code" || type === "select" || type === "radio") {
863
+ return `'${String(value)}'`;
864
+ }
865
+ if (type === "checkbox") {
866
+ if (this.dialect === "sqlite") return value ? "1" : "0";
867
+ return value ? "TRUE" : "FALSE";
868
+ }
869
+ if (type === "json" || type === "repeater" || type === "group") {
870
+ return `'${typeof value === "string" ? value : JSON.stringify(value)}'`;
871
+ }
872
+ if (type === "date") {
873
+ if (this.dialect === "sqlite" && typeof value === "string") {
874
+ return String(Math.floor(new Date(value).getTime() / 1e3));
875
+ }
876
+ return `'${String(value)}'`;
877
+ }
878
+ if (type === "number") {
879
+ return String(value);
880
+ }
881
+ return String(value);
882
+ }
883
+ toSnakeCase(name) {
884
+ return name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
885
+ }
886
+ toPascalCase(str) {
887
+ return str.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
888
+ }
889
+ };
890
+
891
+ export {
892
+ ComponentSchemaService
893
+ };