Skip to content

A high-performance relational database for Dart with multi-space architecture. Features smart caching, file/local storage, SQL & key-value persistent store.

License

Notifications You must be signed in to change notification settings

tocreator/tostore

Repository files navigation

ToStore

English | 简体中文 | 日本語 | 한국어 | Español | Português (Brasil) | Русский | Deutsch | Français | Italiano | Türkçe

pub package Build Status License: MIT Platform Dart Version

ToStore is a fast, high-performance relational database and storage engine for Dart/Flutter applications. it provides both SQL and key-value data persistence with smart caching and efficient indexing. The multi-space architecture enables concurrent query capabilities and optimized local storage.

Built with mobile apps in mind, ToStore offers:

  • Efficient data persistence through file storage and smart caching
  • Flexible query options with SQL, key-value, and schema-based tables
  • Advanced indexing system for fast data retrieval
  • Transaction support with ACID compliance
  • Multi-space architecture for data isolation
  • Concurrent access with optimized performance
  • Lightweight and easy to integrate
  • Automatic schema upgrades without manual version migration

Implemented purely in Dart, ToStore achieves exceptional performance through B+ tree indexing and intelligent caching strategies. Enterprise-grade features like transaction protection, automatic repair, and incremental backup ensure reliable data storage for your applications.

Why ToStore?

  • 🚀 Ultimate Performance:
    • B+ tree indexing with smart query optimization
    • Intelligent caching strategy with millisecond response
    • Non-blocking concurrent read/write with stable performance
  • 🔄 Smart Schema Evolution:
    • Automatic table structure upgrades through schemas
    • No more manual version-by-version migrations
    • Chainable schema modification API for complex changes
    • Zero-downtime schema updates
  • 🎯 Easy to Use:
    • Fluent chainable API design
    • Support for SQL/Map style queries
    • Smart type inference with complete code hints
    • Zero configuration, ready out of the box
  • 🔄 Innovative Architecture:
    • Multi-space data isolation, perfect for multi-user scenarios
    • Global data sharing solves configuration sync challenges
    • Support for nested transactions
    • On-demand space loading minimizes resource usage
    • Automatic storage data operations (upsert)
  • 🛡️ Enterprise-Grade Reliability:
    • ACID transaction protection ensures data consistency
    • Incremental backup mechanism with quick recovery
    • Data integrity validation with automatic error repair

Quick Start

Basic Setup

// Initialize database
final db = ToStore(
  version: 2, // every time the version number is increased, the data table structure in schemas will be automatically created or upgraded
  schemas: [
    // Simply define your latest schema, ToStore handles the upgrade automatically
    const TableSchema(
      name: 'users',
      primaryKey: 'id',
      fields: [
        FieldSchema(name: 'id', type: DataType.integer, nullable: false),
        FieldSchema(name: 'username', type: DataType.text, nullable: false),
        FieldSchema(name: 'email', type: DataType.text, nullable: false),
        FieldSchema(name: 'last_login', type: DataType.datetime),
      ],
      indexes: [
        IndexSchema(fields: ['username'], unique: true),
        IndexSchema(fields: ['email'], unique: true),
      ],
    ),
    const TableSchema(
      name: 'settings',
      primaryKey: 'key',
      isGlobal: true,
      fields: [
        FieldSchema(name: 'key', type: DataType.text, nullable: false),
        FieldSchema(name: 'value', type: DataType.text),
        FieldSchema(name: 'updated_at', type: DataType.datetime),
      ],
    ),
  ],
  // complex upgrade and migration can be done using db.updateSchema
  // if the number of data tables is small, it is recommended to directly adjust the data structure in schemas for automatic upgrade
  onUpgrade: (db, oldVersion, newVersion) async {
    if (oldVersion == 1) {
      await db.updateSchema('users') // update users table structure
          .addField("fans", type: DataType.array, comment: "fans") // add fans field
          .addIndex("follow",fields: ["follow", "username"]) // add follow index
          .removeField("last_login") // drop last_login field
          .modifyField('email', unique: true)   // more complex field modification
          .renameField("last_login", "last_login_time"); // rename last_login to last_login_time
    } else if (oldVersion == 2) {
      await db.updateSchema('users').renameTable('users_new'); // rename users table to users_new
    }
  },
);
await db.initialize(); // Optional, ensures database is fully initialized before operations

// Insert data
await db.insert('users', {
  'id': 1,
  'name': 'John',
  'age': 30,
});

// Update data
await db.update('users', {
  'age': 31,
}).where('id', '=', 1);

// Delete data
await db.delete('users').where('id', '!=', 1);

// Chain query with complex conditions
final users = await db.query('users')
    .where('age', '>', 20)
    .where('name', 'like', '%John%')
    .or()
    .whereIn('id', [1, 2, 3])
    .orderByDesc('age')
    .limit(10);

// Count records
final count = await db.query('users').count();

// SQL style query
final users = await db.queryBySql(
  'users',
  where: 'age > 20 AND name LIKE "%John%" OR id IN (1, 2, 3)',
  limit: 10
);

// Map style query
final users = await db.queryByMap(
  'users',
  where: {
    'age': {'>=': 30},
    'name': {'like': '%John%'},
  },
  orderBy: ['age'],
  limit: 10,
);

// Batch insert
await db.batchInsert('users', [
  {'id': 1, 'name': 'John', 'age': 30},
  {'id': 2, 'name': 'Mary', 'age': 25},
]);

Multi-Space Architecture

ToStore's multi-space architecture makes multi-user data management effortless:

// Switch to user space
await db.switchBaseSpace(spaceName: 'user_123');

// Query user data
final followers = await db.query('followers');

// Set or update key-value data, isGlobal: true means global data
await db.setValue('isAgreementPrivacy', true, isGlobal: true);

// Get global key-value data
final isAgreementPrivacy = await db.getValue('isAgreementPrivacy', isGlobal: true);

Upsert Data

// Automatically store data,Support batch upsert
await db.upsert('users', {'name': 'John'})
  .where('email', '=', '[email protected]');

// Auto insert or update based on primary key
await db.upsert('users', {
  'id': 1,
  'name': 'John',
  'email': '[email protected]'
});

Performance

In high-concurrency scenarios including batch writes, random read/writes, and conditional queries, ToStore demonstrates exceptional performance, far surpassing other mainstream databases available for Dart/Flutter.

More Features

  • 💫 Elegant chainable API
  • 🎯 Smart type inference
  • 📝 Complete code hints
  • 🔐 Automatic incremental backup
  • 🛡️ Data integrity validation
  • 🔄 Crash auto-recovery
  • 📦 Smart data compression
  • 📊 Automatic index optimization
  • 💾 Tiered caching strategy

Our goal isn't just to create another database. ToStore is extracted from the Toway framework to provide an alternative solution. If you're developing mobile applications, we recommend using the Toway framework, which offers a complete Flutter development ecosystem. With Toway, you won't need to deal with the underlying database directly - data requests, loading, storage, caching, and display are all handled automatically by the framework. For more information about the Toway framework, visit the Toway Repository

Documentation

Visit our Wiki for detailed documentation.

Support & Feedback

License

This project is licensed under the MIT License - see the LICENSE file for details.


If you find ToStore helpful, please give us a ⭐️

About

A high-performance relational database for Dart with multi-space architecture. Features smart caching, file/local storage, SQL & key-value persistent store.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published