Flutter数据库管理插件sql_commander的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter数据库管理插件sql_commander的使用

sql_commander 是一个支持多种数据库的SQL命令链处理和执行器,内置了对MySQL和PostgreSQL的支持。

动机

创建这个包的主要动机是为了在远程位置方便地执行SQL查询链。通过部署一个数据库无关的SQL链命令执行器 (sql_commander),可以简化维护并减少远程设备上的问题。该执行器接收 DBCommand 并远程执行它们,同时适应特定的数据库方言,并解析SQL链引用和ID。

使用方法

DBCommand 示例

以下是一个使用 DBCommand 的示例:

import 'package:sql_commander/sql_commander_postgres.dart';

void main() async {
  // DBCommand SQLs链:
  var dbCommandSQLs = [
    // 提供参数 %SYS_USER% 在以下插入语句中:
    SQL(
      '%SYS_USER%',
      'user',
      SQLType.SELECT,
      where: SQLConditionValue('id', '>', 0),
      returnColumns: {'user_id': 'id'},
      orderBy: '>user_id',
      limit: 1,
    ),
    // 提供参数 %TAB_NUMBER% 在以下插入语句中:
    SQL(
      '%TAB_NUMBER%',
      'tab',
      SQLType.SELECT,
      where: SQLConditionGroup.and([
        SQLConditionValue('serie', '=', 'tabs'),
        SQLConditionGroup.or([
          SQLConditionValue('status', '=', 'free'),
          SQLConditionValue('status', '=', null),
        ])
      ]),
      returnColumns: {'num': null},
      orderBy: '>num',
      limit: 1,
    ),
    // 使用 %SYS_USER% 和 %TAB_NUMBER% 作为参数插入到表 `order` 中:
    SQL(
      // 此SQL的ID,用于命令链中的引用:`#order:1001#`
      '1001',
      'order',
      SQLType.INSERT,
      parameters: {
        'product': 123,
        'price': 10.20,
        'title': 'Water',
        'user': '%SYS_USER%',
        'tab': '%TAB_NUMBER%',
      },
      variables: {'SYS_USER': null, 'TAB_NUMBER': null},
      returnLastID: true,
    ),
    // 另一个插入语句,使用上面的插入语句:`#order:1001#`
    SQL(
      // 此SQL的ID,用于引用:
      '1',
      'order_history',
      SQLType.INSERT,
      parameters: {
        // 上面插入的订单:
        'order': '#order:1001#',
        'date': DateTime.now(),
      },
      returnLastID: true,
    ),
  ];

  // 将DBCommand作为JSON:
  var commandJSON = {
    "host": 'localhost',
    "port": 5432,
    "user": 'root',
    "pass": 'abc123',
    "db": 'dev',
    "software": 'postgres',
    "sqls": dbCommandSQLs.map((e) => e.toJson()).toList(),
  };

  // 从JSON加载DBCommand:
  var dbCommand = DBCommand.fromJson(commandJSON);

  // 注册PostgreSQL连接实现:
  DBConnectionPostgres.register();
  // 对于MySQL:
  // DBConnectionMySQL.register();

  // 执行SQL链:
  var ok = await dbCommand.execute(
    logInfo: (m) => print('[INFO] $m'),
    logError: (m, [e, s]) => print('[ERROR] $m >> $e\n$s'),
  );

  print('SQL链执行结果: $ok');
}

Procedure 示例

你也可以定义一个 Procedure,其中包含一个动态的Dart代码,可以在任何由Dart支持的平台上加载。

import 'package:sql_commander/sql_commander_postgres.dart';

void main() async {
  // 注册PostgreSQL连接实现:
  DBConnectionPostgres.register();
  // 对于MySQL:
  // DBConnectionMySQL.register();

  // DBCommand SQLs链:
  var sqls = [
    // 提供参数 %SYS_USER% 在以下插入语句中:
    SQL(
      '%SYS_USER%',
      'user',
      SQLType.SELECT,
      where: SQLConditionValue('id', '>', 0),
      returnColumns: {'user_id': 'id'},
      orderBy: '>user_id',
      limit: 1,
    ),
    // 提供参数 %TAB_NUMBER% 在以下插入语句中:
    SQL(
      '%TAB_NUMBER%',
      'tab',
      SQLType.SELECT,
      where: SQLConditionGroup.and([
        SQLConditionValue('serie', '=', 'tabs'),
        SQLConditionGroup.or([
          SQLConditionValue('status', '=', 'free'),
          SQLConditionValue('status', '=', null),
        ])
      ]),
      returnColumns: {'num': null},
      orderBy: '>num',
      limit: 1,
    ),
    // 使用 %SYS_USER% 和 %TAB_NUMBER% 作为参数插入到表 `order` 中:
    SQL(
      // 此SQL的ID,用于命令链中的引用:`#order:1001#`
      '1001',
      'order',
      SQLType.INSERT,
      parameters: {
        'product': 123,
        'price': 10.20,
        'title': 'Water',
        'user': '%SYS_USER%',
        'tab': '%TAB_NUMBER%',
      },
      variables: {'SYS_USER': null, 'TAB_NUMBER': null},
      returnLastID: true,
    ),
    // 另一个插入语句,使用上面的插入语句:`#order:1001#`
    SQL(
      // 此SQL的ID,用于引用:
      '1',
      'order_history',
      SQLType.INSERT,
      parameters: {
        // 上面插入的订单:
        'order': '#order:1001#',
        'date': DateTime.now(),
      },
      returnLastID: true,
    ),
  ];

  var dbCommand = DBCommand(
      id: 'cmd_1', 'localhost', 5432, 'root', '123456', 'postgres', '', sqls);

  var procedure = ProcedureDart(
    name: 'do',
    dbCommands: [dbCommand],
    code: r'''
  
      int do() {
        var cmdOK = executeDBCommandByID("cmd_1");
        
        if (!cmdOK) {
          print('** Error executing DBCommand!');
          return false;
        }
        
        print('DBCommand `cmd_1` executed.');
        
        var tabNumber = getSQLResult('%TAB_NUMBER%');
        print('TAB_NUMBER: $tabNumber');
        
        return tabNumber ;
      }
      
    ''',
  );

  var tabNumber = await procedure.execute();
  print("Procedure结果> tabNumber: $tabNumber");
}

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

1 回复

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


在Flutter中,sql_commander 是一个用于管理 SQLite 数据库的插件。它提供了简化的 API 来执行 SQL 语句,并管理数据库中的表和数据。以下是如何在 Flutter 项目中使用 sql_commander 的一个简单示例。

首先,确保你已经在 pubspec.yaml 文件中添加了 sql_commander 依赖:

dependencies:
  flutter:
    sdk: flutter
  sql_commander: ^最新版本号 # 请替换为实际发布的最新版本号

然后,运行 flutter pub get 来获取依赖。

接下来,是一个简单的示例,展示了如何使用 sql_commander 来创建数据库、表和插入数据:

import 'package:flutter/material.dart';
import 'package:sql_commander/sql_commander.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('SQL Commander Example'),
        ),
        body: DatabaseExample(),
      ),
    );
  }
}

class DatabaseExample extends StatefulWidget {
  @override
  _DatabaseExampleState createState() => _DatabaseExampleState();
}

class _DatabaseExampleState extends State<DatabaseExample> {
  late DatabaseExecutor _dbExecutor;

  @override
  void initState() {
    super.initState();
    // 初始化数据库执行器
    _dbExecutor = DatabaseExecutor(
      'example.db', // 数据库文件名
      version: 1, // 数据库版本
      onCreate: (db, version) async {
        // 在这里创建表
        await db.execute('''
          CREATE TABLE users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            email TEXT NOT NULL UNIQUE
          )
        ''');
      },
      onUpgrade: (db, oldVersion, newVersion) async {
        // 在这里处理数据库升级逻辑
        await db.execute('DROP TABLE IF EXISTS users');
        // 重新创建表或其他升级操作
        onCreate(db, newVersion);
      },
    );

    // 打开数据库连接
    _dbExecutor.open().then((_) {
      // 插入示例数据
      _insertExampleData();
    });
  }

  Future<void> _insertExampleData() async {
    await _dbExecutor.execute('''
      INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')
    ''');
    await _dbExecutor.execute('''
      INSERT INTO users (name, email) VALUES ('Bob', 'bob@example.com')
    ''');
  }

  Future<List<Map<String, Object?>>> _fetchUserData() async {
    return await _dbExecutor.query('users');
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<List<Map<String, Object?>>>(
      future: _fetchUserData(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else if (snapshot.hasError) {
          return Center(child: Text('Error: ${snapshot.error!}'));
        } else {
          final users = snapshot.data ?? [];
          return ListView.builder(
            itemCount: users.length,
            itemBuilder: (context, index) {
              final user = users[index];
              return ListTile(
                title: Text('${user['name']}'),
                subtitle: Text('${user['email']}'),
              );
            },
          );
        }
      },
    );
  }

  @override
  void dispose() {
    // 关闭数据库连接
    _dbExecutor.close();
    super.dispose();
  }
}

在这个示例中:

  1. 我们创建了一个 DatabaseExecutor 实例来管理数据库。
  2. onCreate 回调中,我们定义了数据库的初始表结构。
  3. initState 方法中,我们打开数据库连接并插入一些示例数据。
  4. 使用 FutureBuilder 来异步获取并显示用户数据。
  5. dispose 方法中,我们确保关闭数据库连接。

这个示例展示了如何使用 sql_commander 插件来管理 SQLite 数据库,包括创建表、插入数据和查询数据。你可以根据实际需求扩展这个示例。

回到顶部