/** * Neon Toolkit Workflow Example * * This demonstrates a complete workflow for creating, using, and cleaning up * an ephemeral Neon database. Perfect for testing, CI/CD, and prototyping. */ import { NeonToolkit } from '@neondatabase/toolkit'; /** * Main workflow function */ export async function ephemeralDatabaseWorkflow() { const apiKey = process.env.NEON_API_KEY; if (!apiKey) { throw new Error('NEON_API_KEY environment variable is required'); } // Initialize Neon Toolkit const neon = new NeonToolkit({ apiKey }); console.log('๐Ÿš€ Starting ephemeral database workflow...\n'); try { // Step 1: Create ephemeral database console.log('๐Ÿ“ฆ Creating ephemeral database...'); const db = await neon.createEphemeralDatabase(); console.log(`โœ… Database created!`); console.log(` Connection string: ${db.url}\n`); // Step 2: Setup schema console.log('๐Ÿ“ Setting up schema...'); await db.query(` CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT NOW() ) `); console.log('โœ… Schema created\n'); // Step 3: Insert sample data console.log('๐Ÿ“ค Inserting sample data...'); const insertResult = await db.query( `INSERT INTO users (email, name) VALUES ($1, $2), ($3, $4), ($5, $6) RETURNING *`, [ 'alice@example.com', 'Alice', 'bob@example.com', 'Bob', 'charlie@example.com', 'Charlie', ] ); console.log(`โœ… Inserted ${insertResult.rows?.length || 0} users\n`); // Step 4: Query data console.log('๐Ÿ” Querying data...'); const selectResult = await db.query('SELECT * FROM users ORDER BY created_at'); console.log('โœ… Users in database:'); selectResult.rows?.forEach((row: any) => { console.log(` โ€ข ${row.name} (${row.email})`); }); console.log(''); // Step 5: Run tests (example) console.log('๐Ÿงช Running tests...'); const testResults = await runTests(db); console.log(`โœ… ${testResults.passed} tests passed, ${testResults.failed} failed\n`); // Step 6: Cleanup console.log('๐Ÿงน Cleaning up...'); await db.delete(); console.log('โœ… Ephemeral database destroyed\n'); console.log('๐ŸŽ‰ Workflow completed successfully!'); return true; } catch (error) { console.error('โŒ Error during workflow:', error); throw error; } } /** * Example test suite using ephemeral database */ async function runTests(db: any) { const tests = [ { name: 'User count should be 3', async run() { const result = await db.query('SELECT COUNT(*) as count FROM users'); return result.rows?.[0]?.count === 3; }, }, { name: 'Should find user by email', async run() { const result = await db.query( "SELECT * FROM users WHERE email = $1", ['alice@example.com'] ); return result.rows?.[0]?.name === 'Alice'; }, }, { name: 'Should insert new user', async run() { await db.query( 'INSERT INTO users (email, name) VALUES ($1, $2)', ['david@example.com', 'David'] ); const result = await db.query('SELECT COUNT(*) as count FROM users'); return result.rows?.[0]?.count === 4; }, }, { name: 'Should update user', async run() { await db.query( "UPDATE users SET name = $1 WHERE email = $2", ['Alice Updated', 'alice@example.com'] ); const result = await db.query( "SELECT name FROM users WHERE email = $1", ['alice@example.com'] ); return result.rows?.[0]?.name === 'Alice Updated'; }, }, { name: 'Should delete user', async run() { await db.query("DELETE FROM users WHERE email = $1", ['bob@example.com']); const result = await db.query('SELECT COUNT(*) as count FROM users'); return result.rows?.[0]?.count >= 3; }, }, ]; let passed = 0; let failed = 0; for (const test of tests) { try { const result = await test.run(); if (result) { console.log(` โœ… ${test.name}`); passed++; } else { console.log(` โŒ ${test.name}`); failed++; } } catch (error) { console.log(` โŒ ${test.name} (error)`); failed++; } } return { passed, failed }; } /** * Example: Using in CI/CD * Run this in your CI/CD pipeline for isolated testing */ export async function cicdWorkflow() { console.log('๐Ÿ”„ CI/CD Workflow\n'); const apiKey = process.env.NEON_API_KEY; if (!apiKey) { console.error('NEON_API_KEY not set. Skipping ephemeral database setup.'); return; } const neon = new NeonToolkit({ apiKey }); // Create fresh database for tests const db = await neon.createEphemeralDatabase(); console.log('โœ… Ephemeral database created for testing'); try { // Run your test suite // await runYourTestSuite(db.url); console.log('โœ… All tests passed!'); } finally { // Always cleanup await db.delete(); console.log('โœ… Ephemeral database cleaned up'); } } /** * Example: Create multiple isolated databases */ export async function multipleEphemeralDatabases() { const apiKey = process.env.NEON_API_KEY; if (!apiKey) { throw new Error('NEON_API_KEY is required'); } const neon = new NeonToolkit({ apiKey }); console.log('Creating 3 parallel ephemeral databases...\n'); const databases = await Promise.all([ neon.createEphemeralDatabase(), neon.createEphemeralDatabase(), neon.createEphemeralDatabase(), ]); console.log(`โœ… Created ${databases.length} databases\n`); try { // Use databases in parallel await Promise.all( databases.map(async (db, index) => { const result = await db.query( `SELECT $1::text as database_number`, [index + 1] ); console.log(`Database ${index + 1}: ${result.rows?.[0]?.database_number}`); }) ); } finally { // Cleanup all databases await Promise.all(databases.map((db) => db.delete())); console.log('\nโœ… All databases cleaned up'); } } // Export for use in tests export { runTests };