Study Record

[Flutter] drift 에서 테이블 데이터 가져오기 (insert, select, delete, update etc) 본문

Flutter/라이브러리

[Flutter] drift 에서 테이블 데이터 가져오기 (insert, select, delete, update etc)

초코초코초코 2023. 3. 25. 19:24
728x90

🎁 drift 테이블과 데이터

test_database.dart

import 'package:drift/drift.dart';
import 'dart:io';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
part 'test_database.g.dart';

class Students extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text()();
  IntColumn get grade => integer()();
  TextColumn get clubName => text()();
}

@DataClassName('ClubRoom')
class Clubs extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get clubName => text()();
  IntColumn get studentTotal => integer()();
  TextColumn get description => text()();
}

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  TestDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;
}

만약 위의 코드와 같이 Todos 테이블과 Clubs 테이블을 설정했다면 "flutter pub run build_runner build" 을 실행한 뒤 생기는 test_database.g.dart 파일에는 각 테이블마다 테이블 클래스와 데이터 클래스, Companion 이 붙은 클래스가 생성된다.

 

 

😶 테이블 클래스

 

ex) Clubs 테이블

 

 

 

😶 데이터 클래스

보통 데이터 클래스는 테이블 이름 뒤의 's' 를 제거한 이름으로 생기는데 @DataClassName 어노테이션에 의해 Clubs 테이블의 데이터 클래스는 Club 가 아닌 ClubRoom 이 된다. Students 테이블은 Student 데이터 클래스가 생긴다.

 

ex) Clubs 테이블

 

 

 

😶 Companion 클래스

칼럼 변수들이 전부 Value() 에 감싸여 있다.

 

ex) Clubs 테이블

 

 

 

😶 table

test_database.g.dart 파일에는 데이터베이스 클래스(_$TestDatabase)가 있는데 이곳에 테이블들이 정의되어 있다. (students, clubs) 따라서 test_database.dart 파일에 있는 TestDatabase 클래스에서 테이블에 대한 정보는 students, clubs 로 불러오면 된다. 

 

 

 

table, 데이터 클래스 Companion 클래스 등이 실제로 어떻게 사용되는지는 sql 구문을 통해 보면 다음과 같다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  TestDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;

  Future<int> addStudent(StudentsCompanion entry) {
    return into(students).insert(entry);
  }

  Future<List<Student>> getStudent() {
    return select(students).get();
  }
}

_TestDatabase 를 상속받는 TestDatabase 는 테이블 변수들을 가볍게 students, clubs 로 참고하면 된다.

addStudent() 는 students 테이블에 데이터를 삽입하는 기능을 하는데 into() 에 테이블 정보를 students, 데이터 정보를 StudentsCompanion 으로 삽입한다. 

getStudent() 는 students 테이블에 있는 데이터 전부를 가져오는데 select() 에 테이블 정보를 students 로 get() 해서 가져온다. 가져온 데이터의 타입은 students 의 데이터 클래스로 가져올 수 있다.

 

 

 

✍ SQL  queries 사용하기

 

😶 데이터 삽입 (insert)

int() 함수에 테이블 정보를 넣고 insert() 함수에 Companion 타입의 데이터를 넣으면 된다.

await TestDatabase().addStudent(const StudentsCompanion(
  name: Value("choho"),
  grade: Value(2),
  clubName: Value("Soccer"),
));

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // returns the generated id
  Future<int> addStudent(StudentsCompanion entry) {
    return into(students).insert(entry);
  }
 
  // 여러개의 데이터 한번에 넣기
  Future<void> insertMultipleEntries() async {
    await batch((batch) {
      batch.insertAll(clubs, [
        ClubsCompanion.insert(
          clubName: 'hahaha',
          studentTotal: 30,
          description: 'This is a hahaha',
        ),
        ClubsCompanion.insert(
          clubName: 'lalala',
          studentTotal: 20,
          description: 'This is a lalala',
        ),
      ]);
    });
  }
}

 

 

😶 데이터 가져오기 (select)

테이블에 있는 데이터 전부를 가져오려면 select() 함수에 원하는 테이블 정보를 넣고 get() 으로 가져온다. Stream 형식으로 자동 업데이트받고 싶으면 watch() 를 사용하면 된다. get() 함수는 단순히 select(students) 를 한 결과인 Selectable<T> 타입을 Future<List<T>> 타입으로 바꿔준다. watch() 함수도 Selectable<T> 타입을 Stream<List<T>> 타입으로 바꿔준다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // select * from students;
  Future<List<Student>> getStudent() {
    return select(students).get();
  }
  
  // 자동 업데이트
  Stream<List<Student>> watchStudent() {
    return select(students).watch();
  }
}

 

 

😶 (where) 칼럼 비교하기

where() 함수를 사용하여 조건에 따라 데이터를 거를 수 있는데 where 함수의 리턴값은 void 이므로 ".." 을 사용하여 where() 함수를 사용한 select(clubs) 를 리턴하여 get() 또는 watch() 함수를 사용하여 데이터를 가져온다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // select * from students where studentTotal <= 10;
  Future<List<ClubRoom>> getClubsFromTotal(int studentTotal) {
    return (select(clubs)
        ..where(
          (tbl) => tbl.studentTotal.isSmallerOrEqualValue(10),
        ))
      .get();
  }
  
  // 자동 업데이트
  // select * from students where studentTotal > 10;
  Stream<List<ClubRoom>> watchClubsFromTotal(int studentTotal) {
    return select(clubs)
      ..where(
        (tbl) => tbl.studentTotal.isBiggerThanValue(10),
      ))
      .watch();
  }
}

 

 

[Dart] ..

✍ .. "." 을 사용해서 함수를 실행하고 return 값으로 실행한 함수의 return 값이 반환된다. 하지만 ".." 은 리턴값으로 함수를 실행한 대상이 리턴된다. int a = 3; String aStr = a.toString(); final aInt = a..toStri

laustudy.tistory.com

 

 

비교 조건으로 사용할 수 있는 함수

...
..where(
  (tbl) => tbl.studentTotal.isBiggerThanValue(10),
)

tbl.studentTotal.isBiggerThanValue(10)		// > 10
tbl.studentTotal.isBiggerOrEqualValue(10)	// >= 10
tbl.studentTotal.isSmallerThanValue(10)		// < 10
tbl.studentTotal.isSmallerOrEqualValue(10)	// <= 10
tbl.studentTotal.equals(20)			// = 10

 

 

😶 (where) 칼럼 여러개 비교하기

&, | 키워드를 사용하여 여러개의 조건을 비교할 수 있다.

() & () : "그리고"의 의미로 양쪽의 조건이 모두 참일때만 참이다.

() | () : "또는"의 의미로 한쪽이 참이면 참이다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // select * from clubs where studentTotal > 5 and studentTotal <= 10;
  Future<List<ClubRoom>> getClubsFromTotal(int studentTotal) {
    return (select(clubs)
        ..where(
          (tbl) => tbl.studentTotal.isSmallerOrEqualValue(10) &
                   tbl.studentTotal.isBiggetThanValue(5),
        ))
      .get();
  }
  
  // 자동 업데이트
  Stream<List<ClubRoom>> watchClubsFromTotal(int studentTotal) {
    return select(clubs)
      ..where(
        (tbl) => tbl.studentTotal.isSmallerOrEqualValue(10) &
                 tbl.studentTotal.isBiggetThanValue(5),
      ))
      .watch();
  }
}

 

 

😶 (where) null, not null 인 데이터만 가져오기

isNull(), isNotNull() 함수를 사용하여 null 혹은 null 이 아닌 칼럼의 데이터를 가져올 수 있다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future<List<ClubRoom>> getClubsNullTotal() {
    return (select(clubs)
          ..where(
            (tbl) => tbl.studentTotal.isNull(),
          ))
        .get();
  }

  // 자동 업데이트
  Stream<List<ClubRoom>> watchClubsNotNullTotal() {
    return (select(clubs)
      ..where(
            (tbl) => tbl.studentTotal.isNotNull(),
      ))
        .watch();
  }
}

 

 

😶 (where) IN or Not IN

특정 데이터 집단에 속하는 데이터만 가져올 수 있다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // select * from clubs where studentTotal IN (10, 40, 30);
  Future<List<ClubRoom>> getClubsNullTotal() {
    return (select(clubs)
          ..where(
            (tbl) => tbl.studentTotal.isIn([10, 40, 30]),
          ))
        .get();
  }

  // 자동 업데이트
  // select * from clubs where studentTotal NOT IN (10, 40, 30);
  Stream<List<ClubRoom>> watchClubsNotNullTotal() {
    return (select(clubs)
      ..where(
            (tbl) => tbl.studentTotal.isNotIn([20, 30]),
      ))
        .watch();
  }
}

 

 

😶 (where) 날짜 타입 비교하기

날짜 데이터(dateTime)일 경우, year, month, day, hour, minute, second 별로 각각을 쉽게 비교할 수 있다.

select(users)..where((u) => u.birthDate.year.isLessThan(1950));

 

 

😶 (where) 문자열 찾기(like)

TextCloumn 타입을 가진 칼럼 중 like 를 사용하여 일치하는 문자열이 있는 데이터만 가져올 수 있다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  // name 칼럼에 "kim" 문자열이 포함된 데이터 가져오기
  Future<List<Student>> getStudentPattern(String pattern) {
    return (select(students)..where((tbl) => tbl.name.like("%kim%")))
        .get();
  }

  Stream<List<Student>> watchStudentPattern(String pattern) {
    return (select(students)..where((tbl) => tbl.name.like("%kim%")))
        .watch();
  }
}

 

 

😶 Single Value 

List 데이터가 아닌 단일 데이터를 가져오고 싶다면 getSingle() 혹은 watchSingle() 로 가져오면 된다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future<Student> getStudentSingle() {
    return select(students).getSingle();
  }

  Stream<Student> watchStudentSingle() {
    return select(students).watchSingle();
  }
}

 

 

😶 오름차순 / 내림차순

orderby() 함수로 칼럼에 따라 오름차순, 내림차순을 설정할 수 있다. OrderingTerm.desc() 는 내림차순이고 OrderingTerm.asc() 는 오름차순이다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future<List<Student>> getStudent() {
    return (select(students)..orderBy([(t) => OrderingTerm.desc(t.grade)]))
        .get();
  }

  Stream<List<Student>> watchStudent() {
    return (select(students)..orderBy([(t) => OrderingTerm.asc(t.grade)]))
        .watch();
  }
}

 

 

😶 (join) 테이블 조인

join 은 join() 함수를 사용하여 구현할 수 있다. 다음 예시는 stduents 과 clubs 를 조인한 예시이다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future<List<Student>> getStudentsClubsFromStudentTotal(int total) {
    final query = select(students)
        .join([innerJoin(clubs, clubs.clubName.equalsExp(students.clubName))]);

    query.where(students.name.length.isSmallerThanValue(3));

    return query.map((row) => row.readTable(students)).get();
  }

  Stream<List<Student>> watchStudentsClubsFromStudentTotal(int total) {
    final query = select(students)
        .join([innerJoin(clubs, clubs.clubName.equalsExp(students.clubName))]);

    query.where(students.name.length.isSmallerThanValue(3));

    return query.map((row) => row.readTable(students)).watch();
  }
}

 

 

😶 데이터 삭제(delete)

delete() 를 사용해서 테이블의 데이터를 삭제할 수 있다. where() 조건으로 조건에 맞는 데이터만 삭제할 수 있다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future allDeleteStudents() {
    // students 데이터 전부 삭제
    return delete(students).go();
  }

  Future deleteStudentsFromName(String name) {
    // students name 이 동일한 데이터만 삭제
    return (delete(students)..where((tbl) => tbl.name.equals(name))).go();
  }
}

 

 

😶 데이터 업데이트(update)

update() 를 사용하여 데이터를 업데이트할 수 있다.

@DriftDatabase(tables: [Students, Clubs])
class TestDatabase extends _$TestDatabase {
  ...
  Future updateStudent(int id, StudentsCompanion student) {
    return (update(students)..where((tbl) => tbl.id.equals(id))).write(student);
  }
}

 

 

 

 

Writing queries

Writing queries Learn how to write database queries in pure Dart with drift Note: This assumes that you've already completed the setup. For each table you've specified in the @DriftDatabase annotation on your database class, a corresponding getter for a ta

drift.simonbinder.eu

 

728x90