Flutter Persistent Object Mapper Based on Sqflite Provides Model

flutter_pom

Flutter Persistent Object Mapper based on sqflite provides model based SQLite access including automatic database creation

Installing

Add dependency

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

dependencies:
  flutter_pom: ^0.0.3

Install the plugin

Now you can install the package (if you got it from pub.dev) via console.

$ flutter pub get

Import the plugin

Finally you have to import the plugin into your Dart source

import 'package:flutter_pom/flutter_pom.dart';

Example

To kickstart with the newly installed library you will have to create the necessary model and database classes.

Create the Table-model

The table model represents the configuration of your table. This includes all columns and the table name. In order to work this needs to extend from Table (flutter_pom).

class SampleTable extends Table {
  // The constructor has to call 'super' with the name of the table
  SampleTable() : super("sample_table");
  
  // These are the fields that we define for the table.
  // Each field corresponds to a table column
  
  final IdField id = IdField("id").autoIncrement();
  final StringField str = StringField("str").notNull("");
  
  // You have to override the method 'getInstance' for the
  // deserializer to get a new instance of your type as dart
  // does not support reflection well by now.
  
  @override
  Table getInstance() {
    return SampleTable();
  }
  
  // initializeFields provides the TableBuilder in the background
  // with all defined fields. As dart does not support reflection 
  // this is our way to go.
  
  @override
  List<Field> initializeFields() {
    return [
      id,
      str
    ];
  }
}

Create the Database model

Next you have to create a database model. The model needs to be inherited from Database (flutter_pom). The database model contains all tables that you want to access inside the specified database.

Note: There can be more than one database model inside your app

class SampleDb extends Database {
  // The constructor has to call 'super' with the database name
  SampleDb() : super("sample.db");
  
  // initializeDatabase provides the DatabaseBuilder in the background
  // with all containing databases. As dart does not support reflection
  // this is our way to go.
  
  @override
  Map<Type, Table> initializeDatabase() {
    return <Type, Table>{
      SampleTable: SampleTable()
    };
  }
}

Use the database in your App Logic

Now its time to make use of the newly created database and tables.

void Do() async {
  
    // initialize the database
    var db = SampleDb();
    
    // open() the connection to the database. 
    // This method has to be called once before 
    // accessing the database
    await db.open();
    
    // Get the automatically created context of the 
    // table 'SampleTable'
    var context = await db.of<SampleTable>();
    
    // Create a new SampleTable item (think of it as a row)
    var sampleItem = SampleTable();
    
    // Access the str field
    sampleItem.str.value = "String value";
    
    // Put the item into the database
    await context.put(sampleItem);
    
    // Get all items 
    var itemsFilter = await context.select();
    
    // A complex filter scenario with comparison of 
    // field values and ordering
    // We also support limiting and offsets
    var itemsFilter2 = await c.select((q) {
          return q
                 .where(c.fields.idField.gte(3))
                 .and(c.fields.idField.lte(20))
                 .orderByAsc([c.fields.idField])
                 .limit(40)
                 .offset(2);
        });    
    
    // NOTICE: There is an alternative way of querying 
    // data using Dart included test methods.
    // The downside of this approach is that all data will 
    // be queried and cached before the
    // filtering begins. 
    // For datasets > 1k items you should use the 'select' 
    // method to do filtering on db level
    // instead.
    //
    // The following query filters the exact same data 
    // like 'itemsFilter2' without ordering 
    // and limiting. This can later be done with dart language 
    
    var itemsFilter3 = await c.where((i) => 
                                i.idField.value >= 3 &&
                                i.idField.value <= 20);
    
    // Count all items
    var count1 = await c.count();
    
    // Count all items where id >= 3 and id <= 20
    var count2 = await c.count((q) {
           return q
                  .where(c.fields.idField.gte(3))
                  .and(c.fields.idField.lte(20));
        });
    
    // Delete the item
    await context.delete(sampleItem);
    
    // Update the item. Only changed values will be updated.
    await context.update(sampleItem);
    
    // Register for the onCreate Stream that gets fired 
    // everytime somebody adds an item
    context.onCreate.listen((sampleItem) {
      // do something with the item
    });
}

Relating Tables

Starting with version 0.1.23 you can now bind tables to a field. This gives you the chance to create dependent tables you can query with a new list extension.

For now only 1:1 relations are supported.

The following code will give you an example of how to get started:

class User extends Table {
  /// We only show things that changed here. 
  /// The Table implementation is still the same 
  /// as described prior.
  StringField userName = StringField("user_name").notNull();
 
  /// Here we reference the job table. 
  /// The framework will internally save the id of the
  /// referenced table item only
  KeyField<Job> job = KeyField<Job>("job_id");
}

/// You may want to manage existing jobs in a seperate table
class Job extends Table {
  /// Same as above
  StringField jobName = StringField("job_name").notNull();
}


/// Example Method adding a new user with a *new* job
void addUser(User user, Job job) async {
  var users = await db.of<User>();  
  var jobs = await db.of<Job>();
  
  user.job.binding = job;
  
  await jobs.put(job);
  await users.put(user);
}

/// Example method reading all users and resolving 
/// all job items automatically
void getUsers() async {
  var users = await db.of<User>();
  var jobs = await db.of<Job>();
  
  /// Here we select all users and then call the method
  /// 'include' on the resulting list.
  /// 'include' expects the database context and the field
  /// you want to resolve.
  var userList = users.select().include<Job>(db, User().job);
}

Indexing fields

You can easily let POM create indexes for your fields by adding .withIndex() to the field definition:

StringField email = StringField("email").withIndex(unique: true);

You can also define whether the indexed values shall be unique or not.

Transaction Support (since 0.1.26)

You can easily manage your transactions by using the 'transaction()' method of your database and provide it to all supported methods inside your context.

Example:

var txn = db.transaction();

await db.of<User>().add(newUser, txn);
await db.of<User>().deleteById(5, txn);

await txn.commit();

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_pom

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_pom: ^0.2.5

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

Import it

Now in your Dart code, you can use:

import 'package:flutter_pom/flutter_pom.dart'; 

example/lib/main.dart

import 'package:example/pom/sample_table.dart';
import 'package:example/pom/sample_table_2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_pom/flutter_pom.dart';

import 'pom/sample_db.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: 'Flutter POM Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  SampleDb db = SampleDb();

  void _incrementCounter() async {
    await db.open();

    var c1 = await db.of<SampleTable>();
    var c2 = await db.of<SampleTable2>();

    var item1 = SampleTable();
    item1.counterValue.value = _counter + 1;
    item1.dateTime.value = DateTime.now();

    await c1.put(item1);

    var item = SampleTable2();
    item.counterValue.value = _counter + 1;
    item.dateTime.value = DateTime.now();
    item.keyField.binding = item1;

    await c2.put(item);

    var itemRef = await c2.select();
    var items = await itemRef.include<SampleTable>(db, SampleTable2().keyField);

    print(items);

    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.bodyText1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
} 

Download Details:

Author: cmoellerffo

Source Code: https://github.com/cmoellerffo/flutter_pom

#flutter #sqflite 

Flutter Persistent Object Mapper Based on Sqflite Provides Model
Zoie  Trantow

Zoie Trantow

1648638000

SQLite Plugin For Flutter. Supports IOS, android and MacOS

sqflite

SQLite plugin for Flutter. Supports iOS, Android and MacOS.

  • Support transactions and batches
  • Automatic version managment during open
  • Helpers for insert/query/update/delete queries
  • DB operation executed in a background thread on iOS and Android

Other platforms support:

Usage example:

  • notepad_sqflite: Simple flutter notepad working on iOS/Android/Windows/linux/Mac

Getting Started

In your flutter project add the dependency:

dependencies:
  ...
  sqflite:

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

Usage example

Import sqflite.dart

import 'package:sqflite/sqflite.dart';

Opening a database

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/MacOS.

var db = await openDatabase('my_db.db');

There is a basic migration mechanism to handle schema changes during opening.

Many applications use one database and would never need to close it (it will be closed when the application is terminated). If you want to release resources, you can close the database.

await db.close();

Raw SQL queries

Demo code to perform Raw SQL queries

// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');

// Delete the database
await deleteDatabase(path);

// open the database
Database database = await openDatabase(path, version: 1,
    onCreate: (Database db, int version) async {
  // When creating the db, create the table
  await db.execute(
      'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});

// Insert some records in a transaction
await database.transaction((txn) async {
  int id1 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
  print('inserted1: $id1');
  int id2 = await txn.rawInsert(
      'INSERT INTO Test(name, value, num) VALUES(?, ?, ?)',
      ['another name', 12345678, 3.1416]);
  print('inserted2: $id2');
});

// Update some record
int count = await database.rawUpdate(
    'UPDATE Test SET name = ?, value = ? WHERE name = ?',
    ['updated name', '9876', 'some name']);
print('updated: $count');

// Get the records
List<Map> list = await database.rawQuery('SELECT * FROM Test');
List<Map> expectedList = [
  {'name': 'updated name', 'id': 1, 'value': 9876, 'num': 456.789},
  {'name': 'another name', 'id': 2, 'value': 12345678, 'num': 3.1416}
];
print(list);
print(expectedList);
assert(const DeepCollectionEquality().equals(list, expectedList));

// Count the records
count = Sqflite
    .firstIntValue(await database.rawQuery('SELECT COUNT(*) FROM Test'));
assert(count == 2);

// Delete a record
count = await database
    .rawDelete('DELETE FROM Test WHERE name = ?', ['another name']);
assert(count == 1);

// Close the database
await database.close();

Basic information on SQL here.

SQL helpers

Example using the helpers

final String tableTodo = 'todo';
final String columnId = '_id';
final String columnTitle = 'title';
final String columnDone = 'done';

class Todo {
  int id;
  String title;
  bool done;

  Map<String, Object?> toMap() {
    var map = <String, Object?>{
      columnTitle: title,
      columnDone: done == true ? 1 : 0
    };
    if (id != null) {
      map[columnId] = id;
    }
    return map;
  }

  Todo();

  Todo.fromMap(Map<String, Object?> map) {
    id = map[columnId];
    title = map[columnTitle];
    done = map[columnDone] == 1;
  }
}

class TodoProvider {
  Database db;

  Future open(String path) async {
    db = await openDatabase(path, version: 1,
        onCreate: (Database db, int version) async {
      await db.execute('''
create table $tableTodo ( 
  $columnId integer primary key autoincrement, 
  $columnTitle text not null,
  $columnDone integer not null)
''');
    });
  }

  Future<Todo> insert(Todo todo) async {
    todo.id = await db.insert(tableTodo, todo.toMap());
    return todo;
  }

  Future<Todo> getTodo(int id) async {
    List<Map> maps = await db.query(tableTodo,
        columns: [columnId, columnDone, columnTitle],
        where: '$columnId = ?',
        whereArgs: [id]);
    if (maps.length > 0) {
      return Todo.fromMap(maps.first);
    }
    return null;
  }

  Future<int> delete(int id) async {
    return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]);
  }

  Future<int> update(Todo todo) async {
    return await db.update(tableTodo, todo.toMap(),
        where: '$columnId = ?', whereArgs: [todo.id]);
  }

  Future close() async => db.close();
}

Read results

Assuming the following read results:

List<Map<String, Object?>> records = await db.query('my_table');

Resulting map items are read-only

// get the first record
Map<String, Object?> mapRead = records.first;
// Update it in memory...this will throw an exception
mapRead['my_column'] = 1;
// Crash... `mapRead` is read-only

You need to create a new map if you want to modify it in memory:

// get the first record
Map<String, Object?> map = Map<String, Object?>.from(mapRead);
// Update it in memory now
map['my_column'] = 1;

Transaction

Don't use the database but only use the Transaction object in a transaction to access the database. Keep in mind that the callbacks onCreate onUpgrade onDowngrade are already internally wrapped in a transaction, so there is no need to wrap your statements in a transaction within those callbacks.

await database.transaction((txn) async {
  // Ok
  await txn.execute('CREATE TABLE Test1 (id INTEGER PRIMARY KEY)');
  
  // DON'T  use the database object in a transaction
  // this will deadlock!
  await database.execute('CREATE TABLE Test2 (id INTEGER PRIMARY KEY)');
});

A transaction is committed if the callback does not throw an error. If an error is thrown, the transaction is cancelled. So to rollback a transaction one way is to throw an exception.

Batch support

To avoid ping-pong between dart and native code, you can use Batch:

batch = db.batch();
batch.insert('Test', {'name': 'item'});
batch.update('Test', {'name': 'new_item'}, where: 'name = ?', whereArgs: ['item']);
batch.delete('Test', where: 'name = ?', whereArgs: ['item']);
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);

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","constraint","create","default","deferrable","delete","distinct","drop","else","escape","except","exists","foreign","from","group","having","if","in","index","insert","intersect","into","is","isnull","join","limit","not","notnull","null","on","or","order","primary","references","select","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"');

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

DateTime is not a supported SQLite type. Personally I store them as int (millisSinceEpoch) or string (iso8601)

bool is not a supported SQLite type. Use INTEGER and 0 and 1 values.

More information on supported types here.

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

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...

Documentation

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add sqflite

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  sqflite: ^2.0.2

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

Import it

Now in your Dart code, you can use:

import 'package:sqflite/sqflite.dart';

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:sqflite_example/batch_test_page.dart';
import 'package:sqflite_example/deprecated_test_page.dart';
import 'package:sqflite_example/exception_test_page.dart';
import 'package:sqflite_example/exp_test_page.dart';
import 'package:sqflite_example/manual_test_page.dart';
import 'package:sqflite_example/src/dev_utils.dart';

import 'model/main_item.dart';
import 'open_test_page.dart';
import 'raw_test_page.dart';
import 'slow_test_page.dart';
import 'src/main_item_widget.dart';
import 'todo_test_page.dart';
import 'type_test_page.dart';

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

/// Sqflite test app
class MyApp extends StatefulWidget {
  /// test app.
  const MyApp({Key? key}) : super(key: key);
  // This widget is the root of your application.

  @override
  _MyAppState createState() => _MyAppState();
}

/// Simple test page.
const String testRawRoute = '/test/simple';

/// Open test page.
const String testOpenRoute = '/test/open';

/// Slow test page.
const String testSlowRoute = '/test/slow';

/// Type test page.
const String testTypeRoute = '/test/type';

/// Batch test page.
const String testBatchRoute = '/test/batch';

/// `todo` example test page.
const String testTodoRoute = '/test/todo';

/// Exception test page.
const String testExceptionRoute = '/test/exception';

/// Manual test page.
const String testManualRoute = '/test/manual';

/// Experiment test page.
const String testExpRoute = '/test/exp';

/// Deprecated test page.
const String testDeprecatedRoute = '/test/deprecated';

class _MyAppState extends State<MyApp> {
  var routes = <String, WidgetBuilder>{
    '/test': (BuildContext context) => MyHomePage(),
    testRawRoute: (BuildContext context) => RawTestPage(),
    testOpenRoute: (BuildContext context) => OpenTestPage(),
    testSlowRoute: (BuildContext context) => SlowTestPage(),
    testTodoRoute: (BuildContext context) => TodoTestPage(),
    testTypeRoute: (BuildContext context) => TypeTestPage(),
    testManualRoute: (BuildContext context) => const ManualTestPage(),
    testBatchRoute: (BuildContext context) => BatchTestPage(),
    testExceptionRoute: (BuildContext context) => ExceptionTestPage(),
    testExpRoute: (BuildContext context) => ExpTestPage(),
    testDeprecatedRoute: (BuildContext context) => DeprecatedTestPage(),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Sqflite Demo',
        theme: ThemeData(
          // This is the theme of your application.
          //
          // Try running your application with 'flutter run'. You'll see
          // the application has a blue toolbar. Then, without quitting
          // the app, try changing the primarySwatch below to Colors.green
          // and then invoke 'hot reload' (press 'r' in the console where
          // you ran 'flutter run', or press Run > Hot Reload App in IntelliJ).
          // Notice that the counter didn't reset back to zero -- the application
          // is not restarted.
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Sqflite Demo Home Page'),
        routes: routes);
  }
}

/// App home menu page.
class MyHomePage extends StatefulWidget {
  /// App home menu page.
  MyHomePage({Key? key, this.title}) : super(key: key) {
    _items.add(
        MainItem('Raw tests', 'Raw SQLite operations', route: testRawRoute));
    _items.add(MainItem('Open tests', 'Open onCreate/onUpgrade/onDowngrade',
        route: testOpenRoute));
    _items
        .add(MainItem('Type tests', 'Test value types', route: testTypeRoute));
    _items.add(MainItem('Batch tests', 'Test batch operations',
        route: testBatchRoute));
    _items.add(
        MainItem('Slow tests', 'Lengthy operations', route: testSlowRoute));
    _items.add(MainItem(
        'Todo database example', 'Simple Todo-like database usage example',
        route: testTodoRoute));
    _items.add(MainItem('Exp tests', 'Experimental and various tests',
        route: testExpRoute));
    _items.add(MainItem('Exception tests', 'Tests that trigger exceptions',
        route: testExceptionRoute));
    _items.add(MainItem('Manual tests', 'Tests that requires manual execution',
        route: testManualRoute));
    _items.add(MainItem('Deprecated test',
        'Keeping some old tests for deprecated functionalities',
        route: testDeprecatedRoute));

    // Uncomment to view all logs
    //Sqflite.devSetDebugModeOn(true);
  }

  final List<MainItem> _items = [];

  /// Page title.
  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

String? _debugAutoStartRouteName;

/// (debug) set the route to start with.
String? get debugAutoStartRouteName => _debugAutoStartRouteName;

/// Deprecated to avoid calls
@Deprecated('Deb only')
set debugAutoStartRouteName(String? routeName) =>
    _debugAutoStartRouteName = routeName;

class _MyHomePageState extends State<MyHomePage> {
  int get _itemCount => widget._items.length;

  @override
  void initState() {
    super.initState();

    Future.delayed(Duration.zero).then((_) async {
      if (mounted) {
        // Use it to auto start a test page
        if (debugAutoStartRouteName != null) {
          // only once

          // await Navigator.of(context).pushNamed(testExpRoute);
          // await Navigator.of(context).pushNamed(testRawRoute);
          final future =
              Navigator.of(context).pushNamed(debugAutoStartRouteName!);
          // ignore: deprecated_member_use_from_same_package
          debugAutoStartRouteName = null;
          await future;
          // await Navigator.of(context).pushNamed(testExceptionRoute);
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Center(
              child: Text('Sqflite demo', textAlign: TextAlign.center)),
        ),
        body:
            ListView.builder(itemBuilder: _itemBuilder, itemCount: _itemCount));
  }

  //new Center(child: new Text('Running on: $_platformVersion\n')),

  Widget _itemBuilder(BuildContext context, int index) {
    return MainItemWidget(widget._items[index], (MainItem item) {
      Navigator.of(context).pushNamed(item.route!);
    });
  }
}

Author: tekartik
Source Code: https://github.com/tekartik/sqflite
License: BSD-2-Clause License

#sqflite #flutter 

SQLite Plugin For Flutter. Supports IOS, android and MacOS
Snippet Coder

Snippet Coder

1646548788

SQLITE Ultimate Guide for Flutter Developers

SQLITE Ultimate Guide for Flutter Developers

In this video we will learn we will do CRUD operation with Flutter and SQLITE. In this video we will Add/Edit/Delete and List Data from SQLITE to Flutter Application.

Video Link : https://youtu.be/0qx70QE-yKo

#flutter #morioh #snippetcoder #sqflite

SQLITE Ultimate Guide for Flutter Developers

SQLite plugin for Flutter

sqflite_tizen

The Tizen implementation of sqflite.

Getting Started

This package is not an endorsed implementation of sqflite. Therefore, you have to include sqflite_tizen alongside sqflite as dependencies in your pubspec.yaml file.

dependencies:
  sqflite: ^2.0.1
  sqflite_tizen: ^0.1.0

Then you can import sqflite in your Dart code:

import 'package:sqflite/sqflite.dart';

For more details, see here.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add sqflite_tizen

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  sqflite_tizen: ^0.1.0

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

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:sqflite_tizen_example/batch_test_page.dart';
import 'package:sqflite_tizen_example/deprecated_test_page.dart';
import 'package:sqflite_tizen_example/exception_test_page.dart';
import 'package:sqflite_tizen_example/exp_test_page.dart';
import 'package:sqflite_tizen_example/manual_test_page.dart';
import 'package:sqflite_tizen_example/src/dev_utils.dart';

import 'model/main_item.dart';
import 'open_test_page.dart';
import 'raw_test_page.dart';
import 'slow_test_page.dart';
import 'src/main_item_widget.dart';
import 'todo_test_page.dart';
import 'type_test_page.dart';

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

/// Sqflite test app
class MyApp extends StatefulWidget {
  /// test app.
  const MyApp({Key? key}) : super(key: key);
  // This widget is the root of your application.

  @override
  _MyAppState createState() => _MyAppState();
}

/// Simple test page.
const String testRawRoute = '/test/simple';

/// Open test page.
const String testOpenRoute = '/test/open';

/// Slow test page.
const String testSlowRoute = '/test/slow';

/// Type test page.
const String testTypeRoute = '/test/type';

/// Batch test page.
const String testBatchRoute = '/test/batch';

/// `todo` example test page.
const String testTodoRoute = '/test/todo';

/// Exception test page.
const String testExceptionRoute = '/test/exception';

/// Manual test page.
const String testManualRoute = '/test/manual';

/// Experiment test page.
const String testExpRoute = '/test/exp';

/// Deprecated test page.
const String testDeprecatedRoute = '/test/deprecated';

class _MyAppState extends State<MyApp> {
  var routes = <String, WidgetBuilder>{
    '/test': (BuildContext context) => MyHomePage(),
    testRawRoute: (BuildContext context) => RawTestPage(),
    testOpenRoute: (BuildContext context) => OpenTestPage(),
    testSlowRoute: (BuildContext context) => SlowTestPage(),
    testTodoRoute: (BuildContext context) => TodoTestPage(),
    testTypeRoute: (BuildContext context) => TypeTestPage(),
    testManualRoute: (BuildContext context) => const ManualTestPage(),
    testBatchRoute: (BuildContext context) => BatchTestPage(),
    testExceptionRoute: (BuildContext context) => ExceptionTestPage(),
    testExpRoute: (BuildContext context) => ExpTestPage(),
    testDeprecatedRoute: (BuildContext context) => DeprecatedTestPage(),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Sqflite Demo',
        theme: ThemeData(
          // This is the theme of your application.
          //
          // Try running your application with 'flutter run'. You'll see
          // the application has a blue toolbar. Then, without quitting
          // the app, try changing the primarySwatch below to Colors.green
          // and then invoke 'hot reload' (press 'r' in the console where
          // you ran 'flutter run', or press Run > Hot Reload App in IntelliJ).
          // Notice that the counter didn't reset back to zero -- the application
          // is not restarted.
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Sqflite Demo Home Page'),
        routes: routes);
  }
}

/// App home menu page.
class MyHomePage extends StatefulWidget {
  /// App home menu page.
  MyHomePage({Key? key, this.title}) : super(key: key) {
    _items.add(
        MainItem('Raw tests', 'Raw SQLite operations', route: testRawRoute));
    _items.add(MainItem('Open tests', 'Open onCreate/onUpgrade/onDowngrade',
        route: testOpenRoute));
    _items
        .add(MainItem('Type tests', 'Test value types', route: testTypeRoute));
    _items.add(MainItem('Batch tests', 'Test batch operations',
        route: testBatchRoute));
    _items.add(
        MainItem('Slow tests', 'Lengthy operations', route: testSlowRoute));
    _items.add(MainItem(
        'Todo database example', 'Simple Todo-like database usage example',
        route: testTodoRoute));
    _items.add(MainItem('Exp tests', 'Experimental and various tests',
        route: testExpRoute));
    _items.add(MainItem('Exception tests', 'Tests that trigger exceptions',
        route: testExceptionRoute));
    _items.add(MainItem('Manual tests', 'Tests that requires manual execution',
        route: testManualRoute));
    _items.add(MainItem('Deprecated test',
        'Keeping some old tests for deprecated functionalities',
        route: testDeprecatedRoute));

    // Uncomment to view all logs
    //Sqflite.devSetDebugModeOn(true);
  }

  final List<MainItem> _items = [];

  /// Page title.
  final String? title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

String? _debugAutoStartRouteName;

/// (debug) set the route to start with.
String? get debugAutoStartRouteName => _debugAutoStartRouteName;

/// Deprecated to avoid calls
@Deprecated('Deb only')
set debugAutoStartRouteName(String? routeName) =>
    _debugAutoStartRouteName = routeName;

class _MyHomePageState extends State<MyHomePage> {
  int get _itemCount => widget._items.length;

  @override
  void initState() {
    super.initState();

    Future.delayed(Duration.zero).then((_) async {
      if (mounted) {
        // Use it to auto start a test page
        if (debugAutoStartRouteName != null) {
          // only once

          // await Navigator.of(context).pushNamed(testExpRoute);
          // await Navigator.of(context).pushNamed(testRawRoute);
          final future =
              Navigator.of(context).pushNamed(debugAutoStartRouteName!);
          // ignore: deprecated_member_use_from_same_package
          debugAutoStartRouteName = null;
          await future;
          // await Navigator.of(context).pushNamed(testExceptionRoute);
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Center(
              child: Text('Sqflite demo', textAlign: TextAlign.center)),
        ),
        body:
            ListView.builder(itemBuilder: _itemBuilder, itemCount: _itemCount));
  }

  //new Center(child: new Text('Running on: $_platformVersion\n')),

  Widget _itemBuilder(BuildContext context, int index) {
    return MainItemWidget(widget._items[index], (MainItem item) {
      Navigator.of(context).pushNamed(item.route!);
    });
  }
} 

Download Details:

Author: flutter-tizen

Source Code: https://github.com/flutter-tizen/plugins/tree/master/packages/sqflite

#flutter #sqflite 

SQLite plugin for Flutter

SQLite plugin for Flutter

SQLite plugin for Flutter. Supports iOS, Android and MacOS.

  • Support transactions and batches
  • Automatic version management during open
  • Helpers for insert/query/update/delete queries
  • DB operation executed in a background thread on iOS and Android
  • Linux/Windows/DartVM support using sqflite_common_ffi

Documentation

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add sqflite_common

With Flutter:

 $ flutter pub add sqflite_common

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  sqflite_common: ^2.0.1+1

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

Import it

Now in your Dart code, you can use:

import 'package:sqflite_common/sqflite_dev.dart';
import 'package:sqflite_common/sql.dart';
import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_common/utils/utils.dart'; 

example/main.dart

Future main() async {
  /// This package is not intended for direct use.
  ///
  /// See [sqflite](https://pub.dev/packages/sqflite)
} 

Download Details:

Author: tekartik

Source Code: https://github.com/tekartik/sqflite

#sqflite  #flutter 

SQLite plugin for Flutter

A Wrapper for Sembast and SQFlite to Enable Easy

FHIR_DB

This is really just a wrapper around Sembast_SQFLite - so all of the heavy lifting was done by Alex Tekartik. I highly recommend that if you have any questions about working with this package that you take a look at Sembast. He's also just a super nice guy, and even answered a question for me when I was deciding which sembast version to use. As usual, ResoCoder also has a good tutorial.

I have an interest in low-resource settings and thus a specific reason to be able to store data offline. To encourage this use, there are a number of other packages I have created based around the data format FHIR. FHIRยฎ is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7.

Using the Db

So, while not absolutely necessary, I highly recommend that you use some sort of interface class. This adds the benefit of more easily handling errors, plus if you change to a different database in the future, you don't have to change the rest of your app, just the interface.

I've used something like this in my projects:

class IFhirDb {
  IFhirDb();
  final ResourceDao resourceDao = ResourceDao();

  Future<Either<DbFailure, Resource>> save(Resource resource) async {
    Resource resultResource;
    try {
      resultResource = await resourceDao.save(resource);
    } catch (error) {
      return left(DbFailure.unableToSave(error: error.toString()));
    }
    return right(resultResource);
  }

  Future<Either<DbFailure, List<Resource>>> returnListOfSingleResourceType(
      String resourceType) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.getAllSortedById(resourceType: resourceType);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }

  Future<Either<DbFailure, List<Resource>>> searchFunction(
      String resourceType, String searchString, String reference) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.searchFor(resourceType, searchString, reference);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }
}

I like this because in case there's an i/o error or something, it won't crash your app. Then, you can call this interface in your app like the following:

final patient = Patient(
    resourceType: 'Patient',
    name: [HumanName(text: 'New Patient Name')],
    birthDate: Date(DateTime.now()),
);

final saveResult = await IFhirDb().save(patient);

This will save your newly created patient to the locally embedded database.

IMPORTANT: this database will expect that all previously created resources have an id. When you save a resource, it will check to see if that resource type has already been stored. (Each resource type is saved in it's own store in the database). It will then check if there is an ID. If there's no ID, it will create a new one for that resource (along with metadata on version number and creation time). It will save it, and return the resource. If it already has an ID, it will copy the the old version of the resource into a _history store. It will then update the metadata of the new resource and save that version into the appropriate store for that resource. If, for instance, we have a previously created patient:

{
    "resourceType": "Patient",
    "id": "fhirfli-294057507-6811107",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2020-10-16T19:41:28.054369Z"
    },
    "name": [
        {
            "given": ["New"],
            "family": "Patient"
        }
    ],
    "birthDate": "2020-10-16"
}

And we update the last name to 'Provider'. The above version of the patient will be kept in _history, while in the 'Patient' store in the db, we will have the updated version:

{
    "resourceType": "Patient",
    "id": "fhirfli-294057507-6811107",
    "meta": {
        "versionId": "2",
        "lastUpdated": "2020-10-16T19:45:07.316698Z"
    },
    "name": [
        {
            "given": ["New"],
            "family": "Provider"
        }
    ],
    "birthDate": "2020-10-16"
}

This way we can keep track of all previous version of all resources (which is obviously important in medicine).

For most of the interactions (saving, deleting, etc), they work the way you'd expect. The only difference is search. Because Sembast is NoSQL, we can search on any of the fields in a resource. If in our interface class, we have the following function:

  Future<Either<DbFailure, List<Resource>>> searchFunction(
      String resourceType, String searchString, String reference) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.searchFor(resourceType, searchString, reference);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }

You can search for all immunizations of a certain patient:

searchFunction(
        'Immunization', 'patient.reference', 'Patient/$patientId');

This function will search through all entries in the 'Immunization' store. It will look at all 'patient.reference' fields, and return any that match 'Patient/$patientId'.

The last thing I'll mention is that this is a password protected db, using AES-256 encryption (although it can also use Salsa20). Anytime you use the db, you have the option of using a password for encryption/decryption. Remember, if you setup the database using encryption, you will only be able to access it using that same password. When you're ready to change the password, you will need to call the update password function. If we again assume we created a change password method in our interface, it might look something like this:

class IFhirDb {
  IFhirDb();
  final ResourceDao resourceDao = ResourceDao();
  ...
    Future<Either<DbFailure, Unit>> updatePassword(String oldPassword, String newPassword) async {
    try {
      await resourceDao.updatePw(oldPassword, newPassword);
    } catch (error) {
      return left(DbFailure.unableToUpdatePassword(error: error.toString()));
    }
    return right(Unit);
  }

You don't have to use a password, and in that case, it will save the db file as plain text. If you want to add a password later, it will encrypt it at that time.

General Store

After using this for a while in an app, I've realized that it needs to be able to store data apart from just FHIR resources, at least on occasion. For this, I've added a second class for all versions of the database called GeneralDao. This is similar to the ResourceDao, but fewer options. So, in order to save something, it would look like this:

await GeneralDao().save('password', {'new':'map'});
await GeneralDao().save('password', {'new':'map'}, 'key');

The difference between these two options is that the first one will generate a key for the map being stored, while the second will store the map using the key provided. Both will return the key after successfully storing the map.

Other functions available include:

// deletes everything in the general store
await GeneralDao().deleteAllGeneral('password'); 

// delete specific entry
await GeneralDao().delete('password','key'); 

// returns map with that key
await GeneralDao().find('password', 'key'); 

FHIRยฎ is a registered trademark of Health Level Seven International (HL7) and its use does not constitute an endorsement of products by HL7ยฎ

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add fhir_db

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  fhir_db: ^0.4.3

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

Import it

Now in your Dart code, you can use:

import 'package:fhir_db/dstu2.dart';
import 'package:fhir_db/dstu2/fhir_db.dart';
import 'package:fhir_db/dstu2/general_dao.dart';
import 'package:fhir_db/dstu2/resource_dao.dart';
import 'package:fhir_db/encrypt/aes.dart';
import 'package:fhir_db/encrypt/salsa.dart';
import 'package:fhir_db/r4.dart';
import 'package:fhir_db/r4/fhir_db.dart';
import 'package:fhir_db/r4/general_dao.dart';
import 'package:fhir_db/r4/resource_dao.dart';
import 'package:fhir_db/r5.dart';
import 'package:fhir_db/r5/fhir_db.dart';
import 'package:fhir_db/r5/general_dao.dart';
import 'package:fhir_db/r5/resource_dao.dart';
import 'package:fhir_db/stu3.dart';
import 'package:fhir_db/stu3/fhir_db.dart';
import 'package:fhir_db/stu3/general_dao.dart';
import 'package:fhir_db/stu3/resource_dao.dart'; 

example/lib/main.dart

import 'package:fhir/r4.dart';
import 'package:fhir_db/r4.dart';
import 'package:flutter/material.dart';
import 'package:test/test.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final resourceDao = ResourceDao();

  // await resourceDao.updatePw('newPw', null);
  await resourceDao.deleteAllResources(null);

  group('Playing with passwords', () {
    test('Playing with Passwords', () async {
      final patient = Patient(id: Id('1'));

      final saved = await resourceDao.save(null, patient);

      await resourceDao.updatePw(null, 'newPw');
      final search1 = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search1[0]);

      await resourceDao.updatePw('newPw', 'newerPw');
      final search2 = await resourceDao.find('newerPw',
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search2[0]);

      await resourceDao.updatePw('newerPw', null);
      final search3 = await resourceDao.find(null,
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search3[0]);

      await resourceDao.deleteAllResources(null);
    });
  });

  final id = Id('12345');
  group('Saving Things:', () {
    test('Save Patient', () async {
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);
      final patient = Patient(id: id, name: [humanName]);
      final saved = await resourceDao.save(null, patient);

      expect(saved.id, id);

      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      final organization = Organization(id: id, name: 'FhirFli');
      final saved = await resourceDao.save(null, organization);

      expect(saved.id, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final observation1 = Observation(
        id: Id('obs1'),
        code: CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      final observation1 = Observation(
          id: Id('obs1'),
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final saved = await resourceDao.save(null, observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, Id('2'));
    });

    test('Save Observation2', () async {
      final observation2 = Observation(
        id: Id('obs2'),
        code: CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation2);

      expect(saved.id, Id('obs2'));

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final observation3 = Observation(
        id: Id('obs3'),
        code: CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation3);

      expect(saved.id, Id('obs3'));

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Finding Things:', () {
    test('Find 1st Patient', () async {
      final search = await resourceDao.find(null,
          resourceType: R4ResourceType.Patient, id: id);
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final search = await resourceDao.find(null,
          resourceType: R4ResourceType.Observation, id: Id('obs3'));

      expect(search.length, 1);

      expect(search[0].id, Id('obs3'));

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final search = await resourceDao.getResourceType(
        null,
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 3);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final search = await resourceDao.getAll(null);

      expect(search.length, 5);
      final patList = search.toList();
      final orgList = search.toList();
      final obsList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 1);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await resourceDao.delete(
          null, null, R4ResourceType.Observation, Id('obs2'), null, null);

      final search = await resourceDao.getResourceType(
        null,
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 2);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await resourceDao.deleteSingleType(null,
          resourceType: R4ResourceType.Observation);

      final search = await resourceDao.getAll(null);

      expect(search.length, 2);

      final patList = search.toList();
      final orgList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 1);

      expect(patList.length, 1);
    });

    test('Delete All Resources', () async {
      await resourceDao.deleteAllResources(null);

      final search = await resourceDao.getAll(null);

      expect(search.length, 0);
    });
  });

  group('Password - Saving Things:', () {
    test('Save Patient', () async {
      await resourceDao.updatePw(null, 'newPw');
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);
      final patient = Patient(id: id, name: [humanName]);
      final saved = await resourceDao.save('newPw', patient);

      expect(saved.id, id);

      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      final organization = Organization(id: id, name: 'FhirFli');
      final saved = await resourceDao.save('newPw', organization);

      expect(saved.id, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final observation1 = Observation(
        id: Id('obs1'),
        code: CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      final observation1 = Observation(
          id: Id('obs1'),
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final saved = await resourceDao.save('newPw', observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, Id('2'));
    });

    test('Save Observation2', () async {
      final observation2 = Observation(
        id: Id('obs2'),
        code: CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation2);

      expect(saved.id, Id('obs2'));

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final observation3 = Observation(
        id: Id('obs3'),
        code: CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation3);

      expect(saved.id, Id('obs3'));

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Password - Finding Things:', () {
    test('Find 1st Patient', () async {
      final search = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Patient, id: id);
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final search = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Observation, id: Id('obs3'));

      expect(search.length, 1);

      expect(search[0].id, Id('obs3'));

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final search = await resourceDao.getResourceType(
        'newPw',
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 3);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final search = await resourceDao.getAll('newPw');

      expect(search.length, 5);
      final patList = search.toList();
      final orgList = search.toList();
      final obsList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 1);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Password - Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await resourceDao.delete(
          'newPw', null, R4ResourceType.Observation, Id('obs2'), null, null);

      final search = await resourceDao.getResourceType(
        'newPw',
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 2);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await resourceDao.deleteSingleType('newPw',
          resourceType: R4ResourceType.Observation);

      final search = await resourceDao.getAll('newPw');

      expect(search.length, 2);

      final patList = search.toList();
      final orgList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 1);

      expect(patList.length, 1);
    });

    test('Delete All Resources', () async {
      await resourceDao.deleteAllResources('newPw');

      final search = await resourceDao.getAll('newPw');

      expect(search.length, 0);

      await resourceDao.updatePw('newPw', null);
    });
  });
} 

Download Details:

Author: MayJuun

Source Code: https://github.com/MayJuun/fhir/tree/main/fhir_db

#sqflite  #dart  #flutter 

A Wrapper for Sembast and SQFlite to Enable Easy
Terry  Tremblay

Terry Tremblay

1625195660

Flutter - Perform Update & Delete Operation in SQFLite Database | SQFLite | Series Finale

In this video we are going to work on the update and delete functionality of our Sqflite Database.

๐Ÿคฉ GitHub Link: https://github.com/DevStack06/Flutter-Tutorials

๐Ÿ”ฅ๐Ÿ”ฅ Flutter SQFLite : https://youtube.com/playlist?list=PLtIU0BH0pkKqOBOlYg-kglxiK9l5yj6P6
๐Ÿ”ฅ๐Ÿ”ฅ Flutter Chat App : https://youtube.com/playlist?list=PLtIU0BH0pkKovuEaNsrGE_Xd5Tz3m1zeC
๐Ÿ”ฅ๐Ÿ”ฅ Flutter with Firebase : https://youtube.com/playlist?list=PLtIU0BH0pkKrQZUFWENF_VXINhfv9WiIA
๐Ÿ”ฅ๐Ÿ”ฅ Flutter Blog App : https://youtube.com/playlist?list=PLtIU0BH0pkKoE2PBvgbHEBPAP-sd670VI
๐Ÿ”ฅ๐Ÿ”ฅ Flutter Model Class : https://youtube.com/playlist?list=PLtIU0BH0pkKpXE-1vC7NswofFPby1OYh-
๐Ÿ”ฅ๐Ÿ”ฅ Flutter Random : https://youtube.com/playlist?list=PLtIU0BH0pkKroOH-tDBhVRKCQTWonHRR

๐Ÿ‘‹ ๐Ÿ‘‹ Get the complete source code with some Cookies (You can support me) ๐Ÿช
๐Ÿ˜„ Patreon: https://www.patreon.com/DevStack06
๐Ÿ˜„ Buy me a Cofee: https://www.buymeacoffee.com/DevStack06
๐Ÿ˜„ DM me for UPI number

๐Ÿ˜‹ ๐Ÿ˜‹ For more updates Join me on Social media ๐Ÿ˜‹ ๐Ÿ˜‹
๐Ÿ’ป ๐Ÿ’ป Twitter -: https://twitter.com/DevStack06
๐Ÿ’ป ๐Ÿ’ป Instagram -:https://www.instagram.com/devstack06/
๐Ÿ’ป ๐Ÿ’ป FB Page-: https://www.facebook.com/devstack06
๐Ÿ’ป ๐Ÿ’ป GitHub-: https://github.com/DevStack06

PLEASE SUBSCRIBE AND SHARE THIS VIDEO!!! ๐Ÿ˜œ ๐Ÿ˜œ
THANKS FOR WATCHING!!! ๐Ÿ˜‹

#Flutter #Database #DB #SQFLIte #FlutterWithDB #PersitantData #DataHandling #FlutterDatabse #LocalDatabase #LocalDB #flutterdev #fluttercommunity #flutterapp #flutterbygoogle #flutterApps

#sqflite #database #sql #flutter

Flutter - Perform Update & Delete Operation in SQFLite Database | SQFLite  | Series Finale
Terry  Tremblay

Terry Tremblay

1624201703

(Flutter SQFLite) Fetch and Show The Data From SQFLite Database || Proper Way Of Handling DB #3

In this video we are going to work on the displaying the fetched data from SQFlite Database. Also we are going to manage the local state as well so We can show the current data in our UI.

This series will going to help you to understand, How you can handle the SQFLite database in the Futter Apps.

๐Ÿคฉ GitHub Link: https://github.com/DevStack06/Flutter-Tutorials

#flutter #sqflite #database

(Flutter SQFLite) Fetch and Show The Data From SQFLite Database || Proper Way Of Handling DB #3
Terry  Tremblay

Terry Tremblay

1623031791

How to Query in SQFLite using Flutter Apps | Flutter SQFLite Tutorials for beginners #2

In this video we are going to work on the Inserting and Reading the data from SQFLITE. Basically we will going to do the query on sqflite and insert and show data using flutter app.

๐Ÿคฉ GitHub Link: https://github.com/DevStack06/Flutter-Tutorials

#flutter #sqflite

How to Query in SQFLite using Flutter Apps | Flutter SQFLite Tutorials for beginners #2
Terry  Tremblay

Terry Tremblay

1622688442

Right way to use SQLite in Flutter Apps using SQFlite | Flutter SQFLite Tutorials for beginners #1

In this video we are going to setup the sqflite project in Flutter, we are going to create the Database handlers and Model Class which will help you to use the sqflite in Flutter.

#flutter #sqflite

Right way to use SQLite in Flutter Apps  using SQFlite | Flutter SQFLite Tutorials for beginners #1
Snippet Coder

Snippet Coder

1619607773

The Best way to learn SQFLITE in Flutter Development ๐Ÿ”ฅ

In this video, we learn The Best way to learn SQFLITE in Flutter Development. Beginner to Advanced in Just 30 Mins Video.

๐Ÿ“„Source Code Video
https://github.com/SnippetCoders/flutter_sqlite

๐Ÿ“ŽFlutter Plugins
https://pub.dev/packages/image_picker
https://pub.dev/packages/sqflite

๐ŸคStay Connected with me !
โœ” Instagram : https://www.instagram.com/SnippetCoder
โœ” Facebook : https://www.facebook.com/SnippetCoder
โœ” Twitter : https://www.twitter.com/SnippetCoder
โœ” Telegram : https://t.me/SnippetCoder
โœ” Github : https://github.com/SnippetCoders/

โ›„If you like my work , you can support me
โ˜‘๏ธPatreon : https://www.patreon.com/SnippetCoder
โ˜‘๏ธPayPal : http://www.paypal.me/iSharpeners
โ˜‘๏ธDM For UPI Number

PLEASE SUBSCRIBE AND SHARE THIS VIDEO!!!๐Ÿ˜ณ
THANKS FOR WATCHING!!!

#flutter #sqflite #snippetcoder #dart

The Best way to learn SQFLITE in Flutter Development ๐Ÿ”ฅ

Flutter SQLite example - CRUD operations with sqflite plugin ยป grokonez

https://grokonez.com/flutter/flutter-sqlite-example-crud-sqflite-example

Flutter SQLite example โ€“ CRUD operations with sqflite plugin

In this tutorial, we're gonna look at how to make SQLite CRUD Operations in a Flutter App using sqflite plugin.

More Practice:
- <a href="https://grokonez.com/android/flutter-sqlite-example-listview-crud-operations-sqflite-plugin">Flutter SQLite example โ€“ CRUD Operations with ListView & sqflite plugin</a>

With Firebase:
- <a href="https://grokonez.com/android/flutter-firebase-database-example-firebase-database-crud-listview">Flutter Firebase Database example โ€“ Firebase Database CRUD with ListView</a>
- <a href="https://grokonez.com/android/flutter-firestore-example-firebase-firestore-crud-operations-with-listview">Flutter Firestore example โ€“ Firebase Firestore CRUD with ListView</a>

More:
- <a href="https://grokonez.com/reactjs-jwt-springboot-token-authentication-example">Reactjs Jwt SpringBoot Token Authentication Example</a>
- <a href="https://grokonez.com/react-node-jwt-authentication-without-redux">React Node Jwt Authentication without Redux โ€“ using LocalStorage and Axios</a>
- <a href="https://grokonez.com/angular-11-elasticsearch-example-start-guide">Angular 11 ElasticSearch Example โ€“ Start Guide</a>
- <a href="https://grokonez.com/django-angular-10-crud-example">Django Angular 10 CRUD Example</a>
- <a href="https://grokonez.com/reactjs-crud-firebase-realtime-database-example">Reactjs CRUD Firebase Realtime Database Example</a>

<!--more-->

<iframe width="560" height="315" src="https://www.youtube.com/embed/7ZfInOvFsz0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h2>Flutter SQLite CRUD with sqflite</h2>
<h3>Import sqflite</h3>
Add <a href="https://github.com/tekartik/sqflite" target="_blank" rel="nofollow noopener noreferrer">sqflite plugin</a> to the dependencies section of our <em><strong>pubspec.yaml</strong></em>:
<pre><code class="language-java">
dependencies:
  sqflite: <latest_version>
</code></pre>
<h3>Open a Database</h3>
First, we find a location path for the database using <code>getDatabasesPath()</code> function. Then we call <code>openDatabase()</code> with <code>onCreate()</code> callback method where we populate data.

More at:

Flutter SQLite example โ€“ CRUD operations with sqflite plugin

https://grokonez.com/flutter/flutter-sqlite-example-crud-sqflite-example

#flutter #sqlite #sqflite

Flutter SQLite example - CRUD operations with sqflite plugin ยป grokonez
Snippet Coder

Snippet Coder

1614001531

The Best way to learn SQFLITE in Flutter Development | Beginner to Advanced

In this video, we learn The Best way to learn SQFLITE in Flutter Development. Beginner to Advanced in Just 30 Mins Video.

๐Ÿ“„Source Code Video
https://github.com/SnippetCoders/flutter_sqlite

๐Ÿ“ŽFlutter Plugins
https://pub.dev/packages/image_picker
https://pub.dev/packages/sqflite

๐ŸคStay Connected with me !
โœ” Instagram : https://www.instagram.com/SnippetCoder
โœ” Facebook : https://www.facebook.com/SnippetCoder
โœ” Twitter : https://www.twitter.com/SnippetCoder
โœ” Telegram : https://t.me/SnippetCoder
โœ” Github : https://github.com/SnippetCoders/

โ›„If you like my work , you can support me
โ˜‘๏ธPatreon : https://www.patreon.com/SnippetCoder
โ˜‘๏ธPayPal : http://www.paypal.me/iSharpeners
โ˜‘๏ธDM For UPI Number

PLEASE SUBSCRIBE AND SHARE THIS VIDEO!!!๐Ÿ˜ณ
THANKS FOR WATCHING!!!

Hive โค๏ธ Flutter - Lightweight & Fast NoSQL Database ๐Ÿ”ฅ| Learn in Just 15 Mins Video
https://youtu.be/HsPG7uqQRSs

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ Login/Logout System in Flutter With Rest API & WordPress ๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅ
https://youtu.be/yuHg4cSRdRQ

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅTHE BEST WAY TO LEARN SQFLITE IN FLUTTER DEVELOPMENT
https://youtu.be/Da2IfcEe90E

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅHIVE โค๏ธ FLUTTER - LIGHTWEIGHT & FAST NOSQL DATABASE ๐Ÿ”ฅ
https://youtu.be/HsPG7uqQRSs

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅFLUTTER - GROCERY APP - WORDPRESS - WOOCOMMERCE SERIES
https://youtu.be/zxPASMrB25U

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅFLUTTER NEWS APPLICATION USING GETX AND WORDPRESS CUSTOM API
https://youtu.be/-NQR89xwlK8

Tags and SEO Stuff :
#flutter #sqlite #snippetcoder flutter #fluttersqflite #fluttertutorialforbeginners #fluttersqlite #sqflite #fluttersql #fluttersqflitetutorial #flutterdatabase #fluttersqlitetutorial #flutterapp #sqlite #fluttersqflitecrud #fluttersqfliteexample #fluttersqflitedatabase #googleflutter #flutterdatabasesqlite #flutterdart #flutterlocaldatabase #fluttercrossplatform #fluttertutorials #flutterdatabasetutorial #fluttertutorial #snippetcoder

#flutter #sqflite #dart #snippetcoder

The Best way to learn SQFLITE in Flutter Development | Beginner to Advanced
Snippet Coder

Snippet Coder

1599568246

๐Ÿ”ฅ Flutter - WooCommerce Series ๐Ÿ”ฅ - EP 01 - WooCommerce Store Setup

This is the first episode of the Flutter - WooCommerce Series. In this Video learn how to Setup WooCommerce Store in just 10 min of Video.

Video : https://www.youtube.com/watch?v=zxPASMrB25U

Click ๐Ÿ”” to get notified about our latest videos

Subscribe & Help us to Grow :)

โœ” Subscribe
https://www.youtube.com/SnippetCoder

โœ” Twitter
https://twitter.com/SnippetCoder

If you like my work , you can support me by donating through PayPal:
http://www.paypal.me/iSharpeners

Source Code on Github-
Please watch the video till end.

The Best way to learn SQFLITE in Flutter Development ๐Ÿ”ฅ| Beginner to Advanced in Just 30 Mins Video
https://www.youtube.com/watch?v=Da2Ifโ€ฆ

#Flutter #sqflite #SnippetCoder #FlutterTutorial #Dart #Code #sqlite

Subscribe to the YouTube channel to learn about the latest technologies that will help you learn new things, Stay tuned for regular updates.


Stay Connected with me !
โœ” Subscribe to my Channel : - https://www.youtube.com/SnippetCoder
โœ” Instagram: https://www.instagram.com/SnippetCoder
โœ” Facebook: https://www.facebook.com/SnippetCoder
โœ” Twitter: https://www.twitter.com/SnippetCoder
โœ” Telegram: https://t.me/SnippetCoder
โœ” Github: https://github.com/SnippetCoders/

Thanks :)

๐Ÿ”ฅ Flutter - WooCommerce Series ๐Ÿ”ฅ - EP 01 - WooCommerce Store Setup

[Fixed] Flutter SQFLITE Insert,Query,Update and Delete

Hey Everyone This Is Prince From Desi Programmer, And In This Video We Are Going To Talk About SQFLITE With Flutter.

#sqflite #flutter

[Fixed] Flutter SQFLITE Insert,Query,Update and Delete