database-integration

Implement reliable and efficient database operations using the ORM, including queries, transactions, and migrations.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "database-integration" with this command: npx skills add vihang-hub/integrated-sdlc-framework/vihang-hub-integrated-sdlc-framework-database-integration

Database Integration

Purpose

Implement reliable and efficient database operations using the ORM, including queries, transactions, and migrations.

When to Use

  • Data model implementation

  • Query optimization

  • Transaction handling

  • Migration writing

Prerequisites

  • Database schema defined

  • ORM configured (Prisma)

  • Connection pooling set up

Process

Step 1: Define Schema

Prisma schema:

  • Models
  • Relations
  • Indexes
  • Constraints

Step 2: Generate Client

Commands:

  • prisma generate
  • prisma migrate dev

Step 3: Implement Repository

Repository pattern:

  • CRUD operations
  • Complex queries
  • Transactions

Step 4: Optimize Queries

Optimization:

  • Select only needed fields
  • Use indexes
  • Avoid N+1 queries
  • Use transactions

Step 5: Handle Errors

Error handling:

  • Constraint violations
  • Connection errors
  • Deadlocks
  • Timeouts

Inputs

Input Type Required Description

database_schema SQL Yes Schema design

queries Markdown Yes Required queries

Outputs

Output Type Description

schema.prisma Prisma Schema definition

migrations/ SQL Migration files

repositories/ TypeScript Data access

StudyAbroad-Specific Considerations

  • User data privacy

  • Application audit trail

  • Soft deletes for GDPR

  • Efficient search queries

Integration Points

  • Architecture Agent: Schema design

  • Security Agent: Data protection

  • DevOps Agent: Migrations

Examples

// prisma/schema.prisma generator client { provider = "prisma-client-js" }

datasource db { provider = "postgresql" url = env("DATABASE_URL") }

model User { id String @id @default(uuid()) email String @unique passwordHash String? firstName String lastName String dateOfBirth DateTime? nationality String? gdprConsent Boolean @default(false) gdprConsentAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt deletedAt DateTime? // Soft delete for GDPR

applications Application[] documents Document[] oauthAccounts OAuthAccount[]

@@index([email]) @@index([deletedAt]) }

model Application { id String @id @default(uuid()) userId String programId String status String @default("draft") progress Int @default(0) submittedAt DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt

user User @relation(fields: [userId], references: [id]) program Program @relation(fields: [programId], references: [id]) documents Document[] statusHistory ApplicationStatusHistory[]

@@unique([userId, programId]) @@index([userId]) @@index([status]) }

model ApplicationStatusHistory { id String @id @default(uuid()) applicationId String oldStatus String? newStatus String changedBy String? notes String? createdAt DateTime @default(now())

application Application @relation(fields: [applicationId], references: [id])

@@index([applicationId]) }

// src/prisma/prisma.service.ts import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common' import { PrismaClient, Prisma } from '@prisma/client'

@Injectable() export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { constructor() { super({ log: [ { emit: 'event', level: 'query' }, { emit: 'stdout', level: 'error' }, { emit: 'stdout', level: 'warn' } ] }) }

async onModuleInit() { await this.$connect()

// Soft delete middleware
this.$use(async (params, next) => {
  if (params.model === 'User') {
    if (params.action === 'delete') {
      params.action = 'update'
      params.args['data'] = { deletedAt: new Date() }
    }
    if (params.action === 'deleteMany') {
      params.action = 'updateMany'
      if (params.args.data !== undefined) {
        params.args.data['deletedAt'] = new Date()
      } else {
        params.args['data'] = { deletedAt: new Date() }
      }
    }
    // Filter out soft-deleted by default
    if (params.action === 'findUnique' || params.action === 'findFirst') {
      params.action = 'findFirst'
      params.args.where['deletedAt'] = null
    }
    if (params.action === 'findMany') {
      if (params.args.where) {
        if (params.args.where.deletedAt === undefined) {
          params.args.where['deletedAt'] = null
        }
      } else {
        params.args['where'] = { deletedAt: null }
      }
    }
  }
  return next(params)
})

}

async onModuleDestroy() { await this.$disconnect() }

// Transaction helper async executeInTransaction<T>( fn: (prisma: Prisma.TransactionClient) => Promise<T> ): Promise<T> { return this.$transaction(fn, { maxWait: 5000, timeout: 10000, isolationLevel: Prisma.TransactionIsolationLevel.Serializable }) } }

// src/application/application.repository.ts @Injectable() export class ApplicationRepository { constructor(private readonly prisma: PrismaService) {}

async findByUserWithPrograms( userId: string, options: { status?: string; page: number; limit: number } ) { const { status, page, limit } = options const where: Prisma.ApplicationWhereInput = { userId }

if (status) {
  where.status = status
}

const [applications, total] = await Promise.all([
  this.prisma.application.findMany({
    where,
    include: {
      program: {
        include: {
          university: true
        }
      },
      documents: {
        select: { id: true, documentType: true, fileName: true }
      }
    },
    skip: (page - 1) * limit,
    take: limit,
    orderBy: { createdAt: 'desc' }
  }),
  this.prisma.application.count({ where })
])

return { applications, total }

}

async submitWithHistory( id: string, userId: string ): Promise<Application> { return this.prisma.executeInTransaction(async (tx) => { // Get current application const application = await tx.application.findFirst({ where: { id, userId } })

  if (!application) {
    throw new NotFoundException()
  }

  // Update status
  const updated = await tx.application.update({
    where: { id },
    data: {
      status: 'submitted',
      submittedAt: new Date()
    }
  })

  // Create history record
  await tx.applicationStatusHistory.create({
    data: {
      applicationId: id,
      oldStatus: application.status,
      newStatus: 'submitted',
      changedBy: userId
    }
  })

  return updated
})

} }

Validation

  • Schema matches design

  • Migrations run cleanly

  • Queries are efficient

  • Transactions used correctly

  • Errors handled properly

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

ambiguity-detection

No summary provided by upstream source.

Repository SourceNeeds Review
General

test-strategy-design

No summary provided by upstream source.

Repository SourceNeeds Review
General

environment-configuration

No summary provided by upstream source.

Repository SourceNeeds Review
General

authentication-testing

No summary provided by upstream source.

Repository SourceNeeds Review