@@ -14,53 +14,180 @@ try {
14
14
const __filename = fileURLToPath ( import . meta. url )
15
15
const __dirname = path . dirname ( __filename )
16
16
17
- // Load .env.local if present
18
- const envPath = path . join ( process . cwd ( ) , '.env.local' )
19
- if ( fs . existsSync ( envPath ) ) {
20
- dotenv . config ( { path : envPath } )
17
+ // Check if we're in Vercel environment
18
+ const isVercel = process . env . VERCEL === '1' ;
19
+ const isProduction = process . env . VERCEL_ENV === 'production' ;
20
+
21
+ console . log ( `Environment: ${ isVercel ? 'Vercel' : 'Local' } ` ) ;
22
+ console . log ( `Deployment: ${ isProduction ? 'Production' : 'Preview' } ` ) ;
23
+
24
+ // Load .env.local if present (only in local development)
25
+ if ( ! isVercel ) {
26
+ const envPath = path . join ( process . cwd ( ) , '.env.local' )
27
+ if ( fs . existsSync ( envPath ) ) {
28
+ dotenv . config ( { path : envPath } )
29
+ }
21
30
}
22
31
23
- // Execute SQL files in order when a GEL_DATABASE_URL is available
32
+ // Check for database configuration
33
+ const edgedbInstance = process . env . EDGEDB_INSTANCE ;
34
+ const edgedbSecretKey = process . env . EDGEDB_SECRET_KEY ;
35
+ const gelDatabaseUrl = process . env . GEL_DATABASE_URL ;
36
+
37
+ console . log ( 'Database configuration:' ) ;
38
+ console . log ( `- EdgeDB: ${ edgedbInstance && edgedbSecretKey ? '✅ Configured' : '❌ Not configured' } ` ) ;
39
+ console . log ( `- GelDB/PostgreSQL: ${ gelDatabaseUrl ? '✅ Configured' : '❌ Not configured' } ` ) ;
40
+
41
+ // Execute SQL files in order when a database connection is available
24
42
const migrationsDir = path . join ( __dirname , 'gel' , 'migrations' )
43
+
44
+ if ( ! fs . existsSync ( migrationsDir ) ) {
45
+ console . log ( 'Migrations directory not found. Skipping migrations.' ) ;
46
+ process . exit ( 0 ) ;
47
+ }
48
+
25
49
const files = fs . readdirSync ( migrationsDir ) . filter ( f => f . endsWith ( '.sql' ) ) . sort ( )
26
50
console . log ( 'Found migrations:' , files )
27
51
28
- const connectionString = process . env . GEL_DATABASE_URL || process . env . DATABASE_URL
29
- if ( ! connectionString ) {
30
- console . error ( 'No GEL_DATABASE_URL provided. Skipping execution.' )
31
- process . exit ( 0 )
52
+ if ( files . length === 0 ) {
53
+ console . log ( 'No migration files found. Skipping migrations.' ) ;
54
+ process . exit ( 0 ) ;
55
+ }
56
+
57
+ // Determine connection string
58
+ let connectionString = null ;
59
+
60
+ if ( edgedbInstance && edgedbSecretKey ) {
61
+ // Use EdgeDB connection string
62
+ connectionString = `edgedb://${ edgedbInstance } :${ edgedbSecretKey } @edgedb.cloud` ;
63
+ console . log ( 'Using EdgeDB connection' ) ;
64
+ } else if ( gelDatabaseUrl ) {
65
+ // Use GelDB/PostgreSQL connection string
66
+ connectionString = gelDatabaseUrl ;
67
+ console . log ( 'Using GelDB/PostgreSQL connection' ) ;
68
+ } else {
69
+ console . log ( 'No database configuration found. Skipping migrations.' ) ;
70
+ process . exit ( 0 ) ;
32
71
}
33
72
34
73
if ( ! Client ) {
35
- console . error ( 'No pg client available. Install pg to execute migrations.' )
36
- process . exit ( 1 )
74
+ console . error ( 'No pg client available. Install pg to execute migrations.' ) ;
75
+ if ( isVercel ) {
76
+ console . log ( 'Continuing build without migrations (Vercel environment)' ) ;
77
+ process . exit ( 0 ) ;
78
+ } else {
79
+ process . exit ( 1 ) ;
80
+ }
37
81
}
38
82
39
- const client = new Client ( { connectionString } )
40
- await client . connect ( )
83
+ const client = new Client ( {
84
+ connectionString,
85
+ connectionTimeoutMillis : 10000 , // 10 seconds
86
+ query_timeout : 30000 , // 30 seconds
87
+ } )
88
+
41
89
try {
42
- for ( const file of files ) {
90
+ await client . connect ( )
91
+ console . log ( 'Connected to database successfully' )
92
+ } catch ( connectError ) {
93
+ console . error ( 'Failed to connect to database:' , connectError . message )
94
+ if ( isVercel ) {
95
+ console . log ( 'Continuing build without migrations (database connection failed)' )
96
+ process . exit ( 0 )
97
+ } else {
98
+ process . exit ( 1 )
99
+ }
100
+ }
101
+
102
+ try {
103
+ // Create migrations tracking table if it doesn't exist
104
+ await client . query ( `
105
+ CREATE TABLE IF NOT EXISTS schema_migrations (
106
+ id SERIAL PRIMARY KEY,
107
+ version VARCHAR(255) UNIQUE NOT NULL,
108
+ applied_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
109
+ )
110
+ ` )
111
+ console . log ( 'Migrations tracking table ready' )
112
+
113
+ // Get already applied migrations
114
+ let appliedMigrations = [ ]
115
+ try {
116
+ const result = await client . query ( 'SELECT version FROM schema_migrations ORDER BY version' )
117
+ appliedMigrations = result . rows . map ( row => row . version )
118
+ console . log ( 'Already applied migrations:' , appliedMigrations )
119
+ } catch ( error ) {
120
+ console . log ( 'No migrations table found, assuming no migrations applied' )
121
+ }
122
+
123
+ // Filter out already applied migrations
124
+ const pendingMigrations = files . filter ( file => ! appliedMigrations . includes ( file ) )
125
+ console . log ( 'Pending migrations:' , pendingMigrations )
126
+
127
+ if ( pendingMigrations . length === 0 ) {
128
+ console . log ( 'All migrations already applied' )
129
+ await client . end ( )
130
+ process . exit ( 0 )
131
+ }
132
+
133
+ // Apply each pending migration
134
+ for ( const file of pendingMigrations ) {
43
135
const full = path . join ( migrationsDir , file )
44
136
const sql = fs . readFileSync ( full , 'utf8' )
45
137
console . log ( `Applying ${ file } ...` )
138
+
46
139
try {
47
140
await client . query ( 'BEGIN' )
48
141
await client . query ( sql )
142
+
143
+ // Record migration as applied
144
+ await client . query ( 'INSERT INTO schema_migrations (version) VALUES ($1)' , [ file ] )
145
+
49
146
await client . query ( 'COMMIT' )
147
+ console . log ( `✅ Successfully applied ${ file } ` )
50
148
} catch ( e ) {
51
149
await client . query ( 'ROLLBACK' )
52
150
const msg = String ( e ?. message || e )
53
- if ( / a l r e a d y e x i s t s | d u p l i c a t e _ o b j e c t / i. test ( msg ) ) {
54
- console . warn ( `Skipping ${ file } : objects already exist` )
151
+
152
+ if ( / a l r e a d y e x i s t s | d u p l i c a t e _ o b j e c t | r e l a t i o n .* a l r e a d y e x i s t s / i. test ( msg ) ) {
153
+ console . warn ( `⚠️ Skipping ${ file } : objects already exist` )
154
+
155
+ // Still record it as applied since the objects exist
156
+ try {
157
+ await client . query ( 'BEGIN' )
158
+ await client . query ( 'INSERT INTO schema_migrations (version) VALUES ($1) ON CONFLICT (version) DO NOTHING' , [ file ] )
159
+ await client . query ( 'COMMIT' )
160
+ } catch ( recordError ) {
161
+ await client . query ( 'ROLLBACK' )
162
+ console . warn ( `Could not record ${ file } as applied:` , recordError . message )
163
+ }
164
+ continue
165
+ }
166
+
167
+ console . error ( `❌ Failed to apply ${ file } :` , msg )
168
+ if ( isVercel ) {
169
+ console . log ( 'Continuing with other migrations...' )
55
170
continue
171
+ } else {
172
+ throw e
56
173
}
57
- throw e
58
174
}
59
175
}
60
- console . log ( 'Migrations applied successfully' )
176
+
177
+ console . log ( '✅ Migrations completed successfully' )
61
178
} catch ( err ) {
62
- console . error ( 'Migration failed:' , err )
63
- process . exit ( 1 )
179
+ console . error ( '❌ Migration process failed:' , err . message )
180
+ if ( isVercel ) {
181
+ console . log ( 'Continuing build despite migration failure (Vercel environment)' )
182
+ console . log ( '💡 Run migrations manually after deployment if needed' )
183
+ } else {
184
+ process . exit ( 1 )
185
+ }
64
186
} finally {
65
- await client . end ( )
187
+ try {
188
+ await client . end ( )
189
+ console . log ( 'Database connection closed' )
190
+ } catch ( closeError ) {
191
+ console . warn ( 'Error closing database connection:' , closeError . message )
192
+ }
66
193
}
0 commit comments