Aus öffentlichen Paketdaten erstellte Orientierung.
Sqlcool ist ein Flutter/Dart-Paket, das die Arbeit mit SQLite-Datenbanken vereinfacht, indem es reaktive Streams für Datenbankänderungen, eingebaute Select-Bloc-Muster und Unterstützung für benutzerdefinierte Datenbankmodelle bereitstellt. Es ermöglicht Echtzeit-Daten-Synchronisation und effiziente Abfragen mit minimalem Boilerplate. Für Entwickler, die eine leichte, intuitive Lösung für die persistente lokale Datenspeicherung in Flutter-Apps suchen, wurde Sqlcool entwickelt und integriert sich nahtlos in reaktive Programmierparadigmen. Das Paket betont Benutzerfreundlichkeit, behält aber Flexibilität für komplexe Datenbankoperationen bei.
Anwendungsfälle
Echtzeit-Daten-Synchronisierung in Offline-zuerst-Anwendungen
Reaktive UI-Updates basierend auf Datenbankänderungen
Verwaltung lokalen Zustands mit strukturierten Datenbankmodellen
Formulare mit dynamischer Datenladung erstellen
Caching-Ebenen mit SQLite implementieren
Vereinfachung von CRUD-Operationen mit benutzerdefinierten Modellen
Hauptmerkmale
Reaktive Streams für Datenbankänderungsbenachrichtigungen
Eingebautes Select-Bloc-Muster für die Zustandsverwaltung
Unterstützung für benutzerdefinierte Datenbankmodelldefinitionen
Einfache API für Abfragen und Mutationen
Automatische typensichere Modellzuordnung
Leichtgewichtig und minimale Abhängigkeiten
Geeignet für
Entwickler, die Offline-fähige Flutter-Apps erstellen
Teams, die reaktive Zustandsverwaltung verwenden
Projekte, die Echtzeit-Datenbankaktualisierungen erfordern
Apps, die strukturierte lokale Datenpersistenz benötigen
Anfänger lernen SQLite in Flutter
Apps mit häufigen lokalen Dateninteraktionen
Hinweise
Nur auf SQLite beschränkt (keine anderen Datenbanken)
Keine integrierte Migrationshandhabung (manuelle oder externe Tools erforderlich)
Kann zusätzliche Einrichtung für komplexe Schemaänderungen erfordern
Nicht ideal für großskalige serverseitige Datenbankoperationen
Am besten geeignet für mobile und Desktop-Anwendungsfälle
Erfordert Verständnis von Konzepten der reaktiven Programmierung
Original-README
Originaler README-Schnappschuss aus dem verknüpften Quell-Repository. Aktuelle Inhalte finden Sie im Repository.
Sqlcool
A database helper library for Sqflite. Forget about implementation details and focus on the business logic.
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_PageSelectBlocStateextendsState<PageSelectBloc> {
SelectBloc bloc;
@overridevoidinitState() {
super.initState();
this.bloc = SelectBloc(
table: "items", orderBy: "name", reactive: true);
}
@overridevoiddispose() {
bloc.dispose();
super.dispose();
}
@overrideWidgetbuild(BuildContext context) {
returnScaffold(
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 anythingif (snapshot.data.length == 0) {
returnCenter(child: constText("No data"));
}
// the select query has resultsreturnListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
var item = snapshot.data[index];
returnListTile(
title: GestureDetector(
child: Text(item["name"]),
onTap: () => someFunction()),
);
});
} else {
// the select query is still runningreturnCircularProgressIndicator();
}
}),
);
}
}
classPageSelectBlocextendsStatefulWidget{
@override_PageSelectBlocStatecreateState() => _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 schemaimport'schema.dart';
// another modelimport'manufacturer_model.dart';
classCarwithDbModel{
Car(
{this.id,
this.name,
this.maxSpeed,
this.price,
this.year,
this.is4wd,
this.manufacturer});
/// define some class propertiesfinalString name;
finalint maxSpeed;
finaldouble price;
finalDateTime year;
finalbool is4wd;
// this is a foreign key to another modelManufacturer manufacturer;
/// [DbModel] required overrides@overrideint id;
/// the [Db] used/// pass it your main db@overrideDbget db => db;
/// the table schema representation/// check example/pages/dbmodels/schema.dart@overrideDbTableget table => carTable;
/// serialize a row to the database@overrideMap<String, dynamic> toDb() {
// we want the foreign key to be recordedassert(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@overrideCarfromDb(Map<String, dynamic> map) {
final car = Car(
id: map["id"] asint,
name: map["name"].toString(),
maxSpeed: map["max_speed"] asint,
price: map["price"] asdouble,
year: DateTime.fromMillisecondsSinceEpoch(map["year"] asint),
is4wd: (map["is_4wd"].toString() == "true"),
);
// the key will be present only with join queries// in a simple select this data is not presentif (map.containsKey("manufacturer")) {
car.manufacturer =
Manufacturer().fromDb(map["manufacturer"] asMap<String, dynamic>);
}
return car;
}
/// Create a static join method for conveniencestaticFuture<List<Car>> selectRelated({String where, int limit}) async {
final cars = List<Car>.from(
awaitCar().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 instancesprint(cars[0].manufacturer.name);