Skip to content

fodedoumbouya/cozy_data

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

40 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Cozy Data

Quickstart β€’ Documentation β€’ Sample Apps β€’ Pub.dev

CozyData:

  1. SwiftData for flutter.
  2. Support sqflite, sqlite3, inMemory data Storage

A Swift-inspired persistent data management solution for Flutter. CozyData provides a simple, powerful, and type-safe way to persist your app's models and automatically update your UI when data changes.

Features

  • πŸ”„ Automatic UI updates when data changes
  • πŸƒβ€β™‚οΈ Fast and efficient database operations
  • πŸ“± Built specifically for Flutter
  • πŸ’Ύ Simple persistent storage
  • πŸ” Powerful querying capabilities
  • 🎯 Type-safe data operations
  • 🧩 Easy-to-use annotations
  • πŸ“¦ Zero configuration needed

Quickstart

Add cozy_data to your pubspec.yaml:

1. Add to pubspec.yaml

dependencies:
  cozy_data: latest
  dart_mappable: latest

dev_dependencies:
  build_runner: any
  dart_mappable_builder: any

Usage

1. Define Your Models

import 'package:dart_mappable/dart_mappable.dart';
part 'recipe.mapper.dart';

@MappableClass()
class Recipe with RecipeMappable {
  final String persistentModelID; // This field is required for the cozy_data package to work
  String name;
  List<Ingredients>? ingredients;

  Recipe({required this.id, required this.name, this.ingredients});
}

@MappableClass()
class Ingredients with IngredientsMappable {
  String name;
  int? quantity;
  CookStyle cookStyle;
  Ingredients({required this.name, this.quantity, required this.cookStyle});
}

@MappableEnum()
enum CookStyle { bake, fry, boil }

and make sure to run dart run build_runner build after creating your model.

For more about the annotation please check dart_mappable.

2. Initialize CozyData

Initialize CozyData in your main.dart:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await CozyData.initialize(
      engine: CozyEngine.sqlite3,
      mappers: [RecipeMapper.ensureInitialized()]);

  runApp(MyApp());
}
 

the RecipeMapper will be generate in .mapper.dart file

Basic Operations

Save Data

final newRecipe = Recipe(
  persistentModelID: CozyId.cozyPersistentModelIDString(),
  name: 'salad',
  ingredients: [
    Ingredients(name: 'Tomato',quantity: 2,cookStyle: CookStyle.fry),
    Ingredients(name: 'Onion',quantity: 1,cookStyle: CookStyle.fry),
    Ingredients(name: 'Salt',quantity: 1,cookStyle: CookStyle.boil),
  ]
);

await CozyData.save<Recipe>(newRecipe);

Note: DataModel must be Specify <Recipe>

Delete Data

await CozyData.delete<Recipe>(model);

Update Data

await CozyData.update<Recipe>(updateRecipe);

Simple Query Data with UI Updates

class RecipeListView extends StatefulWidget {
  @override
  _RecipeListViewState createState() => _RecipeListViewState();
}

class _RecipeistViewState extends State<RecipeListView> {

final CozyQueryListener<Recipe> _recipeQuery = CozyData.queryListener<Recipe>();

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: _recipeQuery,
      builder: (context, _) {
        final recipes = _recipeQuery.items;
        return ListView.builder(
          itemCount: recipes.length,
          itemBuilder: (context, index) => ListTile(
            title: Text(recipes[index].name),
          ),
        );
      },
    );
  }

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

Fetch Data Once

final recipes = await CozyData.fetch<Recipe>();

Find by ID

final recipe = await CozyData.fetcById<Recipe>(persistentModelID: id);

Advanced Usage

The CozyQueryBuilder is a class used to construct complex SQL-like queries in a structured and programmatic way. It allows you to specify various components of a query, such as fields to group by, order by, having clauses, joins, limits, offsets, selected fields, subqueries, table aliases, and where conditions.

final customBuilder = CozyQueryBuilder(
// groupByFields: A list of fields by which the results should be grouped. In this case, it's an empty list, meaning no grouping is applied.
groupByFields: [],
// orderByFields: A list of fields by which the results should be ordered. It's also an empty list here, so no specific ordering is applied.
orderByFields: [],
// Conditions that filter the groups created by the groupBy clause. It's empty, indicating no such conditions.
havingClauses: [],
// joins: A list of join operations to combine rows from two or more tables based on a related column. No joins are specified here
joins: [],
// limit: The maximum number of records to return. Here, it's set to 10.
limit: 10,
// offset: The number of records to skip before starting to return records. It's set to 0, meaning no records are skipped.
offset: 0,
// selectFields: A list of fields to be selected in the query. It's empty, meaning all fields are selected
selectFields: [],
// subqueries: A list of subqueries to be included in the main query. It's empty, indicating no subqueries.
subqueries: [],
// tableAliases: A map of table aliases to be used in the query. It's an empty map here.
tableAliases: {},
// whereGroups: A list of conditions to filter the results. It's empty, meaning no filtering conditions are applied.
whereGroups: [],
);

Sorting and Filtering once

final recipes = await CozyData.fetch<Recipe>(customBuilder: customBuilder);

The CozyQueryController manages query operations for a CozyQueryListener. It allows adding where conditions, joins, order by fields, and custom queries to the listener.

Example usage:

  final controller = CozyQueryController<MyModel>();
  await controller.addWhere([PredicateGroup(predicates: [Predicate.equals('field', 'value')])]);
  await controller.addJoin([Join(table: 'other_table', condition: 'other_table.id = my_table.other_id')]);
  await controller.orderBy([OrderBy(field: 'created_at', direction: OrderDirection.desc)]);
  await controller.addCustomQuery(CozyQueryBuilder<MyModel>());
  await controller.reset();

Sorting and Filtering

// Controller
final CozyQueryController<Recipe> _queryController = CozyQueryController<Recipe>();

final CozyQueryListener<Recipe> _recipeQuery =
      CozyData.queryListener<Recipe>(controller: _queryController);

  await controller.addWhere([PredicateGroup(predicates: [Predicate.contains('field', 'value')])]);

Best Practices

  • Initialize Early: Call CozyData.initialize() as early as possible in your app lifecycle.

  • Dispose Queries: Always dispose of queries when they're no longer needed to prevent memory leaks.

Full Documentation

See the full documentation here or jump directly to the topic you are looking for:

About

A Swift-inspired persistent data management solution for Flutter

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages