laconic 3.0.0 copy "laconic: ^3.0.0" to clipboard
laconic: ^3.0.0 copied to clipboard

A Laravel-style SQL query builder for Dart, supporting MySQL, SQLite, and PostgreSQL.

example/laconic_example.dart

/// This example demonstrates how to use Laconic with a custom driver.
///
/// For practical usage, you'll want to use one of the official drivers:
/// - laconic_sqlite
/// - laconic_mysql
/// - laconic_postgresql
library;

import 'package:laconic/laconic.dart';

/// A simple in-memory driver for demonstration purposes.
class MockDriver implements DatabaseDriver {
  final List<Map<String, Object?>> _data = [];
  static final _grammar = _MockGrammar();

  @override
  SqlGrammar get grammar => _grammar;

  @override
  Future<List<LaconicResult>> select(
    String sql, [
    List<Object?> params = const [],
  ]) async {
    // In a real driver, this would execute the SQL query
    print('SELECT: $sql');
    print('Params: $params');
    return _data.map((row) => LaconicResult.fromMap(row)).toList();
  }

  @override
  Future<void> statement(String sql, [List<Object?> params = const []]) async {
    print('STATEMENT: $sql');
    print('Params: $params');
  }

  @override
  Future<int> affectingStatement(
    String sql, [
    List<Object?> params = const [],
  ]) async {
    print('AFFECTING STATEMENT: $sql');
    print('Params: $params');
    return 0;
  }

  @override
  Future<int> insertAndGetId(
    String sql, [
    List<Object?> params = const [],
  ]) async {
    print('INSERT: $sql');
    print('Params: $params');
    final id = _data.length + 1;
    _data.add({'id': id});
    return id;
  }

  @override
  Future<T> transaction<T>(Future<T> Function() action) async {
    print('BEGIN TRANSACTION');
    try {
      final result = await action();
      print('COMMIT');
      return result;
    } catch (e) {
      print('ROLLBACK');
      rethrow;
    }
  }

  @override
  Future<void> close() async {
    print('Connection closed');
  }
}

class _MockGrammar extends SqlGrammar {
  @override
  CompiledQuery compileSelect({
    required String table,
    required List<String> columns,
    required List<Map<String, dynamic>> wheres,
    required List<Map<String, dynamic>> joins,
    required List<Map<String, dynamic>> orders,
    required List<String> groups,
    required List<Map<String, dynamic>> havings,
    required bool distinct,
    int? limit,
    int? offset,
    List<Map<String, dynamic>> locks = const [],
  }) {
    final sql = StringBuffer('SELECT ');
    if (distinct) sql.write('DISTINCT ');
    sql.write(columns.isEmpty ? '*' : columns.join(', '));
    sql.write(' FROM $table');
    return CompiledQuery(sql: sql.toString(), bindings: []);
  }

  @override
  CompiledQuery compileInsert({
    required String table,
    required List<Map<String, Object?>> data,
  }) {
    return CompiledQuery(sql: 'INSERT INTO $table ...', bindings: []);
  }

  @override
  CompiledQuery compileUpdate({
    required String table,
    required Map<String, Object?> data,
    required List<Map<String, dynamic>> wheres,
  }) {
    return CompiledQuery(sql: 'UPDATE $table ...', bindings: []);
  }

  @override
  CompiledQuery compileDelete({
    required String table,
    required List<Map<String, dynamic>> wheres,
  }) {
    return CompiledQuery(sql: 'DELETE FROM $table ...', bindings: []);
  }

  @override
  CompiledQuery compileInsertGetId({
    required String table,
    required Map<String, Object?> data,
    String idColumn = 'id',
  }) {
    return CompiledQuery(
      sql: 'INSERT INTO $table ... RETURNING $idColumn',
      bindings: [],
    );
  }

  @override
  CompiledQuery compileIncrement({
    required String table,
    required String column,
    required int amount,
    Map<String, Object?>? extra,
    required List<Map<String, dynamic>> wheres,
  }) {
    return CompiledQuery(
      sql: 'UPDATE $table SET $column = $column + $amount ...',
      bindings: [],
    );
  }

  @override
  CompiledQuery compileDecrement({
    required String table,
    required String column,
    required int amount,
    Map<String, Object?>? extra,
    required List<Map<String, dynamic>> wheres,
  }) {
    return CompiledQuery(
      sql: 'UPDATE $table SET $column = $column - $amount ...',
      bindings: [],
    );
  }

  @override
  CompiledQuery compileTruncate({required String table}) {
    return CompiledQuery(sql: 'TRUNCATE $table', bindings: []);
  }

  @override
  CompiledQuery compileInsertOrIgnore({
    required String table,
    required List<Map<String, Object?>> data,
  }) {
    return CompiledQuery(sql: 'INSERT OR IGNORE INTO $table ...', bindings: []);
  }

  @override
  CompiledQuery compileUpsert({
    required String table,
    required List<Map<String, Object?>> data,
    required List<String> uniqueBy,
    List<String>? update,
  }) {
    return CompiledQuery(sql: 'UPSERT INTO $table ...', bindings: []);
  }
}

void main() async {
  // Create a Laconic instance with a custom driver
  final laconic = Laconic(
    MockDriver(),
    listen: (query) {
      print('Query executed: ${query.sql}');
    },
  );

  // Basic query
  print('--- Basic Query ---');
  await laconic.table('users').get();

  // Query with conditions
  print('\n--- Query with WHERE ---');
  await laconic.table('users').where('active', true).get();

  // Nested WHERE group
  print('\n--- Nested WHERE ---');
  await laconic.table('users')
      .where('status', 'active')
      .whereNested((q) => q.where('age', 18, comparator: '>=').orWhere('role', 'admin'))
      .get();

  // Debug: toSql() / dump()
  print('\n--- Debug ---');
  laconic.table('users').where('name', 'John').dump();
  print('SQL: ${laconic.table('users').where('age', 18, comparator: '>').toSql()}');

  // WHERE EXISTS
  print('\n--- WHERE EXISTS ---');
  await laconic.table('users u')
      .whereExists((q) => q.from('orders o').whereColumn('o.user_id', 'u.id'))
      .get();

  // Upsert
  print('\n--- Upsert ---');
  await laconic.table('users').upsert(
    [{'email': 'john@example.com', 'name': 'John Updated'}],
    uniqueBy: ['email'],
    update: ['name'],
  );

  // Locking
  print('\n--- Locking ---');
  await laconic.table('users').where('status', 'pending').lockForUpdate().get();

  // Union
  print('\n--- Union ---');
  await laconic.table('users').where('role', 'admin')
      .union((q) => q.from('users').where('role', 'moderator'))
      .get();

  // Insert and get ID
  print('\n--- Insert ---');
  final id = await laconic.table('users').insertGetId({
    'name': 'John',
    'email': 'john@example.com',
  });
  print('Inserted ID: $id');

  // Transaction
  print('\n--- Transaction ---');
  await laconic.transaction(() async {
    await laconic.table('users').insert([
      {'name': 'Jane'},
    ]);
  });

  // Chunking
  print('\n--- Chunking ---');
  await laconic.table('users').chunk(2, (batch) async {
    print('Processing ${batch.length} users...');
  });

  // Clone (reusable query scope)
  print('\n--- Clone ---');
  final activeQuery = laconic.table('users').where('active', true).select(['id', 'name']);
  final count = await activeQuery.clone().count();
  final results = await activeQuery.clone().get();
  print('Active users: $count (fetched ${results.length})');

  // Close connection
  await laconic.close();
}
1
likes
160
points
365
downloads

Documentation

API reference

Publisher

verified publishercals.xyz

Weekly Downloads

A Laravel-style SQL query builder for Dart, supporting MySQL, SQLite, and PostgreSQL.

Repository (GitHub)
View/report issues

License

MIT (license)

More

Packages that depend on laconic