Drizzle와 OP-SQLite 시작하기

This guide assumes familiarity with:

1단계 - Expo 템플릿으로 프로젝트 설정하기

npm
yarn
pnpm
bun
npx create expo-app --template blank-typescript

이 템플릿에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

기본 파일 구조

템플릿을 설치하고 db 폴더를 추가한 후, 다음과 같은 내용을 확인할 수 있습니다. db/schema.ts 파일에는 Drizzle 테이블 정의가 포함되어 있습니다. drizzle 폴더에는 SQL 마이그레이션 파일과 스냅샷이 들어 있습니다.

📦 <project root>
 ├ 📂 assets
 ├ 📂 drizzle
 ├ 📂 db
 │  └ 📜 schema.ts
 ├ 📜 .gitignore
 ├ 📜 .npmrc
 ├ 📜 app.json
 ├ 📜 App.tsx
 ├ 📜 babel.config.ts
 ├ 📜 drizzle.config.ts
 ├ 📜 package.json
 └ 📜 tsconfig.json

2단계 - 필요한 패키지 설치하기

npm
yarn
pnpm
bun
npm i drizzle-orm @op-engineering/op-sqlite
npm i -D drizzle-kit

3단계 - Drizzle ORM을 데이터베이스에 연결하기

루트 디렉토리에 App.tsx 파일을 생성하고 연결을 초기화합니다:

import { open } from '@op-engineering/op-sqlite';
import { drizzle } from 'drizzle-orm/expo-sqlite';

const opsqliteDb = open({
  name: 'db',
});

const db = drizzle(opsqliteDb);

4단계 - 테이블 생성하기

db 디렉토리에 schema.ts 파일을 생성하고 테이블을 선언합니다:

import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const usersTable = sqliteTable("users_table", {
  id: int().primaryKey({ autoIncrement: true }),  // 자동 증가하는 기본 키
  name: text().notNull(),  // 이름 (필수)
  age: int().notNull(),    // 나이 (필수)
  email: text().notNull().unique(),  // 이메일 (필수, 고유값)
});

5단계 - Drizzle 설정 파일 설정하기

Drizzle 설정 파일Drizzle Kit에서 사용하는 구성 파일로, 데이터베이스 연결 정보, 마이그레이션 폴더, 스키마 파일 등에 대한 모든 정보를 담고 있습니다.

프로젝트 루트에 drizzle.config.ts 파일을 생성하고 다음 내용을 추가하세요:

import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  dialect: 'sqlite',  // 사용할 데이터베이스 종류 (SQLite)
  driver: 'expo',     // 드라이버 설정 (Expo)
  schema: './db/schema.ts',  // 스키마 파일 경로
  out: './drizzle',          // 마이그레이션 파일이 생성될 경로
});

이 설정 파일은 Drizzle Kit이 데이터베이스와 상호작용하는 데 필요한 기본 정보를 제공합니다. dialect는 사용할 데이터베이스 종류를 지정하고, schema는 스키마 파일의 위치를 가리킵니다. out은 마이그레이션 파일이 생성될 경로를 설정합니다.

6단계 - metro 설정하기

루트 폴더에 metro.config.js 파일을 생성하고 다음 코드를 추가합니다:

const { getDefaultConfig } = require('expo/metro-config');
/** @type {import('expo/metro-config').MetroConfig} */
const config = getDefaultConfig(__dirname);
config.resolver.sourceExts.push('sql');
module.exports = config;

이 코드는 Expo 프로젝트에서 Metro 번들러의 기본 설정을 가져와서 SQL 파일을 처리할 수 있도록 확장합니다. sourceExts 배열에 ‘sql’을 추가함으로써, 프로젝트에서 SQL 파일을 임포트할 수 있게 됩니다.

7단계 - babel 설정 업데이트

metro.config.js
module.exports = function(api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [["inline-import", { "extensions": [".sql"] }]] // <-- 이 부분 추가
  };
};

8단계 - 데이터베이스에 변경사항 적용하기

Expo를 사용할 때는 drizzle-kit generate 커맨드를 통해 마이그레이션을 생성한 후, drizzle-ormmigrate() 함수를 사용해 런타임에 적용해야 합니다.

마이그레이션 생성:

npx drizzle-kit generate

9단계 - 마이그레이션 적용 및 데이터베이스 쿼리:

App.tsx 파일에 마이그레이션과 사용자 생성, 읽기, 업데이트, 삭제를 위한 쿼리를 추가해 보겠습니다.

import { Text, View } from 'react-native';
import { open } from '@op-engineering/op-sqlite';
import { useEffect, useState } from 'react';
import { drizzle } from 'drizzle-orm/op-sqlite';
import { usersTable } from './db/schema';
import { useMigrations } from 'drizzle-orm/op-sqlite/migrator';
import migrations from './drizzle/migrations';

const opsqliteDb = open({
  name: 'db',
});

const db = drizzle(opsqliteDb);

export default function App() {
  const { success, error } = useMigrations(db, migrations);
  const [items, setItems] = useState(null);

  useEffect(() => {
    if (!success) return;

    (async () => {
      await db.delete(usersTable);

      await db.insert(usersTable).values([
        {
          name: 'John',
          age: 30,
          email: 'john@example.com',
        },
      ]);

      const users = await db.select().from(usersTable);
      setItems(users);
    })();
  }, [success]);

  if (error) {
    return (
      <View>
        <Text>마이그레이션 오류: {error.message}</Text>
      </View>
    );
  }

  if (!success) {
    return (
      <View>
        <Text>마이그레이션 진행 중...</Text>
      </View>
    );
  }

  if (items === null || items.length === 0) {
    return (
      <View>
        <Text>데이터가 없습니다.</Text>
      </View>
    );
  }

  return (
    <View
      style={{
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        width: '100%',
        height: '100%',
        justifyContent: 'center',
      }}
    >
      {items.map((item) => (
        <Text key={item.email}>{item.email}</Text>
      ))}
    </View>
  );
}

이 코드는 SQLite 데이터베이스를 열고, 마이그레이션을 적용한 후 사용자 데이터를 생성, 읽기, 업데이트, 삭제하는 기본적인 작업을 수행합니다. 마이그레이션이 성공적으로 완료되면, 사용자 데이터를 화면에 표시합니다.

10단계 - Expo 앱 사전 빌드 및 실행

npm
yarn
pnpm
bun
npx expo run:ios