Flutter数据库代码生成插件typesql_generator的使用

Flutter数据库代码生成插件typesql_generator的使用

typesql_generator 是一个从 .sql 文件生成 Dart 查询和模型的插件。它利用 wasm_run 执行 WASM 和 sqlparser-rs 来实现底层功能。

示例代码

以下是一个完整的示例,展示了如何使用 typesql_generator 插件来生成和使用数据库查询和模型。

import 'dart:convert';

import 'package:typesql/sqlite.dart';
import 'package:typesql/typesql.dart';

import 'example.sql.dart';

Future<void> main() async {
  return test();
}

void defaultExpect(Object? a, Object? b) {
  if (a != b) throw Exception('$a != $b');
}

Future<void> test({
  void Function(Object? a, Object? b) expect = defaultExpect,
}) async {
  final sqlite = await loadSqlite();
  final db = sqlite.openInMemory();
  final executor = SqliteExecutor(db);
  final example = ExampleQueries(executor);

  await example.defineDatabaseObjects();
  // await example.createTableUsers();
  final execution = await example.insertUsers1(InsertUsers1Args(c: 'name'));
  expect(execution.updaterRows, 2);
  expect(execution.lastInsertId, '2');

  final users = await example.querySelectUsers1();
  expect(users.length, 2);
  expect(users[0], QuerySelectUsers1(usersId: 1, usersName: 'name1'));
  expect(users[1], QuerySelectUsers1(usersId: 2, usersName: 'name'));

  {
    final toInsert = [
      UsersInsert(id: 3, name: 'name3'),
      UsersInsert(id: 4, name: 'name4'),
    ];
    final usersQueries = example.usersController;
    final inserted = await usersQueries.insertManyReturning(toInsert);
    expect(jsonEncode(toInsert), jsonEncode(inserted));

    final deleted = await usersQueries.deleteManyReturning([UsersKeyId(id: 3)]);
    expect(jsonEncode([toInsert.first]), jsonEncode(deleted));

    final updated3 = await usersQueries.updateReturning(
      UsersKeyId(id: 3),
      UsersUpdate(name: 'nameUpdated3'),
    );
    expect(updated3, null);

    final updated4 = await usersQueries.updateReturning(
      UsersKeyId(id: 4),
      UsersUpdate(name: 'nameUpdated4'),
    );
    expect(updated4, Users(id: 4, name: 'nameUpdated4'));

    final selected4 = await usersQueries.selectUnique(UsersKeyId(id: 4));
    expect(selected4, updated4);
  }

  {
    final toInsert = [
      PostsInsert(id: 3, userId: 4, title: 'title', body: 'body'),
      PostsInsert(
        id: 4,
        userId: 4,
        title: 'title4',
        body: 'body4',
        subtitle: 'subtitle4',
        createdAt: DateTime(2024),
      ),
    ];
    final postsQueries = example.postsController;
    final inserted = await postsQueries.insertManyReturning(toInsert);
    expect(
      jsonEncode([
        PostsInsert(
          id: 3,
          userId: 4,
          title: 'title',
          body: 'body',
          createdAt: inserted.first.createdAt,
        ),
        toInsert.last,
      ]),
      jsonEncode(inserted),
    );

    final deleted = await postsQueries.deleteManyReturning([PostsKeyId(id: 3)]);
    expect(jsonEncode([inserted.first]), jsonEncode(deleted));

    final updated3 = await postsQueries.updateReturning(
      PostsKeyId(id: 3),
      PostsUpdate(subtitle: Some('subtitleUpdated')),
    );
    expect(updated3, null);

    final updated4 = await postsQueries.updateReturning(
      PostsKeyId(id: 4),
      PostsUpdate(subtitle: Some('subtitleUpdated')),
    );
    expect(
      updated4,
      Posts(
        id: 4,
        userId: 4,
        title: 'title4',
        body: 'body4',
        subtitle: 'subtitleUpdated',
        createdAt: DateTime(2024),
      ),
    );

    final selected4 = await postsQueries.selectUnique(PostsKeyId(id: 4));
    expect(selected4, updated4);
  }

  // final values =
  //     await example.typedExecutor.selectMany(FilterEq(UsersUpdate()));

  // final d = await example.typedExecutor.selectUnique(UsersKeyId(id: 3));
}

class SqliteExecutor extends SqlExecutor {
  final CommonDatabase db;

  SqliteExecutor(this.db);

  [@override](/user/override)
  SqlDialect get dialect => SqlDialect.sqlite;

  [@override](/user/override)
  Future<T?> transaction<T>(Future<T> Function() transact) async {
    bool started = false;
    try {
      db.execute('BEGIN TRANSACTION');
      started = true;
      final result = await transact();
      db.execute('COMMIT');
      return result;
    } catch (e) {
      if (started) {
        try {
          db.execute('ROLLBACK');
        } catch (_) {}
      }
      return null;
    }
  }

  [@override](/user/override)
  Future<SqlExecution> execute(String sql, [List<Object?>? params]) async {
    db.execute(sql, params ?? const []);
    return SqlExecution(
      lastInsertId: db.lastInsertRowId.toString(),
      updaterRows: db.getUpdatedRows(),
    );
  }

  [@override](/user/override)
  Future<List<List<Object?>>> query(String sql, [List<Object?>? params]) {
    final rows = db.select(sql, params ?? const []);
    return Future.value(rows.rows);
  }

  [@override](/user/override)
  Future<SqlPreparedStatement> prepare(String sql) async {
    final statement = db.prepare(sql, persistent: true);
    return SqlPreparedStatement.value(
      sql,
      statement.parameterCount,
      dispose: statement.dispose,
      execute: ([p]) async {
        statement.execute(p ?? const []);
        return SqlExecution(
          lastInsertId: db.lastInsertRowId.toString(),
          updaterRows: db.getUpdatedRows(),
        );
      },
      select: ([p]) async {
        return statement.select(p ?? const []).rows;
      },
    );
  }
}

说明

  1. 导入库:

    import 'dart:convert';
    
    import 'package:typesql/sqlite.dart';
    import 'package:typesql/typesql.dart';
    
    import 'example.sql.dart';
    
  2. 初始化数据库:

    final sqlite = await loadSqlite();
    final db = sqlite.openInMemory();
    final executor = SqliteExecutor(db);
    final example = ExampleQueries(executor);
    
  3. 定义数据库对象:

    await example.defineDatabaseObjects();
    
  4. 插入数据:

    final execution = await example.insertUsers1(InsertUsers1Args(c: 'name'));
    
  5. 查询数据:

    final users = await example.querySelectUsers1();
    
  6. 更新数据:

    final updated3 = await usersQueries.updateReturning(
      UsersKeyId(id: 3),
      UsersUpdate(name: 'nameUpdated3'),
    );
    
  7. 删除数据:

    final deleted = await usersQueries.deleteManyReturning([UsersKeyId(id: 3)]);
    
  8. 事务处理:

    [@override](/user/override)
    Future<T?> transaction<T>(Future<T> Function() transact) async {
      bool started = false;
      try {
        db.execute('BEGIN TRANSACTION');
        started = true;
        final result = await transact();
        db.execute('COMMIT');
        return result;
      } catch (e) {
        if (started) {
          try {
            db.execute('ROLLBACK');
          } catch (_) {}
        }
        return null;
      }
    }
    

更多关于Flutter数据库代码生成插件typesql_generator的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter数据库代码生成插件typesql_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


typesql_generator 是一个用于 Flutter 的代码生成插件,它可以帮助开发者自动生成与 SQLite 数据库交互的代码,从而减少手动编写重复代码的工作量。使用 typesql_generator,你可以通过定义数据模型类来生成对应的 SQLite 表和 CRUD 操作代码。

安装和使用步骤

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 typesql_generatorbuild_runner 依赖。

dependencies:
  flutter:
    sdk: flutter
  typesql: ^0.1.0  # 或者最新版本

dev_dependencies:
  build_runner: ^2.1.0  # 或者最新版本
  typesql_generator: ^0.1.0  # 或者最新版本

2. 定义数据模型类

接下来,你需要定义一个数据模型类,并使用 @TypeSql 注解来标记它。这个类将被用来生成 SQLite 表和 CRUD 操作代码。

import 'package:typesql/typesql.dart';

part 'user.g.dart';  // 生成的文件

@TypeSql()
class User {
  final int id;
  final String name;
  final int age;

  User({required this.id, required this.name, required this.age});
}

3. 生成代码

运行以下命令来生成代码:

flutter pub run build_runner build

这将会生成一个名为 user.g.dart 的文件,其中包含了与 SQLite 数据库交互的代码。

4. 使用生成的代码

生成的代码包含了数据库表的创建、插入、查询、更新和删除等操作。你可以在你的应用中使用这些生成的代码来操作数据库。

import 'package:flutter/material.dart';
import 'user.dart';  // 导入生成的文件

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化数据库
  final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();

  // 获取 UserDao
  final userDao = database.userDao;

  // 插入用户
  await userDao.insertUser(User(id: 1, name: 'John Doe', age: 30));

  // 查询所有用户
  final users = await userDao.findAllUsers();
  print(users);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TypeSQL Example'),
        ),
        body: Center(
          child: Text('Check the console for database output!'),
        ),
      ),
    );
  }
}
回到顶部