kaneo (minimalist kanban) fork to experiment adding a tangled integration
github.com/usekaneo/kaneo
1import { sql } from "drizzle-orm";
2import db from "../database";
3
4/**
5 * Migration script to:
6 * 1. Rename active_workspace_id to active_organization_id in session table
7 * 2. Add created_at column to invitation table if it doesn't exist
8 * This runs before Drizzle migrations to ensure the column names match the schema.
9 */
10export async function migrateSessionColumn() {
11 console.log(
12 "🔄 Checking session table for active_workspace_id to active_organization_id migration...",
13 );
14
15 try {
16 // Migrate session table column
17 const sessionTableExists = await db.execute(sql`
18 SELECT EXISTS (
19 SELECT 1
20 FROM information_schema.tables
21 WHERE table_name = 'session'
22 ) AS exists;
23 `);
24
25 const sessionExists =
26 sessionTableExists.rows[0]?.exists === true ||
27 sessionTableExists.rows[0]?.exists === "t";
28 if (sessionExists) {
29 // Check if active_workspace_id column exists
30 const hasOldColumn = await db.execute(sql`
31 SELECT column_name
32 FROM information_schema.columns
33 WHERE table_name = 'session'
34 AND column_name = 'active_workspace_id'
35 `);
36
37 // Check if active_organization_id column already exists
38 const hasNewColumn = await db.execute(sql`
39 SELECT column_name
40 FROM information_schema.columns
41 WHERE table_name = 'session'
42 AND column_name = 'active_organization_id'
43 `);
44
45 if (hasOldColumn.rows.length > 0 && hasNewColumn.rows.length === 0) {
46 console.log(
47 "📝 Found active_workspace_id column, renaming to active_organization_id...",
48 );
49 await db.execute(sql`
50 ALTER TABLE "session"
51 RENAME COLUMN "active_workspace_id" TO "active_organization_id";
52 `);
53 console.log(
54 "✅ Successfully renamed active_workspace_id to active_organization_id",
55 );
56 } else if (hasNewColumn.rows.length > 0) {
57 console.log(
58 "✅ active_organization_id column already exists — skipping migration.",
59 );
60 } else if (hasOldColumn.rows.length === 0) {
61 console.log(
62 "🛈 active_workspace_id column does not exist — skipping migration.",
63 );
64 }
65 } else {
66 console.log("🛈 session table does not exist — skipping migration.");
67 }
68
69 // Migrate invitation table - add created_at column
70 console.log(
71 "🔄 Checking invitation table for created_at column migration...",
72 );
73
74 const invitationTableExists = await db.execute(sql`
75 SELECT EXISTS (
76 SELECT 1
77 FROM information_schema.tables
78 WHERE table_name = 'invitation'
79 ) AS exists;
80 `);
81
82 const invitationExists =
83 invitationTableExists.rows[0]?.exists === true ||
84 invitationTableExists.rows[0]?.exists === "t";
85
86 if (invitationExists) {
87 const hasCreatedAt = await db.execute(sql`
88 SELECT column_name
89 FROM information_schema.columns
90 WHERE table_name = 'invitation'
91 AND column_name = 'created_at'
92 `);
93
94 if (hasCreatedAt.rows.length === 0) {
95 console.log("📝 Adding created_at column to invitation table...");
96 // Add column as nullable first
97 await db.execute(sql`
98 ALTER TABLE "invitation"
99 ADD COLUMN "created_at" timestamp;
100 `);
101
102 // Set default value for existing rows (use expires_at - 1 month as a reasonable default)
103 await db.execute(sql`
104 UPDATE "invitation"
105 SET "created_at" = COALESCE("expires_at" - INTERVAL '1 month', NOW())
106 WHERE "created_at" IS NULL;
107 `);
108
109 // Now make it NOT NULL with default
110 await db.execute(sql`
111 ALTER TABLE "invitation"
112 ALTER COLUMN "created_at" SET DEFAULT NOW(),
113 ALTER COLUMN "created_at" SET NOT NULL;
114 `);
115 console.log(
116 "✅ Successfully added created_at column to invitation table",
117 );
118 } else {
119 console.log(
120 "✅ created_at column already exists in invitation table — skipping migration.",
121 );
122 }
123 } else {
124 console.log("🛈 invitation table does not exist — skipping migration.");
125 }
126 } catch (error) {
127 console.error("❌ Error during migration:", error);
128 throw error;
129 }
130}