搜索插件、代码仓与 APP 分类

插件详情v5.1.1

sqlcool

简单且响应式的 Sqlite。变更流、选择 bloc、自定义数据库模型

近 30 天下载
148
喜欢数
43
Pub 分数
40

安装插件

flutter pub add sqlcool

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

Sqlcool 是一个 Flutter/Dart 包,通过提供数据库更改的响应式流、内置的 select bloc 模式以及对自定义数据库模型的支持,简化了与 SQLite 数据库的交互。它能够实现实时数据同步和高效的查询,同时最大限度地减少样板代码。专为寻求轻量级、直观解决方案以在 Flutter 应用中进行本地持久化数据存储的开发者设计,Sqlcool 可无缝集成到响应式编程范式中。该包强调易用性,同时保持对复杂数据库操作的灵活性。

适合场景

  • 离线优先应用中的实时数据同步
  • 基于数据库更改的反应式 UI 更新
  • 使用结构化数据库模型管理本地状态
  • 使用动态数据加载构建表单
  • 使用 SQLite 实现缓存层
  • 使用自定义模型简化 CRUD 操作

主要特点

  • 数据库变更通知的反应式流
  • 用于状态管理的内置选择块模式
  • 对自定义数据库模型定义的支持
  • 用于查询和变更的简单 API
  • 自动类型安全的模型映射
  • 轻量且依赖极少

适合对象

  • 开发离线功能的 Flutter 应用程序的开发者
  • 使用反应式状态管理的团队
  • 需要实时数据库更新的项目
  • 需要结构化本地数据持久化的应用
  • 初学者学习Flutter中的SQLite
  • 频繁本地数据交互的应用

使用建议

  • 仅限 SQLite(不支持其他数据库)
  • 无内置迁移处理(需要手动或外部工具)
  • 可能需要额外设置才能完成复杂的架构更改
  • 不太适合大规模的服务器端数据库操作
  • 最适合移动和桌面使用场景
  • 需要理解响应式编程概念

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

Sqlcool

pub package Build Status Coverage Status

A database helper library for Sqflite. Forget about implementation details and focus on the business logic.

  • Simple: easy api for crud operations
  • Reactive: stream of changes, select bloc
  • Adaptative: plug custom models into the database

Check the documentation or the api doc for usage instructions

Simple crud

Define the database schema
import 'package:sqlcool/sqlcool.dart';

Db db = Db();
// define the database schema
DbTable category = DbTable("category")..varchar("name", unique: true);
DbTable product = DbTable("product")
   ..varchar("name", unique: true)
   ..integer("price")
   ..text("descripton", nullable: true)
   ..foreignKey("category", onDelete: OnDelete.cascade)
   ..index("name");
List<DbTable> schema = [category, product];
Initialize the database
String dbpath = "db.sqlite"; // relative to the documents directory
try {
  await db.init(path: dbpath, schema: schema);
} catch(e) {
  rethrow;
}
Insert
final Map<String, String> row = {name: "My item"};
try {
  int id = await db.insert(table: "category", row: row)
} catch(e) {
  rethrow;
}
Select
try {
  List<Map<String, dynamic>> rows = await db.select(
    table: "product",
    limit: 20,
    columns: "id,name",
    where: "name LIKE '%something%'",
    orderBy: "name ASC",
  );
} catch (e) {
  rethrow;
}
Update
try {
  int numRowsUpdated = await db.update(table: "category", 
   row: row, where: "id=1");
} catch(e) {
  rethrow;
}
Delete
try {
  await db.delete(table: "category", where: "id=3");
} catch(e) {
  rethrow;
}
Join queries
try {
  final data = await db.join(
   table: "product",
   columns: "product.name,price,category.name as category_name",
   joinTable: "category",
   joinOn: "product.category=category.id");
} catch(e) {
  rethrow;
}
Join on multiple tables
try {
  final data = db.mJoin(table: "product", joinsTables: <String>[
   "category",
   "manufacturer"
 ], joinsOn: <String>[
   "product.category=category.id",
   "product.manufacturer=manufacturer.id"
 ]);
} catch(e) {
  rethrow;
}

Reactivity

Changefeed

A stream of database change events is available. Inspired by Rethinkdb

import 'dart:async';
import 'package:sqlcool/sqlcool.dart';

StreamSubscription changefeed;

changefeed = db.changefeed.listen((change) {
   print("Change in the database:");
   print("Query: ${change.query}");
   if (change.type == DatabaseChange.update) {
     print("${change.value} items updated");
   }
 });
// Dispose the changefeed when finished using it
changefeed.cancel();
Reactive select bloc

The bloc will rebuild itself on any database change because of the reactive parameter set to true:

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

class _PageSelectBlocState extends State<PageSelectBloc> {
  SelectBloc bloc;

  @override
  void initState() {
    super.initState();
    this.bloc = SelectBloc(
        table: "items", orderBy: "name", reactive: true);
  }

  @override
  void dispose() {
    bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("My app")),
      body: StreamBuilder<List<Map>>(
          stream: bloc.items,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.hasData) {
              // the select query has not found anything
              if (snapshot.data.length == 0) {
                return Center(child: const Text("No data"));
              }
              // the select query has results
              return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (BuildContext context, int index) {
                    var item = snapshot.data[index];
                    return ListTile(
                      title: GestureDetector(
                        child: Text(item["name"]),
                        onTap: () => someFunction()),
                    );
                  });
            } else {
              // the select query is still running
              return CircularProgressIndicator();
            }
          }),
    );
  }
}

class PageSelectBloc extends StatefulWidget {
  @override
  _PageSelectBlocState createState() => _PageSelectBlocState();
}

Database models

New in 4.0.0: define models that have database methods. The main advantage of this is to use only typed model data and avoid the type conversions from maps for every query. It directly plugs custom models into the database. Example:

In schema.dart:

final carTable = DbTable("car")
  ..varchar("name")
  ..integer("max_speed")
  ..real("price")
  ..integer("year")
  ..boolean("is_4wd", defaultValue: false)
  ..foreignKey("manufacturer", onDelete: OnDelete.cascade);

final manufacturerTable = DbTable("manufacturer")..varchar("name");

In car_model.dart:

import 'package:sqlcool/sqlcool.dart';
// the database schema
import 'schema.dart';
// another model
import 'manufacturer_model.dart';

class Car with DbModel {
  Car(
      {this.id,
      this.name,
      this.maxSpeed,
      this.price,
      this.year,
      this.is4wd,
      this.manufacturer});

  /// define some class properties

  final String name;
  final int maxSpeed;
  final double price;
  final DateTime year;
  final bool is4wd;
  // this is a foreign key to another model
  Manufacturer manufacturer;

  /// [DbModel] required overrides

  @override
  int id;

  /// the [Db] used
  /// pass it your main db
  @override
  Db get db => db;

  /// the table schema representation
  /// check example/pages/dbmodels/schema.dart
  @override
  DbTable get table => carTable;

  /// serialize a row to the database
  @override
  Map<String, dynamic> toDb() {
    // we want the foreign key to be recorded
    assert(manufacturer?.id != null);
    final row = <String, dynamic>{
      "name": name,
      "max_speed": maxSpeed,
      "price": price,
      "year": year.millisecondsSinceEpoch,
      "is_4wd": is4wd,
      "manufacturer": manufacturer.id
    };
    return row;
  }

  /// deserialize a row from database
  @override
  Car fromDb(Map<String, dynamic> map) {
    final car = Car(
      id: map["id"] as int,
      name: map["name"].toString(),
      maxSpeed: map["max_speed"] as int,
      price: map["price"] as double,
      year: DateTime.fromMillisecondsSinceEpoch(map["year"] as int),
      is4wd: (map["is_4wd"].toString() == "true"),
    );
    // the key will be present only with join queries
    // in a simple select this data is not present
    if (map.containsKey("manufacturer")) {
      car.manufacturer =
          Manufacturer().fromDb(map["manufacturer"] as Map<String, dynamic>);
    }
    return car;
  }

  /// Create a static join method for convenience

  static Future<List<Car>> selectRelated({String where, int limit}) async {
    final cars = List<Car>.from(
        await Car().sqlJoin(where: where, limit: limit, verbose: true));
    return cars;
  }
}

Then use the models:

/// car is an instance of [Car]
await car.sqlInsert();
await car.sqlUpdate();
await car.sqlUpsert();
await car.sqlDelete();
final cars = Car.selectRelated(where: "speed>200");
// foreign keys are retrieved as model instances
print(cars[0].manufacturer.name);

Using this

  • Sqlview: admin view and infinite list view
  • Kvsql: a type safe key/value store
  • Geopoint sql: sql operations for geospatial data

所属分类

依赖

依赖清单 5 项

源码仓库

使用此插件的项目

暂无相关数据。