sqlite_at_runtime 0.0.2+1

  • Readme
  • Changelog
  • Example
  • Installing
  • 69

sqlite_at_runtime #

SQLite plugin for Flutter. Supports both iOS and Android.

  • Allows creation of multiple SQLite databases and their manipulation thus, at application runtime.
  • Supports transactions and batches
  • Helpers for insert/query/update/delete queries

Getting Started #

In your flutter project add the dependency:

dependencies:
  ...
  sqlite_at_runtime: ^0.0.1

For help getting started with Flutter, view the online documentation.

Usage example #

Import sqlite_at_runtime.dart

import 'package:sqlite_at_runtime/sqlite_at_runtime.dart';

Databases (create, delete and existence) #

Once an application is set up, a default SQLite Database is created, with a table that holds information to the Databases created at runtime. The major infomation stored here is an id (as the primary key, an auto incremental integer), the database name and an optional note for the database.

// CREATE A NEW DATABASE
await Sqlartime.addNewDB(String name, String note);
/*
Creation of databases need be done with nowledge of existing databases.
In as much as the databases are differentiated with a timestamp; the process will only create a new database if and only oif there doesn't exist a database with that name.
*/

//GET A LIST OF ALL EXISTING DATABASES
 await Sqlartime.fetchDBs(); 

 /* this returns the name, Id and note of the existing databases
in json. To get any of these entities thus:*/
var list = await Sqlartime.fetchDBs(); 
//get id
final id = list[index]['Id'];
//get DB name
final id = list[index]['name'];
//get note
final id = list[index]['note'];
//get timestamp
final id = list[index]['time'];

//DELETE/DROP AN EXISTING DATABASE
  await Sqlartime.deleteDb(int id, String dbName); 

/*A SQLite database is a file in the file system identified by a path. If relative, this path is relative to the path obtained by `getDatabasesPath()`, which is the default database directory on Android and the documents directory on iOS.
The deleteDB() method deletes the database details as stored in the default database, thus the importance to access and provide the database id (from the fetchDBs() method).
The method goes on to delete the file of the named database from the default file directory that holds the database*/

SQL queries #

Demo code to perform SQL queries It is important to point out that all SQL queries should be done on an open database; making the method of opening a given database a rather important one before the entire lifespan of the database CRUD queries!

//OPEN AN EXISTING DB
//the method closes the default database before opening the prescribed runtime created database
await Sqlartime.openDb(String dbName);
  
//ADD TABLE(S) TO EXISTING DB
await Sqlartime.tableCreate(List tableName, List variables);

/*
The above method take two lists; 
1. A list of tables that come out to share the same structure; this list could without doubt consist of only one table
2. the table structure; with a column name and type in caps, seperated by space.

The below example creates three tables spf the same structures, with a 'name' column of type 'String', 
an 'age' column of type 'int' and a 'temp' column that takes in floating points.

example:
*/
await Sqlartime.tableCreate(['sample1','sample2','sample3'],['name TEXT','age INTEGER','temp REAL']);

// a default 'Id INTEGER PRIMARY KEY AUTOINCREMENT' column is created in this process.

//DELETE/DROP TABLE FROM EXISTING DB
//takes in a list of tables to be deleted/dropped.
//the list can without doubt be made of only one table!
await Sqlartime.deleteTable(List tabName);

//GET ALL TABLES FROM EXISTING DB
await Sqlartime.getTables();

//INSERT INTO TABLE
    //to insert into a table, provide all of three:
    //1. the table name
    //2. a list of the column names to be inserted into
    //3. a list of values that fall respective to the column names provided in #2
await Sqlartime.insertIntoTable(String tableName, List columnTitle, List samplesValue);

//GET ALL FROM TABLE
//this returns a list of all table entities, including id(s)
await Sqlartime.getAll(String tabName);

//DELETE FROM TABLE
//this method takes in the table name and the entity id and goes on to delete everything with the 
//specified id
//this makes the above method of getting table items a prudent method before the delete method
await Sqlartime.deleteTableValues(int id, String tabName);

// UPDATE TABLE VALUES
//muchlike the insert method, the update method takes a list of columns to be manipulated and a list of 
//values for this manipulation
//finally, it takes the id of the entity to be manipulated
await Sqlartime.updateTableValues(List sampleUpdate, List sampleUpdateValue, int id);

//CLOSE AN OPEN DATABASE/
//it is important to close a database once the lifespan of all methods realted to it are done!
await Sqlartime.closeDyn();

Batch support #

One can use Batch as an approach to avoid ping-pong between dart and native code,

batch = db.batch();
batch.insert('myTable', {'name': 'sample'});
batch.update('myTable', {'name': 'new_sample'}, where: 'name = ?', whereArgs: ['sample']);
batch.delete('myTable', where: 'name = ?', whereArgs: ['sample']);
results = await batch.commit();

Getting the result for each operation has a cost (id for insertion and number of changes for update and delete), especially on Android where an extra SQL request is executed. If you don't care about the result and worry about performance in big batches, you can use

await batch.commit(noResult: true);

Warning, during a transaction, the batch won't be committed until the transaction is committed

await database.transaction((txn) async {
  var batch = txn.batch();
  
  // ...
  
  // commit but the actual commit will happen when the transaction is committed
  // however the data is available in this transaction
  await batch.commit();
  
  //  ...
});

By default a batch stops as soon as it encounters an error (which typically reverts the uncommitted changes). You can ignore errors so that every successfull operation is ran and committed even if one operation fails:

await batch.commit(continueOnError: true);

Database, Table and Column names #

In general it is better to avoid using SQLite keywords for entity names. If any of the following name is used:

"add","all","alter","and","as","autoincrement","between","case","check","collate","commit",
"isnull","join","limit","not","notnull","null","on","or","order","primary","references","select","constraint","create","default","deferrable","delete","distinct","drop","else","escape","except","exists","foreign","from","group","having","if","in","index","insert","intersect","into","is","set","table","then","to","transaction","union","unique","update","using","values","when","where"

the helper will escape the name i.e.

db.query('table')

will be equivalent to manually adding double-quote around the table name (confusingly here named table)

db.rawQuery('SELECT * FROM "table"');

in addition to these, it is advisable to not use the following names for creating databases: "defaultDB" : this happens to be the name of the default database holding infomation on created databases. Any other name that has already been used to create an existing database.

However in any other raw statement (including orderBy, where, groupBy), make sure to escape the name properly using double quote. For example see below where the column name group is not escaped in the columns argument, but is escaped in the where argument.

db.query('table', columns: ['group'], where: '"group" = ?', whereArgs: ['my_group']);

Supported SQLite types #

No validity check is done on values yet so please avoid non supported types https://www.sqlite.org/datatype3.html

INTEGER #

  • Dart type: int
  • Supported values: from -2^63 to 2^63 - 1

REAL #

  • Dart type: num

TEXT #

  • Dart type: String

BLOB #

  • Dart type: Uint8List
  • Dart type List<int> is supported but not recommended (slow conversion)

Current issues #

  • Due to the way transaction works in SQLite (threads), concurrent read and write transaction are not supported. All calls are currently synchronized and transactions block are exclusive. I thought that a basic way to support concurrent access is to open a database multiple times but it only works on iOS as Android reuses the same database object. I also thought a native thread could be a potential future solution however on android accessing the database in another thread is blocked while in a transaction...
  • Currently INTEGER are limited to -2^63 to 2^63 - 1 (although Android supports bigger ones)

[0.0.1] #

  • Preliminary Release and Trial

[0.0.2] #

  • Example app and trial code

[0.0.2+1] #

  • Bugs under the example app solved.

example/lib/main.dart

import 'package:example/tables.dart';
import 'package:flutter/material.dart';
import 'package:sqlite_at_runtime/sqlite_at_runtime.dart';
import 'package:toast/toast.dart';


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Runtime_SQLite Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  create() {
    return Sqlartime.addNewDB('myDeeBee', 'optional');
  }

  delete() {
    return Sqlartime.deleteDb(1, 'myDeeBee');
  }

  static Future<List<Map>> fetch() {
    return Sqlartime.fetchDBs();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          height: 400.0,
          width: MediaQuery.of(context).size.width,
          child: GridView.count(
            crossAxisCount: 2,
            childAspectRatio: 2.0,
            padding: const EdgeInsets.all(8.0),
            mainAxisSpacing: 12.0,
            crossAxisSpacing: 12.0,
            children: <Widget>[
              RaisedButton(
                child: Text(
                  'Create DB',
                  style: TextStyle(
                    fontSize: 28,
                    color: Colors.black,
                  ),
                  textAlign: TextAlign.center,
                ),
                onPressed: create,
              ),
              RaisedButton(
                child: Text(
                  'Drop DB',
                  style: TextStyle(
                    fontSize: 28,
                    color: Colors.black,
                  ),
                  textAlign: TextAlign.center,
                ),
                onPressed: delete,
              ),
              RaisedButton(
                child: Text(
                  'DB Detail',
                  style: TextStyle(
                    fontSize: 28,
                    color: Colors.black,
                  ),
                  textAlign: TextAlign.center,
                ),
                onPressed: () => fetch().then((value) {
                  Toast.show(value.toString(), context,
                      duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
                }),
                // onPressed:() {},
              ),
              RaisedButton(
                child: Text(
                  'Tables',
                  style: TextStyle(
                    fontSize: 28,
                    color: Colors.black,
                  ),
                  textAlign: TextAlign.center,
                ),
                onPressed: () {
                  Navigator.push(context,
                      MaterialPageRoute(builder: (context) => Tables()));
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  sqlite_at_runtime: ^0.0.2+1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:sqlite_at_runtime/sqlite_at_runtime.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
43
Health:
Code health derived from static analysis. [more]
99
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
69
Learn more about scoring.

We analyzed this package on May 24, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.1
  • pana: 0.13.8-dev
  • Flutter: 1.17.0

Health issues and suggestions

Document public APIs. (-1 points)

98 out of 98 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
path ^1.6.4 1.7.0
shared_preferences ^0.5.4+6 0.5.7+3
sqflite ^1.1.7+3 1.3.0+1
Transitive dependencies
collection 1.14.12
flutter_web_plugins 0.0.0
meta 1.1.8
shared_preferences_macos 0.0.1+9
shared_preferences_platform_interface 1.0.4
shared_preferences_web 0.1.2+7
sky_engine 0.0.99
sqflite_common 1.0.1
synchronized 2.2.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test