@ooneex/migrations 0.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ooneex
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @ooneex/migrations
@@ -0,0 +1,39 @@
1
+ import { SQL } from "bun";
2
+ declare const createMigrationTable: (sql: SQL, tableName: string) => Promise<void>;
3
+ import { EContainerScope } from "@ooneex/container";
4
+ import { SQL as SQL2, TransactionSQL } from "bun";
5
+ type MigrationClassType = new (...args: any[]) => IMigration;
6
+ interface IMigration {
7
+ up: (tx: TransactionSQL, sql: SQL2) => Promise<void>;
8
+ down: (tx: TransactionSQL, sql: SQL2) => Promise<void>;
9
+ getVersion: () => string;
10
+ }
11
+ declare const migration: (scope?: EContainerScope) => (target: MigrationClassType) => void;
12
+ /**
13
+ * Generates a migration version based on the current timestamp.
14
+ *
15
+ * Format: YYYYMMDDHHMMSSMMM
16
+ * - YYYY: 4-digit year (e.g., 2025)
17
+ * - MM: 2-digit month (01-12)
18
+ * - DD: 2-digit day (01-31)
19
+ * - HH: 2-digit hour in 24-hour format (00-23)
20
+ * - MM: 2-digit minutes (00-59)
21
+ * - SS: 2-digit seconds (00-59)
22
+ * - MMM: 3-digit milliseconds (000-999)
23
+ *
24
+ * @returns {string} A migration version string (e.g., "20250630210755123")
25
+ *
26
+ * @example
27
+ * const version = generateMigrationVersion();
28
+ * console.log(version); // "20250630210755123"
29
+ */
30
+ declare const generateMigrationVersion: () => string;
31
+ declare const getMigrations: () => IMigration[];
32
+ declare const migrationCreate: (config?: {
33
+ dir?: string;
34
+ }) => Promise<void>;
35
+ declare const migrationUp: (config?: {
36
+ databaseUrl?: string;
37
+ tableName?: string;
38
+ }) => Promise<void>;
39
+ export { migrationUp, migrationCreate, migration, getMigrations, generateMigrationVersion, createMigrationTable, MigrationClassType, IMigration };
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ // @bun
2
+ var g=async(o,t)=>{await o.begin(async(r)=>{await r`CREATE TABLE IF NOT EXISTS ${o(t)} (id VARCHAR(20) PRIMARY KEY)`})};import{ContainerException as f,container as y,EContainerScope as I}from"@ooneex/container";var c=[];var l=(o=I.Singleton)=>{return(t)=>{if(!t.name.startsWith("Migration"))throw new f(`Class name "${t.name}" must start with "Migration"`);y.add(t,o),c.push(t)}};var M=()=>{let o=new Date,t=o.getFullYear().toString(),r=(o.getMonth()+1).toString().padStart(2,"0"),i=o.getDate().toString().padStart(2,"0"),s=o.getHours().toString().padStart(2,"0"),n=o.getMinutes().toString().padStart(2,"0"),e=o.getSeconds().toString().padStart(2,"0"),m=o.getMilliseconds().toString().padStart(3,"0");return`${t}${r}${i}${s}${n}${e}${m}`};import{container as w}from"@ooneex/container";var d=()=>{return c.map((t)=>{return w.get(t)}).sort((t,r)=>Number(t.getVersion())-Number(r.getVersion()))};import{join as u}from"path";import{TerminalLogger as T}from"@ooneex/logger";var{Glob:$}=globalThis.Bun;var S=`import { type IMigration, migration } from '@ooneex/migrations';
3
+ import type { TransactionSQL } from 'bun';
4
+
5
+ @migration()
6
+ export class {{ name }} implements IMigration {
7
+ public async up(tx: TransactionSQL): Promise<void> {
8
+ // await tx\`...\`;
9
+ }
10
+
11
+ public async down(tx: TransactionSQL): Promise<void> {
12
+ // await tx\`...\`;
13
+ }
14
+
15
+ public getVersion(): string {
16
+ return '{{ version }}';
17
+ }
18
+ }
19
+ `;var C=async(o)=>{let t=M(),r=`Migration${t}`,i=o?.dir||"migrations",s=new T;await Bun.write(u(process.cwd(),i,`${r}.ts`),S.replaceAll("{{ name }}",r).replaceAll("{{ version }}",t));let n=[],e=new $("**/Migration*.ts");for await(let m of e.scan(i)){let a=m.replace(/\.ts$/,"");n.push(`export { ${a} } from './${a}';`)}await Bun.write(u(process.cwd(),i,"migrations.ts"),`${n.sort().join(`
20
+ `)}
21
+ `),s.success(`Migration ${r} created successfully
22
+ `)};import{TerminalLogger as A}from"@ooneex/logger";var{SQL:v}=globalThis.Bun;var R=async(o)=>{let t=o?.tableName||"migrations",r=new v({url:o?.databaseUrl||Bun.env.DATABASE_URL,max:20,idleTimeout:30,maxLifetime:0,connectionTimeout:30}),i=new A,s=d();if(s.length===0)i.info(`No migrations found
23
+ `),process.exit(0);await g(r,t);for(let n of s){let e=n.getVersion();if((await r`SELECT * FROM ${r(t)} WHERE id = ${e}`).length>0)continue;let a=e;try{await r.begin(async(p)=>{await n.up(p,r),await p`INSERT INTO ${r(t)} (id) VALUES (${e})`,i.success(`Migration ${a} completed
24
+ `)})}catch(p){i.error(`Migration ${a} failed
25
+ `),i.error(p),process.exit(1)}}};export{R as migrationUp,C as migrationCreate,l as migration,d as getMigrations,M as generateMigrationVersion,g as createMigrationTable};
26
+
27
+ //# debugId=372B947C78EA7B1B64756E2164756E21
@@ -0,0 +1,16 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["src/createMigrationTable.ts", "src/decorators.ts", "src/container.ts", "src/generateMigrationVersion.ts", "src/getMigrations.ts", "src/migrationCreate.ts", "src/migrationUp.ts"],
4
+ "sourcesContent": [
5
+ "import type { SQL } from \"bun\";\n\nexport const createMigrationTable = async (sql: SQL, tableName: string): Promise<void> => {\n await sql.begin(async (tx) => {\n await tx`CREATE TABLE IF NOT EXISTS ${sql(tableName)} (id VARCHAR(20) PRIMARY KEY)`;\n });\n};\n",
6
+ "import { ContainerException, container, EContainerScope } from \"@ooneex/container\";\nimport { MIGRATIONS_CONTAINER } from \"./container\";\nimport type { MigrationClassType } from \"./types\";\n\nexport const migration = (scope: EContainerScope = EContainerScope.Singleton) => {\n return (target: MigrationClassType): void => {\n if (!target.name.startsWith(\"Migration\")) {\n throw new ContainerException(`Class name \"${target.name}\" must start with \"Migration\"`);\n }\n container.add(target, scope);\n MIGRATIONS_CONTAINER.push(target);\n };\n};\n",
7
+ "import type { MigrationClassType } from \"./types\";\n\nexport const MIGRATIONS_CONTAINER: MigrationClassType[] = [];\n",
8
+ "/**\n * Generates a migration version based on the current timestamp.\n *\n * Format: YYYYMMDDHHMMSSMMM\n * - YYYY: 4-digit year (e.g., 2025)\n * - MM: 2-digit month (01-12)\n * - DD: 2-digit day (01-31)\n * - HH: 2-digit hour in 24-hour format (00-23)\n * - MM: 2-digit minutes (00-59)\n * - SS: 2-digit seconds (00-59)\n * - MMM: 3-digit milliseconds (000-999)\n *\n * @returns {string} A migration version string (e.g., \"20250630210755123\")\n *\n * @example\n * const version = generateMigrationVersion();\n * console.log(version); // \"20250630210755123\"\n */\nexport const generateMigrationVersion = (): string => {\n const now = new Date();\n\n const year = now.getFullYear().toString();\n const month = (now.getMonth() + 1).toString().padStart(2, \"0\");\n const date = now.getDate().toString().padStart(2, \"0\");\n const hour = now.getHours().toString().padStart(2, \"0\");\n const minutes = now.getMinutes().toString().padStart(2, \"0\");\n const seconds = now.getSeconds().toString().padStart(2, \"0\");\n const milliseconds = now.getMilliseconds().toString().padStart(3, \"0\");\n\n return `${year}${month}${date}${hour}${minutes}${seconds}${milliseconds}`;\n};\n",
9
+ "import { container } from \"@ooneex/container\";\nimport { MIGRATIONS_CONTAINER } from \"./container\";\nimport type { IMigration } from \"./types\";\n\nexport const getMigrations = (): IMigration[] => {\n const migrationInstances = MIGRATIONS_CONTAINER.map((MigrationClass) => {\n return container.get(MigrationClass);\n });\n\n return migrationInstances.sort((a, b) => Number(a.getVersion()) - Number(b.getVersion()));\n};\n",
10
+ "import { join } from \"node:path\";\nimport { TerminalLogger } from \"@ooneex/logger\";\nimport { Glob } from \"bun\";\nimport { generateMigrationVersion } from \"./generateMigrationVersion\";\nimport content from \"./migration.txt\";\n\nexport const migrationCreate = async (config?: { dir?: string }): Promise<void> => {\n const version = generateMigrationVersion();\n const name = `Migration${version}`;\n const migrationsDir = config?.dir || \"migrations\";\n const logger = new TerminalLogger();\n\n await Bun.write(\n join(process.cwd(), migrationsDir, `${name}.ts`),\n content.replaceAll(\"{{ name }}\", name).replaceAll(\"{{ version }}\", version),\n );\n\n const imports: string[] = [];\n const glob = new Glob(\"**/Migration*.ts\");\n for await (const file of glob.scan(migrationsDir)) {\n const name = file.replace(/\\.ts$/, \"\");\n imports.push(`export { ${name} } from './${name}';`);\n }\n\n await Bun.write(join(process.cwd(), migrationsDir, \"migrations.ts\"), `${imports.sort().join(\"\\n\")}\\n`);\n\n logger.success(`Migration ${name} created successfully\\n`);\n};\n",
11
+ "import type { IException } from \"@ooneex/exception\";\nimport { TerminalLogger } from \"@ooneex/logger\";\nimport { SQL } from \"bun\";\nimport { createMigrationTable } from \"./createMigrationTable\";\nimport { getMigrations } from \"./getMigrations\";\n\nexport const migrationUp = async (config?: { databaseUrl?: string; tableName?: string }): Promise<void> => {\n const tableName = config?.tableName || \"migrations\";\n\n const sql = new SQL({\n url: config?.databaseUrl || Bun.env.DATABASE_URL,\n\n // Connection pool settings\n max: 20, // Maximum connections in pool\n idleTimeout: 30, // Close idle connections after 30s\n maxLifetime: 0, // Connection lifetime in seconds (0 = forever)\n connectionTimeout: 30, // Timeout when establishing new connections\n });\n\n const logger = new TerminalLogger();\n const migrations = getMigrations();\n\n if (migrations.length === 0) {\n logger.info(\"No migrations found\\n\");\n process.exit(0);\n }\n\n await createMigrationTable(sql, tableName);\n\n for (const migration of migrations) {\n const id = migration.getVersion();\n\n const entities = await sql`SELECT * FROM ${sql(tableName)} WHERE id = ${id}`;\n\n if (entities.length > 0) {\n continue;\n }\n\n const migrationName = id;\n\n try {\n await sql.begin(async (tx) => {\n await migration.up(tx, sql);\n await tx`INSERT INTO ${sql(tableName)} (id) VALUES (${id})`;\n logger.success(`Migration ${migrationName} completed\\n`);\n });\n } catch (error: unknown) {\n logger.error(`Migration ${migrationName} failed\\n`);\n logger.error(error as IException);\n process.exit(1);\n }\n }\n};\n"
12
+ ],
13
+ "mappings": "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",
14
+ "debugId": "372B947C78EA7B1B64756E2164756E21",
15
+ "names": []
16
+ }
Binary file
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@ooneex/migrations",
3
+ "description": "",
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "files": [
7
+ "dist",
8
+ "LICENSE",
9
+ "README.md",
10
+ "package.json"
11
+ ],
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "./package.json": "./package.json"
22
+ },
23
+ "license": "MIT",
24
+ "scripts": {
25
+ "test": "bun test tests",
26
+ "build": "bunup",
27
+ "lint": "tsgo --noEmit && bunx biome lint",
28
+ "publish:prod": "bun publish --tolerate-republish --access public",
29
+ "publish:pack": "bun pm pack --destination ./dist",
30
+ "publish:dry": "bun publish --dry-run"
31
+ },
32
+ "dependencies": {
33
+ "@ooneex/container": "0.0.1",
34
+ "@ooneex/logger": "0.0.1"
35
+ },
36
+ "devDependencies": {
37
+ "@ooneex/exception": "0.0.1"
38
+ },
39
+ "peerDependencies": {}
40
+ }