본문 바로가기
Flutter/Package

플러터에서 Moor 패키지 사용 방법(sql 쿼리)

by Maccrey Coding 2024. 11. 9.
728x90
반응형

 

Moor는 Flutter에서 로컬 데이터베이스 작업을 더욱 간편하고 효율적으로 처리할 수 있게 도와주는 Flutter용 SQLite 라이브러리입니다.

SQLite를 기반으로 하지만 SQL 쿼리를 직접 작성할 필요 없이 Dart 객체를 사용해 데이터를 다룰 수 있습니다.

Moor는 객체 지향적인 방식으로 SQLite를 제어할 수 있도록 설계되었으며, 특히 Flutter와의 통합에 매우 유용합니다.

Moor의 주요 특징 및 기능

1. 데이터 모델 정의와 관리

Moor에서는 데이터베이스 테이블을 Dart 클래스로 정의하고, 이를 기반으로 데이터를 관리합니다. 일반적으로 @Table 어노테이션을 사용하여 테이블을 정의합니다. 이를 통해 SQL 없이 객체 지향적으로 데이터를 처리할 수 있습니다.

테이블 정의

테이블을 정의할 때 각 필드에 대해 TextColumn, IntColumn, BoolColumn 등의 컬럼을 지정합니다. 예를 들어, User라는 테이블을 다음과 같이 정의할 수 있습니다.

import 'package:moor/moor.dart';

@DataClassName('User')  // 데이터 모델 클래스 이름
class Users extends Table {
  IntColumn get id => integer().autoIncrement()();  // 기본 키, 자동 증가
  TextColumn get name => text()();  // 사용자 이름
  IntColumn get age => integer()();  // 사용자 나이
  TextColumn get email => text()();  // 이메일 주소
}

위와 같이 Users 테이블을 정의하며, name, age, email 등을 필드로 설정합니다. id는 자동 증가하도록 설정합니다.

2. 데이터베이스 접근: DAO (Data Access Object)

Moor에서는 DAO(Data Access Object)라는 클래스를 사용하여 데이터베이스와 상호작용합니다. DAO는 데이터를 삽입, 삭제, 업데이트, 조회하는 메서드를 제공합니다. @UseDao 어노테이션을 사용하여 DAO 클래스를 정의하고, 데이터베이스 작업을 쉽게 처리할 수 있습니다.

DAO 클래스 예시

@UseDao(tables: [Users])
class UserDao extends DatabaseAccessor<AppDatabase> with _$UserDaoMixin {
  final AppDatabase db;

  UserDao(this.db) : super(db);

  Future<List<User>> getAllUsers() => select(users).get();  // 모든 사용자 조회
  Stream<List<User>> watchAllUsers() => select(users).watch();  // 사용자 목록 실시간 스트림
  Future insertUser(User user) => into(users).insert(user);  // 사용자 삽입
  Future updateUser(User user) => update(users).replace(user);  // 사용자 업데이트
  Future deleteUser(int id) => (delete(users)..where((u) => u.id.equals(id))).go();  // 사용자 삭제
}

위 코드에서 getAllUsers, insertUser, deleteUser 등의 메서드를 정의하여 Users 테이블과 상호작용합니다.

3. 쿼리와 데이터 접근

Moor는 직접 SQL 쿼리를 작성하지 않고도 Dart 코드를 통해 데이터를 조회, 삽입, 수정, 삭제할 수 있도록 해줍니다.

Dart 코드로 직접 테이블과 상호작용하며 데이터베이스 작업을 수행할 수 있습니다.

데이터 삽입

final user = UsersCompanion(
  name: Value('John Doe'),
  age: Value(30),
  email: Value('john.doe@example.com'),
);

await userDao.insertUser(user);

데이터 조회

// 비동기적으로 모든 사용자 조회
List<User> users = await userDao.getAllUsers();

// 스트림을 사용하여 사용자 목록을 실시간으로 업데이트
Stream<List<User>> userStream = userDao.watchAllUsers();

데이터 업데이트

final user = User(id: 1, name: 'John Updated', age: 31, email: 'updated@example.com');
await userDao.updateUser(user);

데이터 삭제

await userDao.deleteUser(1);  // id가 1인 사용자 삭제

4. 복잡한 쿼리 지원

Moor는 기본적인 CRUD 작업 외에도 복잡한 쿼리를 처리할 수 있습니다.

예를 들어, 조건에 맞는 데이터를 필터링하거나 정렬하는 쿼리를 쉽게 작성할 수 있습니다.

조건에 맞는 데이터 필터링

Future<List<User>> getUsersByAge(int minAge) {
  return (select(users)..where((u) => u.age.isBiggerThanValue(minAge))).get();
}

정렬된 데이터 조회

Future<List<User>> getUsersSortedByName() {
  return (select(users)..orderBy([(u) => OrderingTerm(expression: u.name)]))
      .get();
}

조인 쿼리

Moor는 테이블 간의 조인도 지원합니다. 예를 들어, 두 테이블을 조인하여 데이터를 조회하는 쿼리를 작성할 수 있습니다.

Future<List<UserWithPost>> getUsersWithPosts() {
  final query = select(users).join([
    leftOuterJoin(posts, posts.userId.equalsExp(users.id)),
  ]);
  return query.map((row) {
    final user = row.readTable(users);
    final post = row.readTable(posts);
    return UserWithPost(user, post);
  }).get();
}

5. 트랜잭션

Moor에서는 여러 데이터베이스 작업을 트랜잭션으로 묶어서 실행할 수 있습니다.

트랜잭션을 사용하면 여러 작업을 원자적으로 처리할 수 있습니다.

await db.transaction(() async {
  await userDao.insertUser(User(id: 1, name: 'Alice', age: 25, email: 'alice@example.com'));
  await userDao.insertUser(User(id: 2, name: 'Bob', age: 30, email: 'bob@example.com'));
});

위 코드는 insertUser 두 개의 작업을 하나의 트랜잭션으로 묶어서 실행합니다.

6. JSON 데이터 저장 (List, Map 등)

Moor는 Dart의 복합 데이터 형식인 List, Map, DateTime 등을 손쉽게 저장하고 관리할 수 있습니다. 복합 데이터를 저장할 때는 TextColumn을 사용하고 JSON 형식으로 직렬화하여 저장합니다.

List<String> 저장하기

TextColumn get tags => text().nullable()();  // JSON 문자열로 저장

데이터 삽입 시 List<String>을 JSON 문자열로 직렬화하여 저장합니다.

final user = UsersCompanion(
  name: Value('John Doe'),
  age: Value(30),
  tags: Value('["developer", "flutter"]'), // List<String> -> JSON String
);
await userDao.insertUser(user);

Map 저장하기

TextColumn get profile => text().nullable()();  // JSON 문자열로 저장

Map도 JSON 문자열로 직렬화하여 저장합니다.

final user = UsersCompanion(
  name: Value('Jane Doe'),
  age: Value(28),
  profile: Value('{"email": "jane.doe@example.com", "address": "Seoul"}'),  // Map -> JSON String
);
await userDao.insertUser(user);

7. 스트림과 리액티브 프로그래밍

Moor는 스트림을 지원하여 데이터베이스의 변화에 반응하는 리액티브한 앱을 만들 수 있습니다. 예를 들어, 사용자 목록을 스트림으로 받아서 실시간으로 UI를 갱신할 수 있습니다.

Stream<List<User>> watchAllUsers() => select(users).watch();

위와 같이 watch 메서드를 사용하여 테이블의 변화를 실시간으로 감지하고 UI에 반영할 수 있습니다.

8. 데이터베이스 마이그레이션

Moor에서는 데이터베이스의 버전 관리마이그레이션을 지원합니다.

앱의 버전이 업그레이드되면서 데이터베이스 구조를 변경할 때 schemaVersion을 관리하여 데이터베이스를 안전하게 마이그레이션할 수 있습니다.

@override
int get schemaVersion => 2;  // 데이터베이스 버전

Moor는 버전 업그레이드 시 자동으로 마이그레이션을 처리하거나, 필요에 따라 커스텀 마이그레이션을 구현할 수 있습니다.

 

구독!! 공감과 댓글,

광고 클릭은 저에게 큰 힘이 됩니다.

 

Starting Google Play App Distribution! "Tester Share" for Recruiting 20 Testers for a Closed Test.

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

728x90
반응형