# @funztic/db: TypeScript 기반 파일 데이터베이스

[![npm version](https://badge.fury.io/js/@funztic%2Fdb.svg)](https://badge.fury.io/js/@funztic%2Fdb) [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)

`@funztic/db`는 TypeScript 기반의 파일 데이터베이스 라이브러리입니다. JSON 파일을 사용하여 데이터를 저장하고 관리하며, Zod 스키마 검증을 지원합니다.

## 📦 설치

```bash
npm i @funztic/db
# 또는
yarn add @funztic/db
```

## 🚀 시작하기

### 기본 사용법

```typescript
import { Collection, Database } from '@funztic/db';

// 단일 컬렉션 사용
const collection = new Collection<User>('users', {
  dir: './data',
  autoSave: true,
  saveDelay: 500
});

// 여러 컬렉션 관리
const db = new Database('./data', {
  autoSave: true,
  saveDelay: 500
});

const users = db.collection<User>('users');
const posts = db.collection<Post>('posts');
```

### Zod 스키마 검증 사용법

```typescript
import { Collection, Database } from '@funztic/db/zod';
import { z } from 'zod';

// 스키마 정의
const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  age: z.number()
});

// Zod 스키마 검증이 포함된 컬렉션 사용
const collection = new Collection<User>('users', userSchema, {
  dir: './data',
  autoSave: true,
  saveDelay: 500
});

// 또는 Database를 통해 사용
const db = new Database('./data', {
  autoSave: true,
  saveDelay: 500
});

const users = db.collection<User>('users', userSchema);
```

## 📚 API 문서

### Collection 클래스

#### 생성자
```typescript
new Collection<T extends { id: string }>(collectionName: string, options: {
  dir: string;
  autoSave?: boolean;
  saveDelay?: number;
})
```

#### 메서드

##### create
새로운 항목을 생성합니다.

```typescript
create(item: T): Promise<T>
```

##### get
ID로 항목을 조회합니다.

```typescript
get(id: string): Promise<T | undefined>
```

##### getAll
모든 항목을 조회합니다.

```typescript
getAll(): Promise<T[]>
```

##### find
조건에 맞는 항목을 검색합니다.

```typescript
find(filterFn: (item: T) => boolean): Promise<T[]>
```

##### update
항목을 업데이트합니다.

```typescript
update(id: string, updates: Partial<Omit<T, 'id'>>): Promise<T | undefined>
```

##### delete
항목을 삭제합니다.

```typescript
delete(id: string): Promise<boolean>
```

##### clear
모든 항목을 삭제합니다.

```typescript
clear(): Promise<void>
```

##### query
사용자 정의 쿼리를 실행합니다.

```typescript
query<R>(queryFn: (data: Record<string, T>) => R): Promise<R>
```

##### close
컬렉션을 종료합니다.

```typescript
close(): Promise<void>
```

### Repository 클래스

#### 생성자
```typescript
new Repository<T extends { id: string }>(collection: Collection<T>, options: RepositoryOptions<T>)
```

#### 메서드

##### save
엔티티를 저장합니다.

```typescript
save(entity: Partial<T> & { id?: string }): Promise<T>
```

##### findById
ID로 엔티티를 조회합니다.

```typescript
findById(id: string): Promise<T | null>
```

##### findAll
모든 엔티티를 조회합니다.

```typescript
findAll(): Promise<T[]>
```

##### findBy
조건에 맞는 엔티티를 검색합니다.

```typescript
findBy(criteria: Partial<T>): Promise<T[]>
```

##### findOne
조건에 맞는 첫 번째 엔티티를 조회합니다.

```typescript
findOne(criteria: Partial<T>): Promise<T | null>
```

##### update
엔티티를 업데이트합니다.

```typescript
update(id: string, data: Partial<Omit<T, 'id'>>): Promise<T | null>
```

##### delete
엔티티를 삭제합니다.

```typescript
delete(id: string): Promise<boolean>
```

##### count
엔티티의 총 개수를 반환합니다.

```typescript
count(): Promise<number>
```

##### exists
엔티티가 존재하는지 확인합니다.

```typescript
exists(id: string): Promise<boolean>
```

##### clear
모든 엔티티를 삭제합니다.

```typescript
clear(): Promise<void>
```

##### query
사용자 정의 쿼리를 실행합니다.

```typescript
query<R>(queryFn: (entities: T[]) => R): Promise<R>
```

##### paginate
페이지네이션을 지원합니다.

```typescript
paginate(page?: number, limit?: number): Promise<{
  data: T[];
  total: number;
  page: number;
  limit: number;
  totalPages: number;
}>
```

##### createPaginator
페이지네이터를 생성합니다.

```typescript
createPaginator<K extends keyof T>(
  limit?: number,
  sortBy?: K,
  order?: 'asc' | 'desc'
): AsyncGenerator<{
  data: T[];
  total: number;
  page: number;
  isLast: boolean;
}>
```

##### findAllSorted
정렬된 엔티티를 조회합니다.

```typescript
findAllSorted<K extends keyof T>(
  sortBy: K,
  order?: 'asc' | 'desc'
): Promise<T[]>
```

##### getRawCollection
내부 Collection 인스턴스를 반환합니다.

```typescript
getRawCollection(): Collection<T>
```

### Database 클래스

#### 생성자
```typescript
new Database(dbDir: string, options?: CollectionOptions)
```

#### 메서드

##### collection
컬렉션을 생성하거나 가져옵니다.

```typescript
collection<T extends { id: string }>(name: string): Collection<T>
```

##### syncAll
모든 컬렉션을 동기화합니다.

```typescript
syncAll(): Promise<void>
```

##### close
모든 컬렉션을 종료합니다.

```typescript
close(): Promise<void>
```

## 📝 예제

### 기본 사용법

```typescript
interface User {
  id: string;
  name: string;
  age: number;
}

const collection = new Collection<User>('users', {
  dir: './data',
  autoSave: true
});

// 사용자 생성
const user = await collection.create({
  id: '1',
  name: 'John Doe',
  age: 30
});

// 사용자 조회
const foundUser = await collection.get('1');

// 모든 사용자 조회
const allUsers = await collection.getAll();

// 조건 검색
const youngUsers = await collection.find(user => user.age < 30);
```

### Repository 사용법

```typescript
const repository = createRepository<User>(collection, {
  idGenerator: () => Math.random().toString(36).substr(2, 9),
  beforeCreate: async (user) => {
    user.createdAt = new Date();
    return user;
  },
  beforeSave: async (user) => {
    user.updatedAt = new Date();
    return user;
  }
});

// 사용자 생성
const user = await repository.save({
  name: 'John Doe',
  age: 30
});

// 페이지네이션
const { data, total, page, totalPages } = await repository.paginate(1, 10);

// 정렬된 조회
const sortedUsers = await repository.findAllSorted('age', 'desc');
```

### Zod 스키마 검증 사용법

```typescript
import { Collection, Database } from '@funztic/db/zod';
import { z } from 'zod';

// 스키마 정의
const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
  createdAt: z.date(),
  updatedAt: z.date()
});

type User = z.infer<typeof userSchema>;

// Zod 스키마 검증이 포함된 컬렉션 사용
const collection = new Collection<User>('users', userSchema, {
  dir: './data',
  autoSave: true
});

// 유효한 데이터 생성
const user = await collection.create({
  id: '1',
  name: 'John Doe',
  age: 30,
  email: 'john@example.com',
  createdAt: new Date(),
  updatedAt: new Date()
});

// 유효하지 않은 데이터 생성 시도 (에러 발생)
try {
  await collection.create({
    id: '2',
    name: 'Jane Doe',
    age: 25,
    email: 'invalid-email',
    createdAt: new Date(),
    updatedAt: new Date()
  });
} catch (error) {
  console.error('Validation error:', error);
}
```

## 📄 라이센스

ISC