Database Operations
Query Execution
typescript
type DbError = { code: string; detail: string }
interface User {
id: string
name: string
email: string
}
async function findUserById(id: string): AsyncResult<User, DbError> {
return Result.fromPromise(
() => db.query<User>('SELECT * FROM users WHERE id = $1', [id]),
(error): DbError => ({
code: 'QUERY_FAILED',
detail: String(error)
})
)
}
// Usage
const result = await findUserById('123')
result.match({
ok: (user) => console.log('Found:', user),
err: (error) => console.error(`${error.code}: ${error.detail}`)
})Transactions
typescript
interface TransferResult {
fromBalance: number
toBalance: number
}
async function transferFunds(
fromId: string,
toId: string,
amount: number
): AsyncResult<TransferResult, DbError> {
return Result.fromPromise(
async () => {
const client = await db.connect()
try {
await client.query('BEGIN')
// Deduct from source
await client.query(
'UPDATE accounts SET balance = balance - $1 WHERE id = $2',
[amount, fromId]
)
// Add to destination
await client.query(
'UPDATE accounts SET balance = balance + $1 WHERE id = $2',
[amount, toId]
)
// Verify balance
const fromAccount = await client.query(
'SELECT balance FROM accounts WHERE id = $1',
[fromId]
)
if (fromAccount.balance < 0) {
throw new Error('Insufficient funds')
}
await client.query('COMMIT')
return {
fromBalance: fromAccount.balance,
toBalance: (await client.query(
'SELECT balance FROM accounts WHERE id = $1',
[toId]
)).balance
}
} catch (error) {
await client.query('ROLLBACK')
throw error
} finally {
client.release()
}
},
(error): DbError => ({
code: 'TRANSACTION_FAILED',
detail: String(error)
})
)
}
// Usage
const result = await transferFunds('user1', 'user2', 100)
result.match({
ok: (transfer) => console.log('Complete:', transfer),
err: (error) => console.error('Failed:', error.detail)
})Batch Operations
typescript
async function bulkInsertUsers(users: User[]): AsyncResult<number, DbError> {
return Result.fromPromise(
async () => {
const values = users
.map((_, i) => `($${i * 3 + 1}, $${i * 3 + 2}, $${i * 3 + 3})`)
.join(',')
const params = users.flatMap((u) => [u.id, u.name, u.email])
const result = await db.query(
`INSERT INTO users (id, name, email) VALUES ${values} RETURNING id`,
params
)
return result.length
},
(error): DbError => ({ code: 'INSERT_FAILED', detail: String(error) })
)
}
// Usage
const result = await bulkInsertUsers([
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' }
])
result.match({
ok: (count) => console.log(`Inserted ${count} users`),
err: (error) => console.error('Insert failed:', error.detail)
})Batch Processing with Report
typescript
interface ProcessingReport {
total: number
succeeded: number
failed: number
}
async function processBatch(ids: string[]): Promise<ProcessingReport> {
const results = await Promise.all(ids.map((id) => findUserById(id)))
const [users, errors] = Result.partition(results)
return {
total: ids.length,
succeeded: users.length,
failed: errors.length
}
}
// Usage
const report = await processBatch(['1', '2', '3', 'invalid'])
console.log(`Processed: ${report.succeeded}/${report.total}`)Data Migration
typescript
async function migrateUsers(): AsyncResult<{ migrated: number }, DbError> {
return Result.ok(null)
.andThenAsync(async () => {
// Fetch from legacy database
return Result.fromPromise(() => legacyDb.fetchAllUsers())
})
.andThenAsync(async (legacyUsers) => {
// Transform
const transformed = legacyUsers.map((u) => ({
id: u.legacyId,
name: u.fullName,
email: u.emailAddress
}))
return Result.ok(transformed)
})
.andThenAsync(async (users) => {
// Insert to new database
const insertResult = await bulkInsertUsers(users)
return insertResult.map((count) => ({ migrated: count }))
})
}
// Usage
const result = await migrateUsers()
result.match({
ok: (report) => console.log(`Migration complete: ${report.migrated}`),
err: (error) => console.error('Migration failed:', error.detail)
})