@stacksjs/database 0.70.258 → 0.70.260

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 (50) hide show
  1. package/dist/auth-tables.js +18 -137
  2. package/dist/column.js +1 -26
  3. package/dist/custom/audits.js +20 -54
  4. package/dist/custom/errors.js +16 -46
  5. package/dist/custom/index.js +1 -3
  6. package/dist/custom/jobs.js +13 -137
  7. package/dist/database.js +1 -181
  8. package/dist/datetime-columns.js +2 -79
  9. package/dist/ddl-constraints.js +7 -111
  10. package/dist/defaults.js +1 -48
  11. package/dist/dialect.js +1 -79
  12. package/dist/driver-config.js +1 -172
  13. package/dist/drivers/defaults/index.js +1 -1
  14. package/dist/drivers/defaults/traits.js +1 -29
  15. package/dist/drivers/dynamodb.js +1 -607
  16. package/dist/drivers/helpers.js +1 -206
  17. package/dist/drivers/index.js +1 -9
  18. package/dist/drivers/mysql.js +58 -299
  19. package/dist/drivers/postgres.js +78 -368
  20. package/dist/drivers/sqlite.js +61 -379
  21. package/dist/ensure-database.js +1 -145
  22. package/dist/fk-audit.js +3 -187
  23. package/dist/index.js +1 -64
  24. package/dist/managed-columns.js +1 -59
  25. package/dist/migration-dialect.js +4 -107
  26. package/dist/migration-ledger.js +1 -382
  27. package/dist/migration-lock.js +1 -143
  28. package/dist/migrations.js +15 -1118
  29. package/dist/model-sources.js +1 -76
  30. package/dist/notification-tables.js +4 -49
  31. package/dist/query-logger.js +2 -241
  32. package/dist/query-parser.js +1 -93
  33. package/dist/rbac-tables.js +6 -61
  34. package/dist/relation-columns.js +1 -66
  35. package/dist/replicas.js +1 -74
  36. package/dist/safe-migrations.js +2 -52
  37. package/dist/schema.js +1 -10
  38. package/dist/seeder.js +1 -457
  39. package/dist/sql-helpers.js +1 -50
  40. package/dist/table.js +1 -26
  41. package/dist/tools/setup.js +1 -6
  42. package/dist/trait-tables.js +8 -153
  43. package/dist/transaction-context.js +1 -62
  44. package/dist/types.js +1 -98
  45. package/dist/unique-audit.js +3 -155
  46. package/dist/utils.js +1 -285
  47. package/dist/uuid-columns.js +1 -68
  48. package/dist/validators.js +1 -122
  49. package/dist/vschema.js +2 -121
  50. package/package.json +20 -13
@@ -1,206 +1 @@
1
- import { log } from "@stacksjs/logging";
2
- import { getTableName } from "@stacksjs/orm";
3
- import { path } from "@stacksjs/path";
4
- import { fs, globSync } from "@stacksjs/storage";
5
- import { plural, snakeCase } from "@stacksjs/strings";
6
- import { db } from "../utils";
7
- import { enumValidator, isBooleanValidator, isDatetimeValidator, isDateValidator, isFloatValidator, isNumberValidator, isStringValidator, isTimestampValidator, isUnixValidator } from "../validators";
8
- export async function deleteMigrationFiles() {
9
- const files = await fs.promises.readdir(path.userMigrationsPath());
10
- if (files.length) {
11
- for (const file of files)
12
- if (file.endsWith(".ts")) {
13
- const migrationPath = path.userMigrationsPath(`${file}`);
14
- if (fs.existsSync(migrationPath))
15
- await Bun.$`rm ${migrationPath}`;
16
- }
17
- }
18
- }
19
- export async function deleteFrameworkModels() {
20
- const cacheDir = path.frameworkPath("cache/models");
21
- if (!fs.existsSync(cacheDir))
22
- return;
23
- const modelFiles = await fs.promises.readdir(cacheDir);
24
- if (modelFiles.length) {
25
- for (const modelFile of modelFiles)
26
- if (modelFile.endsWith(".ts")) {
27
- const modelPath = path.frameworkPath(`cache/models/${modelFile}`);
28
- if (fs.existsSync(modelPath))
29
- await Bun.$`rm ${modelPath}`;
30
- }
31
- }
32
- }
33
- export async function getLastMigrationFields(modelName) {
34
- const model = (await import(path.frameworkPath(`cache/models/${modelName}`))).default;
35
- let fields = {};
36
- if (typeof model.attributes === "object")
37
- fields = model.attributes;
38
- else
39
- try {
40
- fields = JSON.parse(model.attributes || "{}");
41
- } catch {
42
- fields = {};
43
- }
44
- return fields;
45
- }
46
- export async function modelTableName(model) {
47
- if (typeof model === "string")
48
- model = (await import(model)).default;
49
- return model.table ?? snakeCase(plural(model?.name || ""));
50
- }
51
- export async function hasTableBeenMigrated(tableName) {
52
- log.debug(`hasTableBeenMigrated for table: ${tableName}`);
53
- return (await getExecutedMigrations()).some((migration) => migration.name.includes(tableName));
54
- }
55
- export async function hasMigrationBeenCreated(tableName) {
56
- log.debug(`hasTableBeenMigrated for table: ${tableName}`);
57
- return globSync([path.userMigrationsPath("*.ts")], { absolute: !0 }).some((path) => path.includes(`create-${tableName}`));
58
- }
59
- export async function getExecutedMigrations() {
60
- try {
61
- return await db.selectFrom("migrations").select("name").execute();
62
- } catch (error) {
63
- if (error?.message.includes("no such table: migrations")) {
64
- console.warn("Migrations table does not exist, returning empty list.");
65
- return [];
66
- }
67
- return [];
68
- }
69
- }
70
- function findCharacterLength(validator) {
71
- if ("getRules" in validator) {
72
- const maxLengthRule = validator.getRules().find((rule) => rule.name === "max");
73
- return maxLengthRule?.params?.length || maxLengthRule?.params?.max || 255;
74
- }
75
- return 255;
76
- }
77
- export function prepareTextColumnType(validator, driver = "mysql") {
78
- if (driver === "sqlite")
79
- return "'text'";
80
- return `'varchar(${findCharacterLength(validator)})'`;
81
- }
82
- export function prepareDateTimeColumnType(validator, driver = "mysql") {
83
- if (driver === "sqlite")
84
- return "'text'";
85
- const name = validator.name;
86
- if (name === "unix")
87
- return "'bigint'";
88
- return name || "date";
89
- }
90
- export function compareRanges(range1, range2) {
91
- return range1.min === range2.min && range1.max === range2.max;
92
- }
93
- export async function checkPivotMigration(dynamicPart) {
94
- return (await fs.promises.readdir(path.userMigrationsPath())).some((migrationFile) => {
95
- const escapedDynamicPart = dynamicPart.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
96
- return new RegExp(`(-${escapedDynamicPart}-)`).test(migrationFile);
97
- });
98
- }
99
- export function pluckChanges(array1, array2) {
100
- const removed = array1.filter((item) => !array2.includes(item)), added = array2.filter((item) => !array1.includes(item));
101
- if (removed.length === 0 && added.length === 0)
102
- return null;
103
- return { added, removed };
104
- }
105
- export function arrangeColumns(attributes) {
106
- if (!attributes)
107
- return [];
108
- const entries = Object.entries(attributes);
109
- entries.sort(([_keyA, valueA], [_keyB, valueB]) => {
110
- const orderA = valueA.order ?? Number.POSITIVE_INFINITY, orderB = valueB.order ?? Number.POSITIVE_INFINITY;
111
- return orderA - orderB;
112
- });
113
- return entries;
114
- }
115
- export function isArrayEqual(arr1, arr2) {
116
- if (!arr1 || !arr2)
117
- return !1;
118
- if (arr1.length !== arr2.length)
119
- return !1;
120
- for (let i = 0;i < arr1.length; i++)
121
- if (arr1[i] !== arr2[i])
122
- return !1;
123
- return !0;
124
- }
125
- export function findDifferingKeys(obj1, obj2) {
126
- const differingKeys = [];
127
- for (const key in obj1)
128
- if (Object.prototype.hasOwnProperty.call(obj1, key) && Object.prototype.hasOwnProperty.call(obj2, key)) {
129
- const lastCharacterLength = findCharacterLength(obj1[key].validation.rule), latestCharacterLength = findCharacterLength(obj2[key].validation.rule);
130
- if (lastCharacterLength !== void 0 && latestCharacterLength !== void 0) {
131
- if (lastCharacterLength !== latestCharacterLength)
132
- differingKeys.push({ key, max: latestCharacterLength, min: latestCharacterLength });
133
- }
134
- }
135
- return differingKeys;
136
- }
137
- export async function fetchTables() {
138
- const modelFiles = globSync([path.userModelsPath("*.ts"), path.storagePath("framework/defaults/app/Models/**/*.ts")], { absolute: !0 }), tables = [];
139
- for (const modelPath of modelFiles) {
140
- const model = (await import(modelPath)).default, tableName = getTableName(model, modelPath), upvoteTable = getUpvoteTableName(model, tableName);
141
- if (upvoteTable)
142
- tables.push(upvoteTable);
143
- tables.push(tableName);
144
- }
145
- return tables;
146
- }
147
- export function getUpvoteTableName(model, tableName) {
148
- const defaultTable = `${tableName}_likes`, traits = model.traits;
149
- if (!traits?.likeable)
150
- return;
151
- return typeof traits.likeable === "object" ? traits.likeable.table || defaultTable : defaultTable;
152
- }
153
- export function getLikeableForeignKey(model, tableName) {
154
- const likeable = model.traits?.likeable;
155
- if (likeable && typeof likeable === "object" && !Array.isArray(likeable) && likeable.foreignKey)
156
- return likeable.foreignKey;
157
- return `${tableName.replace(/s$/, "")}_id`;
158
- }
159
- export function prepareNumberColumnType(validator, driver = "mysql") {
160
- if (driver === "sqlite")
161
- return "'integer'";
162
- if ("getRules" in validator) {
163
- const minRule = validator.getRules().find((rule) => rule.name === "min"), maxRule = validator.getRules().find((rule) => rule.name === "max"), min = minRule?.params?.min ?? -2147483648, max = maxRule?.params?.max ?? 2147483647;
164
- return min >= -2147483648 && max <= 2147483647 ? "'integer'" : "'bigint'";
165
- }
166
- return "'integer'";
167
- }
168
- export function prepareEnumColumnType(validator, driver = "mysql") {
169
- const allowedValues = validator.getAllowedValues();
170
- if (!allowedValues)
171
- throw Error("Enum rule found but no allowedValues defined");
172
- const enumStructure = allowedValues.map((value) => `'${value}'`).join(", ");
173
- if (driver === "postgres")
174
- return "'varchar(255)'";
175
- if (driver === "sqlite")
176
- return "'text'";
177
- return `sql\`enum(${enumStructure})\``;
178
- }
179
- export function mapFieldTypeToColumnType(validator, driver = "mysql") {
180
- if (enumValidator(validator))
181
- return prepareEnumColumnType(validator, driver);
182
- if (isStringValidator(validator))
183
- return prepareTextColumnType(validator, driver);
184
- if (isNumberValidator(validator))
185
- return prepareNumberColumnType(validator, driver);
186
- if (isBooleanValidator(validator))
187
- return "'boolean'";
188
- if (isDateValidator(validator))
189
- return "'date'";
190
- if (isDatetimeValidator(validator))
191
- return driver === "postgres" ? "'timestamp'" : "'datetime'";
192
- if (isUnixValidator(validator))
193
- return "'bigint'";
194
- if (isTimestampValidator(validator))
195
- return "'timestamp'";
196
- if (isFloatValidator(validator))
197
- return "'float4'";
198
- if (["array", "object"].includes(validator.name))
199
- return driver === "sqlite" ? "'text'" : "'json'";
200
- if (driver === "sqlite")
201
- return "'text'";
202
- return driver === "mysql" ? "'varchar(255)'" : "'text'";
203
- }
204
- export function checkIsRequired(rule) {
205
- return rule.includes(".required()");
206
- }
1
+ import{log}from"@stacksjs/logging";import{getTableName}from"@stacksjs/orm";import{path}from"@stacksjs/path";import{fs,globSync}from"@stacksjs/storage";import{plural,snakeCase}from"@stacksjs/strings";import{db}from"../utils";import{enumValidator,isBooleanValidator,isDatetimeValidator,isDateValidator,isFloatValidator,isNumberValidator,isStringValidator,isTimestampValidator,isUnixValidator}from"../validators";export async function deleteMigrationFiles(){const files=await fs.promises.readdir(path.userMigrationsPath());if(files.length){for(const file of files)if(file.endsWith(".ts")){const migrationPath=path.userMigrationsPath(`${file}`);if(fs.existsSync(migrationPath))await Bun.$`rm ${migrationPath}`}}}export async function deleteFrameworkModels(){const cacheDir=path.frameworkPath("cache/models");if(!fs.existsSync(cacheDir))return;const modelFiles=await fs.promises.readdir(cacheDir);if(modelFiles.length){for(const modelFile of modelFiles)if(modelFile.endsWith(".ts")){const modelPath=path.frameworkPath(`cache/models/${modelFile}`);if(fs.existsSync(modelPath))await Bun.$`rm ${modelPath}`}}}export async function getLastMigrationFields(modelName){const model=(await import(path.frameworkPath(`cache/models/${modelName}`))).default;let fields={};if(typeof model.attributes==="object")fields=model.attributes;else try{fields=JSON.parse(model.attributes||"{}")}catch{fields={}}return fields}export async function modelTableName(model){if(typeof model==="string")model=(await import(model)).default;return model.table??snakeCase(plural(model?.name||""))}export async function hasTableBeenMigrated(tableName){log.debug(`hasTableBeenMigrated for table: ${tableName}`);return(await getExecutedMigrations()).some((migration)=>migration.name.includes(tableName))}export async function hasMigrationBeenCreated(tableName){log.debug(`hasTableBeenMigrated for table: ${tableName}`);return globSync([path.userMigrationsPath("*.ts")],{absolute:!0}).some((path)=>path.includes(`create-${tableName}`))}export async function getExecutedMigrations(){try{return await db.selectFrom("migrations").select("name").execute()}catch(error){if(error?.message.includes("no such table: migrations")){console.warn("Migrations table does not exist, returning empty list.");return[]}return[]}}function findCharacterLength(validator){if("getRules"in validator){const maxLengthRule=validator.getRules().find((rule)=>rule.name==="max");return maxLengthRule?.params?.length||maxLengthRule?.params?.max||255}return 255}export function prepareTextColumnType(validator,driver="mysql"){if(driver==="sqlite")return"'text'";return`'varchar(${findCharacterLength(validator)})'`}export function prepareDateTimeColumnType(validator,driver="mysql"){if(driver==="sqlite")return"'text'";const name=validator.name;if(name==="unix")return"'bigint'";return name||"date"}export function compareRanges(range1,range2){return range1.min===range2.min&&range1.max===range2.max}export async function checkPivotMigration(dynamicPart){return(await fs.promises.readdir(path.userMigrationsPath())).some((migrationFile)=>{const escapedDynamicPart=dynamicPart.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(-${escapedDynamicPart}-)`).test(migrationFile)})}export function pluckChanges(array1,array2){const removed=array1.filter((item)=>!array2.includes(item)),added=array2.filter((item)=>!array1.includes(item));if(removed.length===0&&added.length===0)return null;return{added,removed}}export function arrangeColumns(attributes){if(!attributes)return[];const entries=Object.entries(attributes);entries.sort(([_keyA,valueA],[_keyB,valueB])=>{const orderA=valueA.order??Number.POSITIVE_INFINITY,orderB=valueB.order??Number.POSITIVE_INFINITY;return orderA-orderB});return entries}export function isArrayEqual(arr1,arr2){if(!arr1||!arr2)return!1;if(arr1.length!==arr2.length)return!1;for(let i=0;i<arr1.length;i++)if(arr1[i]!==arr2[i])return!1;return!0}export function findDifferingKeys(obj1,obj2){const differingKeys=[];for(const key in obj1)if(Object.prototype.hasOwnProperty.call(obj1,key)&&Object.prototype.hasOwnProperty.call(obj2,key)){const lastCharacterLength=findCharacterLength(obj1[key].validation.rule),latestCharacterLength=findCharacterLength(obj2[key].validation.rule);if(lastCharacterLength!==void 0&&latestCharacterLength!==void 0){if(lastCharacterLength!==latestCharacterLength)differingKeys.push({key,max:latestCharacterLength,min:latestCharacterLength})}}return differingKeys}export async function fetchTables(){const modelFiles=globSync([path.userModelsPath("*.ts"),path.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}),tables=[];for(const modelPath of modelFiles){const model=(await import(modelPath)).default,tableName=getTableName(model,modelPath),upvoteTable=getUpvoteTableName(model,tableName);if(upvoteTable)tables.push(upvoteTable);tables.push(tableName)}return tables}export function getUpvoteTableName(model,tableName){const defaultTable=`${tableName}_likes`,traits=model.traits;if(!traits?.likeable)return;return typeof traits.likeable==="object"?traits.likeable.table||defaultTable:defaultTable}export function getLikeableForeignKey(model,tableName){const likeable=model.traits?.likeable;if(likeable&&typeof likeable==="object"&&!Array.isArray(likeable)&&likeable.foreignKey)return likeable.foreignKey;return`${tableName.replace(/s$/,"")}_id`}export function prepareNumberColumnType(validator,driver="mysql"){if(driver==="sqlite")return"'integer'";if("getRules"in validator){const minRule=validator.getRules().find((rule)=>rule.name==="min"),maxRule=validator.getRules().find((rule)=>rule.name==="max"),min=minRule?.params?.min??-2147483648,max=maxRule?.params?.max??2147483647;return min>=-2147483648&&max<=2147483647?"'integer'":"'bigint'"}return"'integer'"}export function prepareEnumColumnType(validator,driver="mysql"){const allowedValues=validator.getAllowedValues();if(!allowedValues)throw Error("Enum rule found but no allowedValues defined");const enumStructure=allowedValues.map((value)=>`'${value}'`).join(", ");if(driver==="postgres")return"'varchar(255)'";if(driver==="sqlite")return"'text'";return`sql\`enum(${enumStructure})\``}export function mapFieldTypeToColumnType(validator,driver="mysql"){if(enumValidator(validator))return prepareEnumColumnType(validator,driver);if(isStringValidator(validator))return prepareTextColumnType(validator,driver);if(isNumberValidator(validator))return prepareNumberColumnType(validator,driver);if(isBooleanValidator(validator))return"'boolean'";if(isDateValidator(validator))return"'date'";if(isDatetimeValidator(validator))return driver==="postgres"?"'timestamp'":"'datetime'";if(isUnixValidator(validator))return"'bigint'";if(isTimestampValidator(validator))return"'timestamp'";if(isFloatValidator(validator))return"'float4'";if(["array","object"].includes(validator.name))return driver==="sqlite"?"'text'":"'json'";if(driver==="sqlite")return"'text'";return driver==="mysql"?"'varchar(255)'":"'text'"}export function checkIsRequired(rule){return rule.includes(".required()")}
@@ -1,9 +1 @@
1
- export * from "./helpers";
2
- export * from "./mysql";
3
- export * from "./postgres";
4
- export * from "./sqlite";
5
- export { generateIndexCreationSQL } from "./mysql";
6
- export { generateIndexCreationSQL as generatePostgresIndexCreationSQL } from "./postgres";
7
- export { generateIndexCreationSQL as generateSqliteIndexCreationSQL } from "./sqlite";
8
- export * from "./defaults";
9
- export * from "./dynamodb";
1
+ export*from"./helpers";export*from"./mysql";export*from"./postgres";export*from"./sqlite";export{generateIndexCreationSQL}from"./mysql";export{generateIndexCreationSQL as generatePostgresIndexCreationSQL}from"./postgres";export{generateIndexCreationSQL as generateSqliteIndexCreationSQL}from"./sqlite";export*from"./defaults";export*from"./dynamodb";
@@ -1,309 +1,68 @@
1
- import { log } from "@stacksjs/logging";
2
- function italic(str) {
3
- return `\x1B[3m${str}\x1B[23m`;
4
- }
5
- import { db } from "../utils";
6
- import { ok } from "@stacksjs/error-handling";
7
- import { fetchOtherModelRelations, getModelName, getPivotTables, getTableName } from "@stacksjs/orm";
8
- import { path } from "@stacksjs/path";
9
- import { fs, globSync } from "@stacksjs/storage";
10
- import { snakeCase } from "@stacksjs/strings";
11
- import {
12
- arrangeColumns,
13
- checkPivotMigration,
14
- deleteFrameworkModels,
15
- deleteMigrationFiles,
16
- fetchTables,
17
- findDifferingKeys,
18
- getLastMigrationFields,
19
- getLikeableForeignKey,
20
- getUpvoteTableName,
21
- hasTableBeenMigrated,
22
- isArrayEqual,
23
- mapFieldTypeToColumnType,
24
- pluckChanges
25
- } from "./helpers";
26
- import { dropCommonTables } from "./defaults/traits";
27
- export async function resetMysqlDatabase() {
28
- await dropMysqlTables();
29
- await deleteFrameworkModels();
30
- await deleteMigrationFiles();
31
- return ok("All tables dropped successfully!");
32
- }
33
- export async function dropMysqlTables() {
34
- const modelFiles = globSync([path.userModelsPath("*.ts"), path.storagePath("framework/defaults/app/Models/**/*.ts")], { absolute: !0 }), tables = await fetchTables();
35
- for (const table of tables) {
36
- if (!/^[a-z_][\w]*$/i.test(table))
37
- throw Error(`[mysql] Refusing to drop table with unsafe name: ${table}`);
38
- await db.unsafe(`DROP TABLE IF EXISTS \`${table}\``).execute();
39
- }
40
- await dropCommonTables();
41
- for (const userModel of modelFiles) {
42
- const userModelPath = (await import(userModel)).default, pivotTables = await getPivotTables(userModelPath, userModel);
43
- for (const pivotTable of pivotTables) {
44
- if (!/^[a-z_][\w]*$/i.test(pivotTable.table))
45
- throw Error(`[mysql] Refusing to drop pivot table with unsafe name: ${pivotTable.table}`);
46
- await db.unsafe(`DROP TABLE IF EXISTS \`${pivotTable.table}\``).execute();
47
- }
48
- }
49
- }
50
- export async function generateMysqlMigration(modelPath) {
51
- const model = (await import(modelPath)).default, fileName = path.basename(modelPath), tableName = getTableName(model, modelPath), fieldsString = JSON.stringify(model.attributes, null, 2), copiedModelPath = path.frameworkPath(`cache/models/${fileName}`);
52
- let haveFieldsChanged = !1;
53
- if (fs.existsSync(copiedModelPath)) {
54
- log.info(`Fields have already been generated for ${tableName}`);
55
- const previousFields = await getLastMigrationFields(fileName);
56
- if (JSON.stringify(previousFields, null, 2) === fieldsString) {
57
- log.debug(`Fields have not changed for ${tableName}`);
58
- return;
59
- }
60
- haveFieldsChanged = !0;
61
- log.debug(`Fields have changed for ${tableName}`);
62
- } else
63
- log.debug(`Fields have not been generated for ${tableName}`);
64
- await Bun.$`mkdir -p ${path.frameworkPath("cache/models")} && cp ${modelPath} ${copiedModelPath}`;
65
- const hasBeenMigrated = await hasTableBeenMigrated(tableName);
66
- log.debug(`Has ${tableName} been migrated? ${hasBeenMigrated}`);
67
- if (haveFieldsChanged)
68
- await createAlterTableMigration(modelPath);
69
- else
70
- await createTableMigration(modelPath);
71
- }
72
- async function createTableMigration(modelPath) {
73
- log.debug("createTableMigration modelPath:", modelPath);
74
- const model = (await import(modelPath)).default, tableName = getTableName(model, modelPath), twoFactorEnabled = model.traits?.useAuth && typeof model.traits.useAuth !== "boolean" ? model.traits.useAuth.useTwoFactor : !1;
75
- await createPivotTableMigration(model, modelPath);
76
- const useTimestamps = model?.traits?.useTimestamps ?? model?.traits?.timestampable ?? !0, useSocials = model?.traits?.useSocials && Array.isArray(model.traits.useSocials) && model.traits.useSocials.length > 0, useLikeable = Array.isArray(model?.traits?.likeable) ? model.traits.likeable.length > 0 : Boolean(model?.traits?.likeable), useSoftDeletes = model?.traits?.useSoftDeletes ?? model?.traits?.softDeletable ?? !1, usePasskey = (typeof model.traits?.useAuth === "object" && model.traits.useAuth.usePasskey) ?? !1, useBillable = model.traits?.billable || !1, useUuid = model.traits?.useUuid || !1;
77
- if (useBillable && tableName === "users")
78
- await createTableMigration(path.frameworkPath("defaults/app/Models/Subscription.ts"));
79
- let migrationContent = `import type { Database } from '@stacksjs/database'
80
- `;
81
- migrationContent += `import { sql } from '@stacksjs/database'
1
+ import{log}from"@stacksjs/logging";function italic(str){return`\x1B[3m${str}\x1B[23m`}import{db}from"../utils";import{ok}from"@stacksjs/error-handling";import{fetchOtherModelRelations,getModelName,getPivotTables,getTableName}from"@stacksjs/orm";import{path}from"@stacksjs/path";import{fs,globSync}from"@stacksjs/storage";import{snakeCase}from"@stacksjs/strings";import{arrangeColumns,checkPivotMigration,deleteFrameworkModels,deleteMigrationFiles,fetchTables,findDifferingKeys,getLastMigrationFields,getLikeableForeignKey,getUpvoteTableName,hasTableBeenMigrated,isArrayEqual,mapFieldTypeToColumnType,pluckChanges}from"./helpers";import{dropCommonTables}from"./defaults/traits";export async function resetMysqlDatabase(){await dropMysqlTables();await deleteFrameworkModels();await deleteMigrationFiles();return ok("All tables dropped successfully!")}export async function dropMysqlTables(){const modelFiles=globSync([path.userModelsPath("*.ts"),path.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}),tables=await fetchTables();for(const table of tables){if(!/^[a-z_][\w]*$/i.test(table))throw Error(`[mysql] Refusing to drop table with unsafe name: ${table}`);await db.unsafe(`DROP TABLE IF EXISTS \`${table}\``).execute()}await dropCommonTables();for(const userModel of modelFiles){const userModelPath=(await import(userModel)).default,pivotTables=await getPivotTables(userModelPath,userModel);for(const pivotTable of pivotTables){if(!/^[a-z_][\w]*$/i.test(pivotTable.table))throw Error(`[mysql] Refusing to drop pivot table with unsafe name: ${pivotTable.table}`);await db.unsafe(`DROP TABLE IF EXISTS \`${pivotTable.table}\``).execute()}}}export async function generateMysqlMigration(modelPath){const model=(await import(modelPath)).default,fileName=path.basename(modelPath),tableName=getTableName(model,modelPath),fieldsString=JSON.stringify(model.attributes,null,2),copiedModelPath=path.frameworkPath(`cache/models/${fileName}`);let haveFieldsChanged=!1;if(fs.existsSync(copiedModelPath)){log.info(`Fields have already been generated for ${tableName}`);const previousFields=await getLastMigrationFields(fileName);if(JSON.stringify(previousFields,null,2)===fieldsString){log.debug(`Fields have not changed for ${tableName}`);return}haveFieldsChanged=!0;log.debug(`Fields have changed for ${tableName}`)}else log.debug(`Fields have not been generated for ${tableName}`);await Bun.$`mkdir -p ${path.frameworkPath("cache/models")} && cp ${modelPath} ${copiedModelPath}`;const hasBeenMigrated=await hasTableBeenMigrated(tableName);log.debug(`Has ${tableName} been migrated? ${hasBeenMigrated}`);if(haveFieldsChanged)await createAlterTableMigration(modelPath);else await createTableMigration(modelPath)}async function createTableMigration(modelPath){log.debug("createTableMigration modelPath:",modelPath);const model=(await import(modelPath)).default,tableName=getTableName(model,modelPath),twoFactorEnabled=model.traits?.useAuth&&typeof model.traits.useAuth!=="boolean"?model.traits.useAuth.useTwoFactor:!1;await createPivotTableMigration(model,modelPath);const useTimestamps=model?.traits?.useTimestamps??model?.traits?.timestampable??!0,useSocials=model?.traits?.useSocials&&Array.isArray(model.traits.useSocials)&&model.traits.useSocials.length>0,useLikeable=Array.isArray(model?.traits?.likeable)?model.traits.likeable.length>0:Boolean(model?.traits?.likeable),useSoftDeletes=model?.traits?.useSoftDeletes??model?.traits?.softDeletable??!1,usePasskey=(typeof model.traits?.useAuth==="object"&&model.traits.useAuth.usePasskey)??!1,useBillable=model.traits?.billable||!1,useUuid=model.traits?.useUuid||!1;if(useBillable&&tableName==="users")await createTableMigration(path.frameworkPath("defaults/app/Models/Subscription.ts"));let migrationContent=`import type { Database } from '@stacksjs/database'
2
+ `;migrationContent+=`import { sql } from '@stacksjs/database'
82
3
 
83
- `;
84
- migrationContent += `export async function up(db: Database<any>) {
85
- `;
86
- migrationContent += ` await (db as any).schema
87
- `;
88
- migrationContent += ` .createTable('${tableName}')
89
- `;
90
- migrationContent += ` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
91
- `;
92
- if (useUuid)
93
- migrationContent += ` .addColumn('uuid', 'varchar(255)')
94
- `;
95
- if (useSocials) {
96
- const socials = model.traits?.useSocials || [];
97
- if (socials.includes("google"))
98
- migrationContent += ` .addColumn('google_id', 'varchar(255)')
99
- `;
100
- if (socials.includes("github"))
101
- migrationContent += ` .addColumn('github_id', 'varchar(255)')
102
- `;
103
- if (socials.includes("apple"))
104
- migrationContent += ` .addColumn('apple_id', 'varchar(255)')
105
- `;
106
- if (socials.includes("twitter"))
107
- migrationContent += ` .addColumn('twitter_id', 'varchar(255)')
108
- `;
109
- if (socials.includes("facebook"))
110
- migrationContent += ` .addColumn('facebook_id', 'varchar(255)')
111
- `;
112
- }
113
- for (const [fieldName, options] of arrangeColumns(model.attributes)) {
114
- const fieldOptions = options, fieldNameFormatted = snakeCase(fieldName), columnType = mapFieldTypeToColumnType(fieldOptions.validation?.rule);
115
- migrationContent += ` .addColumn('${fieldNameFormatted}', ${columnType}`;
116
- const isRequired = "isRequired" in (fieldOptions.validation?.rule ?? {}) ? (fieldOptions.validation?.rule).isRequired : !1;
117
- if (isRequired || fieldOptions.unique || fieldOptions.default !== void 0) {
118
- migrationContent += ", col => col";
119
- if (isRequired)
120
- migrationContent += ".notNull()";
121
- if (fieldOptions.unique)
122
- migrationContent += ".unique()";
123
- if (fieldOptions.default !== void 0)
124
- if (typeof fieldOptions.default === "string")
125
- migrationContent += `.defaultTo('${fieldOptions.default.replace(/'/g, "\\'")}')`;
126
- else if (fieldOptions.default === null)
127
- migrationContent += ".defaultTo(null)";
128
- else
129
- migrationContent += `.defaultTo(${fieldOptions.default})`;
130
- migrationContent += "";
131
- }
132
- migrationContent += `)
133
- `;
134
- }
135
- if (twoFactorEnabled !== !1 && twoFactorEnabled)
136
- migrationContent += ` .addColumn('two_factor_secret', 'varchar(255)')
137
- `;
138
- if (useBillable)
139
- migrationContent += ` .addColumn('stripe_id', 'varchar(255)')
140
- `;
141
- if (usePasskey)
142
- migrationContent += ` .addColumn('public_passkey', 'varchar(255)')
143
- `;
144
- if (useTimestamps) {
145
- migrationContent += ` .addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
146
- `;
147
- migrationContent += ` .addColumn('updated_at', 'timestamp')
148
- `;
149
- }
150
- if (useSoftDeletes)
151
- migrationContent += ` .addColumn('deleted_at', 'timestamp')
152
- `;
153
- migrationContent += ` .execute()
154
- `;
155
- migrationContent += generatePrimaryKeyIndexSQL(tableName);
156
- if (useLikeable) {
157
- const upvoteTable = getUpvoteTableName(model, tableName);
158
- if (upvoteTable) {
159
- const foreignKey = getLikeableForeignKey(model, tableName);
160
- migrationContent += `
4
+ `;migrationContent+=`export async function up(db: Database<any>) {
5
+ `;migrationContent+=` await (db as any).schema
6
+ `;migrationContent+=` .createTable('${tableName}')
7
+ `;migrationContent+=` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
8
+ `;if(useUuid)migrationContent+=` .addColumn('uuid', 'varchar(255)')
9
+ `;if(useSocials){const socials=model.traits?.useSocials||[];if(socials.includes("google"))migrationContent+=` .addColumn('google_id', 'varchar(255)')
10
+ `;if(socials.includes("github"))migrationContent+=` .addColumn('github_id', 'varchar(255)')
11
+ `;if(socials.includes("apple"))migrationContent+=` .addColumn('apple_id', 'varchar(255)')
12
+ `;if(socials.includes("twitter"))migrationContent+=` .addColumn('twitter_id', 'varchar(255)')
13
+ `;if(socials.includes("facebook"))migrationContent+=` .addColumn('facebook_id', 'varchar(255)')
14
+ `}for(const[fieldName,options]of arrangeColumns(model.attributes)){const fieldOptions=options,fieldNameFormatted=snakeCase(fieldName),columnType=mapFieldTypeToColumnType(fieldOptions.validation?.rule);migrationContent+=` .addColumn('${fieldNameFormatted}', ${columnType}`;const isRequired="isRequired"in(fieldOptions.validation?.rule??{})?(fieldOptions.validation?.rule).isRequired:!1;if(isRequired||fieldOptions.unique||fieldOptions.default!==void 0){migrationContent+=", col => col";if(isRequired)migrationContent+=".notNull()";if(fieldOptions.unique)migrationContent+=".unique()";if(fieldOptions.default!==void 0)if(typeof fieldOptions.default==="string")migrationContent+=`.defaultTo('${fieldOptions.default.replace(/'/g,"\\'")}')`;else if(fieldOptions.default===null)migrationContent+=".defaultTo(null)";else migrationContent+=`.defaultTo(${fieldOptions.default})`;migrationContent+=""}migrationContent+=`)
15
+ `}if(twoFactorEnabled!==!1&&twoFactorEnabled)migrationContent+=` .addColumn('two_factor_secret', 'varchar(255)')
16
+ `;if(useBillable)migrationContent+=` .addColumn('stripe_id', 'varchar(255)')
17
+ `;if(usePasskey)migrationContent+=` .addColumn('public_passkey', 'varchar(255)')
18
+ `;if(useTimestamps){migrationContent+=` .addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
19
+ `;migrationContent+=` .addColumn('updated_at', 'timestamp')
20
+ `}if(useSoftDeletes)migrationContent+=` .addColumn('deleted_at', 'timestamp')
21
+ `;migrationContent+=` .execute()
22
+ `;migrationContent+=generatePrimaryKeyIndexSQL(tableName);if(useLikeable){const upvoteTable=getUpvoteTableName(model,tableName);if(upvoteTable){const foreignKey=getLikeableForeignKey(model,tableName);migrationContent+=`
161
23
  // Create upvote table
162
- `;
163
- migrationContent += ` await (db as any).schema
164
- `;
165
- migrationContent += ` .createTable('${upvoteTable}')
166
- `;
167
- migrationContent += ` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
168
- `;
169
- migrationContent += ` .addColumn('${foreignKey}', 'integer', col => col.notNull())
170
- `;
171
- migrationContent += ` .addColumn('user_id', 'integer', col => col.notNull())
172
- `;
173
- migrationContent += ` .addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
174
- `;
175
- migrationContent += ` .addColumn('updated_at', 'timestamp')
176
- `;
177
- migrationContent += ` .execute()
24
+ `;migrationContent+=` await (db as any).schema
25
+ `;migrationContent+=` .createTable('${upvoteTable}')
26
+ `;migrationContent+=` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
27
+ `;migrationContent+=` .addColumn('${foreignKey}', 'integer', col => col.notNull())
28
+ `;migrationContent+=` .addColumn('user_id', 'integer', col => col.notNull())
29
+ `;migrationContent+=` .addColumn('created_at', 'timestamp', col => col.notNull().defaultTo(sql.raw('CURRENT_TIMESTAMP')))
30
+ `;migrationContent+=` .addColumn('updated_at', 'timestamp')
31
+ `;migrationContent+=` .execute()
178
32
 
179
- `;
180
- migrationContent += ` // Add indexes for upvote table
181
- `;
182
- migrationContent += ` await (db as any).schema.createIndex('${upvoteTable}_${foreignKey}_index').on('${upvoteTable}').column('${foreignKey}').execute()
183
- `;
184
- migrationContent += ` await (db as any).schema.createIndex('${upvoteTable}_user_${foreignKey}_unique').on('${upvoteTable}').columns(['user_id', '${foreignKey}']).unique().execute()
185
- `;
186
- migrationContent += ` await (db as any).schema.createIndex('${upvoteTable}_id_index').on('${upvoteTable}').column('id').execute()
187
- `;
188
- }
189
- }
190
- migrationContent += `}
191
- `;
192
- const migrationFileName = `${new Date().getTime().toString()}-create-${tableName}-table.ts`, migrationFilePath = path.userMigrationsPath(migrationFileName);
193
- log.debug(migrationFilePath);
194
- await Bun.write(migrationFilePath, migrationContent);
195
- log.success(`Created migration: ${italic(migrationFileName)}`);
196
- }
197
- async function createPivotTableMigration(model, modelPath) {
198
- const pivotTables = await getPivotTables(model, modelPath), processedPivotTables = new Set;
199
- if (!pivotTables.length)
200
- return;
201
- for (const pivotTable of pivotTables) {
202
- if (processedPivotTables.has(pivotTable.table))
203
- continue;
204
- if (await checkPivotMigration(pivotTable.table)) {
205
- processedPivotTables.add(pivotTable.table);
206
- continue;
207
- }
208
- let migrationContent = `import type { Database } from '@stacksjs/database'
209
- `;
210
- migrationContent += `import { sql } from '@stacksjs/database'
33
+ `;migrationContent+=` // Add indexes for upvote table
34
+ `;migrationContent+=` await (db as any).schema.createIndex('${upvoteTable}_${foreignKey}_index').on('${upvoteTable}').column('${foreignKey}').execute()
35
+ `;migrationContent+=` await (db as any).schema.createIndex('${upvoteTable}_user_${foreignKey}_unique').on('${upvoteTable}').columns(['user_id', '${foreignKey}']).unique().execute()
36
+ `;migrationContent+=` await (db as any).schema.createIndex('${upvoteTable}_id_index').on('${upvoteTable}').column('id').execute()
37
+ `}}migrationContent+=`}
38
+ `;const migrationFileName=`${new Date().getTime().toString()}-create-${tableName}-table.ts`,migrationFilePath=path.userMigrationsPath(migrationFileName);log.debug(migrationFilePath);await Bun.write(migrationFilePath,migrationContent);log.success(`Created migration: ${italic(migrationFileName)}`)}async function createPivotTableMigration(model,modelPath){const pivotTables=await getPivotTables(model,modelPath),processedPivotTables=new Set;if(!pivotTables.length)return;for(const pivotTable of pivotTables){if(processedPivotTables.has(pivotTable.table))continue;if(await checkPivotMigration(pivotTable.table)){processedPivotTables.add(pivotTable.table);continue}let migrationContent=`import type { Database } from '@stacksjs/database'
39
+ `;migrationContent+=`import { sql } from '@stacksjs/database'
211
40
 
212
- `;
213
- migrationContent += `export async function up(db: Database<any>) {
214
- `;
215
- migrationContent += ` await (db as any).schema
216
- `;
217
- migrationContent += ` .createTable('${pivotTable.table}')
218
- `;
219
- migrationContent += ` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
220
- `;
221
- migrationContent += ` .addColumn('${pivotTable.firstForeignKey}', 'integer')
222
- `;
223
- migrationContent += ` .addColumn('${pivotTable.secondForeignKey}', 'integer')
224
- `;
225
- migrationContent += ` .addColumn('created_at', 'timestamp', col => col.defaultTo(sql.raw('CURRENT_TIMESTAMP')))
226
- `;
227
- migrationContent += ` .execute()
228
- `;
229
- migrationContent += ` }
230
- `;
231
- const migrationFileName = `${new Date().getTime().toString()}-create-${pivotTable.table}-table.ts`, migrationFilePath = path.userMigrationsPath(migrationFileName);
232
- await Bun.write(migrationFilePath, migrationContent);
233
- processedPivotTables.add(pivotTable.table);
234
- log.success(`Created pivot migration: ${migrationFileName}`);
235
- }
236
- }
237
- export async function createAlterTableMigration(modelPath) {
238
- const model = (await import(modelPath)).default, modelName = getModelName(model, modelPath), tableName = getTableName(model, modelPath);
239
- let hasChanged = !1;
240
- const lastFields = await getLastMigrationFields(modelName) ?? {}, currentFields = model.attributes, changes = pluckChanges(Object.keys(lastFields), Object.keys(currentFields)), fieldsToAdd = changes?.added || [], fieldsToRemove = changes?.removed || [];
241
- let migrationContent = `import type { Database } from '@stacksjs/database'
242
- `;
243
- migrationContent += `import { sql } from '@stacksjs/database'
41
+ `;migrationContent+=`export async function up(db: Database<any>) {
42
+ `;migrationContent+=` await (db as any).schema
43
+ `;migrationContent+=` .createTable('${pivotTable.table}')
44
+ `;migrationContent+=` .addColumn('id', 'integer', col => col.primaryKey().autoIncrement())
45
+ `;migrationContent+=` .addColumn('${pivotTable.firstForeignKey}', 'integer')
46
+ `;migrationContent+=` .addColumn('${pivotTable.secondForeignKey}', 'integer')
47
+ `;migrationContent+=` .addColumn('created_at', 'timestamp', col => col.defaultTo(sql.raw('CURRENT_TIMESTAMP')))
48
+ `;migrationContent+=` .execute()
49
+ `;migrationContent+=` }
50
+ `;const migrationFileName=`${new Date().getTime().toString()}-create-${pivotTable.table}-table.ts`,migrationFilePath=path.userMigrationsPath(migrationFileName);await Bun.write(migrationFilePath,migrationContent);processedPivotTables.add(pivotTable.table);log.success(`Created pivot migration: ${migrationFileName}`)}}export async function createAlterTableMigration(modelPath){const model=(await import(modelPath)).default,modelName=getModelName(model,modelPath),tableName=getTableName(model,modelPath);let hasChanged=!1;const lastFields=await getLastMigrationFields(modelName)??{},currentFields=model.attributes,changes=pluckChanges(Object.keys(lastFields),Object.keys(currentFields)),fieldsToAdd=changes?.added||[],fieldsToRemove=changes?.removed||[];let migrationContent=`import type { Database } from '@stacksjs/database'
51
+ `;migrationContent+=`import { sql } from '@stacksjs/database'
244
52
 
245
- `;
246
- migrationContent += `export async function up(db: Database<any>) {
247
- `;
248
- if (fieldsToAdd.length || fieldsToRemove.length) {
249
- hasChanged = !0;
250
- migrationContent += ` await (db as any).schema.alterTable('${tableName}')
251
- `;
252
- }
253
- const fieldValidations = findDifferingKeys(lastFields, currentFields);
254
- for (const fieldValidation of fieldValidations) {
255
- hasChanged = !0;
256
- const fieldNameFormatted = snakeCase(fieldValidation.key);
257
- migrationContent += ` .modifyColumn('${fieldNameFormatted}', 'varchar(${fieldValidation.max})')
258
- `;
259
- }
260
- const lastFieldOrder = Object.values(lastFields).map((attr) => attr.order), currentFieldOrder = Object.values(currentFields).map((attr) => attr.order);
261
- if (!isArrayEqual(lastFieldOrder, currentFieldOrder)) {
262
- hasChanged = !0;
263
- migrationContent += reArrangeColumns(model.attributes, tableName);
264
- }
265
- if (hasChanged) {
266
- migrationContent += ` .execute()
267
- `;
268
- migrationContent += `}
269
- `;
270
- const migrationFileName = `${new Date().getTime().toString()}-alter-${tableName}-table.ts`, migrationFilePath = path.userMigrationsPath(migrationFileName);
271
- await Bun.write(migrationFilePath, migrationContent);
272
- log.success(`Created alter migration: ${italic(migrationFileName)}`);
273
- }
274
- }
275
- export function generateIndexCreationSQL(tableName, index) {
276
- if (index.unique || index.where) {
277
- const unique = index.unique ? "UNIQUE " : "", cols = index.columns.map((col) => snakeCase(col)).join(", "), whereClause = index.where ? ` WHERE ${index.where}` : "";
278
- return ` await db.unsafe(\`CREATE ${unique}INDEX IF NOT EXISTS \\\`${index.name}\\\` ON \\\`${tableName}\\\` (${cols})${whereClause}\`).execute()
279
- `;
280
- }
281
- const columnsStr = index.columns.map((col) => `'${snakeCase(col)}'`).join(", ");
282
- return ` await (db as any).schema.createIndex('${index.name}').on('${tableName}').columns([${columnsStr}]).execute()
283
- `;
284
- }
285
- function generatePrimaryKeyIndexSQL(tableName) {
286
- return ` await (db as any).schema.createIndex('${tableName}_id_index').on('${tableName}').column('id').execute()
287
- `;
288
- }
289
- function generateForeignKeyIndexSQL(tableName, foreignKey) {
290
- return ` await (db as any).schema.createIndex('${tableName}_${foreignKey}_index').on('${tableName}').column('${foreignKey}').execute()
53
+ `;migrationContent+=`export async function up(db: Database<any>) {
54
+ `;if(fieldsToAdd.length||fieldsToRemove.length){hasChanged=!0;migrationContent+=` await (db as any).schema.alterTable('${tableName}')
55
+ `}const fieldValidations=findDifferingKeys(lastFields,currentFields);for(const fieldValidation of fieldValidations){hasChanged=!0;const fieldNameFormatted=snakeCase(fieldValidation.key);migrationContent+=` .modifyColumn('${fieldNameFormatted}', 'varchar(${fieldValidation.max})')
56
+ `}const lastFieldOrder=Object.values(lastFields).map((attr)=>attr.order),currentFieldOrder=Object.values(currentFields).map((attr)=>attr.order);if(!isArrayEqual(lastFieldOrder,currentFieldOrder)){hasChanged=!0;migrationContent+=reArrangeColumns(model.attributes,tableName)}if(hasChanged){migrationContent+=` .execute()
57
+ `;migrationContent+=`}
58
+ `;const migrationFileName=`${new Date().getTime().toString()}-alter-${tableName}-table.ts`,migrationFilePath=path.userMigrationsPath(migrationFileName);await Bun.write(migrationFilePath,migrationContent);log.success(`Created alter migration: ${italic(migrationFileName)}`)}}export function generateIndexCreationSQL(tableName,index){if(index.unique||index.where){const unique=index.unique?"UNIQUE ":"",cols=index.columns.map((col)=>snakeCase(col)).join(", "),whereClause=index.where?` WHERE ${index.where}`:"";return` await db.unsafe(\`CREATE ${unique}INDEX IF NOT EXISTS \\\`${index.name}\\\` ON \\\`${tableName}\\\` (${cols})${whereClause}\`).execute()
59
+ `}const columnsStr=index.columns.map((col)=>`'${snakeCase(col)}'`).join(", ");return` await (db as any).schema.createIndex('${index.name}').on('${tableName}').columns([${columnsStr}]).execute()
60
+ `}function generatePrimaryKeyIndexSQL(tableName){return` await (db as any).schema.createIndex('${tableName}_id_index').on('${tableName}').column('id').execute()
61
+ `}function generateForeignKeyIndexSQL(tableName,foreignKey){return` await (db as any).schema.createIndex('${tableName}_${foreignKey}_index').on('${tableName}').column('${foreignKey}').execute()
291
62
 
292
- `;
293
- }
294
- function reArrangeColumns(attributes, tableName) {
295
- const fields = arrangeColumns(attributes);
296
- let migrationContent = "", previousField = "";
297
- for (const [fieldName] of fields) {
298
- const fieldNameFormatted = snakeCase(fieldName);
299
- if (previousField)
300
- migrationContent += `await sql\`
63
+ `}function reArrangeColumns(attributes,tableName){const fields=arrangeColumns(attributes);let migrationContent="",previousField="";for(const[fieldName]of fields){const fieldNameFormatted=snakeCase(fieldName);if(previousField)migrationContent+=`await sql\`
301
64
  ALTER TABLE ${tableName}
302
65
  MODIFY COLUMN ${fieldNameFormatted} VARCHAR(255) NOT NULL AFTER ${snakeCase(previousField)};
303
66
  \`.execute(db)
304
67
 
305
- `;
306
- previousField = fieldNameFormatted;
307
- }
308
- return migrationContent;
309
- }
68
+ `;previousField=fieldNameFormatted}return migrationContent}