aquabase 0.7.1
aquabase: ^0.7.1 copied to clipboard
Flutter SDK for Aquabase — encrypted real-time database with offline sync, tags, and binary transport.
example/main.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:aquabase/aquabase.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// ── Init ──────────────────────────────────────────────
final app = await Aquabase.init(
projectId: 'demo',
apiKey: 'aq_pub_demo',
// url: 'http://localhost:3280', // optional
// encrypted: true, // optional: encrypts ALL collections
// localSync: LocalSync.enabled, // optional: device-to-device LAN sync
);
// ── Auth ──────────────────────────────────────────────
final session = await app.auth.register('user@test.com', 'pass123');
debugPrint('Authenticated: ${session.uid}');
debugPrint('Restored session: ${app.authSession?.uid}');
// Existing user: await app.auth.login('user@test.com', 'pass123');
// OAuth: app.auth.signInWithOAuth(context, OAuthProvider.google) drives the
// whole flow in a bottom sheet over the in-app browser.
// ── Collections ───────────────────────────────────────
final users = app.collection('users'); // unencrypted, synced
final students = app.collection(
'_students',
local: true,
); // local, unencrypted
// ── Document CRUD ─────────────────────────────────────
await users.doc('u1').set({
'name': 'Ana',
'age': 25,
'createdAt': DateTime.now(),
});
// Reads return DocData: typed accessors that fall back when a field is
// absent, null or written with another type. `createdAt` was written as a
// DateTime and reads back as ms since epoch.
final user = await users.doc('u1').get();
debugPrint('User: ${user?.text('name')} (${user?.integer('createdAt')})');
await users.doc('u1').delete(localOnly: true);
final generatedId = await users.add({'name': 'Carlos', 'age': 30});
final scopedId = await users.add({
'name': 'Lucía',
'age': 28,
}, idPrefix: 'team_a_');
debugPrint('Generated IDs: $generatedId, $scopedId');
// ── Document write (auto-index) ──────────────────────
final scores = app.collection('scores');
await scores.doc('s1').set({
'studentId': 'u1',
'subject': 'math',
'score': 95,
'date': '2026-03-19',
});
// ── Equality query ────────────────────────────────────
final mathScores = await scores
.where('studentId', eq: 'u1')
.where('subject', eq: 'math')
.get();
debugPrint('Math scores: ${mathScores.docs.length} results');
// ── Range query ───────────────────────────────────────
// score entre 90 y 100 (inclusivo)
final highScores = await scores.where('score', from: 90, to: 100).get();
debugPrint('High scores: ${highScores.docs.length} results');
// fechas de marzo completo + filtro por studentId
final marchScores = await scores
.where('date', from: '2026-03-01', to: '2026-03-31')
.where('studentId', eq: 'u1')
.get();
debugPrint('March scores: ${marchScores.docs.length} results');
// ── isIn, count, exists and ordering ──────────────────
final selectedScores = await scores
.where('studentId', eq: 'u1')
.where('subject', isIn: ['math', 'science'])
.orderBy('score', descending: true)
.get();
final scoreCount = await scores.where('studentId', eq: 'u1').count();
final hasHighScore = await scores
.where('studentId', eq: 'u1')
.where('subject', isIn: ['math', 'science'])
.exists();
debugPrint(
'Selected: ${selectedScores.docs.length}, count: $scoreCount, exists: $hasHighScore',
);
// ── Cursor pagination ─────────────────────────────────
final firstPage = await scores.where('studentId', eq: 'u1').fetchPage(20);
if (firstPage.nextCursor != null) {
final secondPage = await scores
.where('studentId', eq: 'u1')
.fetchPage(20, firstPage.nextCursor);
debugPrint('Second page: ${secondPage.docs.length} results');
}
await for (final page in scores.where('studentId', eq: 'u1').paginate(20)) {
debugPrint('Page: ${page.docs.length} results');
}
// ── Watch doc ─────────────────────────────────────────
final sub1 = users.watch('u1').listen((data) {
debugPrint('User changed: $data');
});
// ── Watch query ───────────────────────────────────────
final sub2 = scores.where('subject', eq: 'math').watch().listen((results) {
debugPrint('Math scores: ${results.docs.length}');
});
// ── Bulk ops ──────────────────────────────────────────
await users.bulkSet({
'u1': {'name': 'Ana'},
'u2': {'name': 'Luis'},
'u3': {'name': 'Carlos'},
});
final bulk = await users.bulkGet(['u1', 'u2', 'u3']);
debugPrint('Bulk get: ${bulk.keys.length} docs');
await users.bulkDelete(['u2', 'u3']);
// ── Local collection ──────────────────────────────────
await students.doc('s1').set({'name': 'Ana', 'age': 12, 'grade': '6A'});
final student = await students.doc('s1').get();
debugPrint('Student: $student');
await students.bulkSet({
's1': {'name': 'Ana'},
's2': {'name': 'Luis'},
});
debugPrint('Local keys: ${students.localKeys()}');
// ── Storage ───────────────────────────────────────────
await app.storage.upload(
'avatars',
'photo.jpg',
await File('photo.jpg').readAsBytes(),
contentType: 'image/jpeg',
);
final photo = await app.storage.download('avatars', 'photo.jpg');
debugPrint('Downloaded: ${photo.length} bytes');
debugPrint('Public URL: ${app.storage.publicUrl('avatars', 'photo.jpg')}');
await app.storage.refresh('avatars', 'photo.jpg');
await app.storage.deleteFile('avatars', 'photo.jpg');
// ── Logs ──────────────────────────────────────────────
await app.logs.connect(); // also captures crashes
app.logs.info('db', 'User created');
app.logs.warn('auth', 'Failed login', source: '192.168.1.1');
app.logs.error('ws', 'Timeout');
final logs = await app.logs.query(
LogQueryOptions(
since:
DateTime.now()
.subtract(const Duration(hours: 1))
.microsecondsSinceEpoch *
1000,
minLevel: LogLevel.warn,
limit: 50,
),
);
debugPrint('Logs: ${logs.length} entries');
// ── Offline status ────────────────────────────────────
debugPrint('Connected: ${app.isConnected}');
debugPrint('Pending ops: ${app.pendingOfflineOps}');
await app.flushOfflineQueue();
app.connectionState.listen((online) => debugPrint('Connection: $online'));
app.deniedOperations.listen((id) => debugPrint('Denied: $id'));
app.flushResults.listen((result) => debugPrint('Flush: $result'));
app.backlogErrors.listen((event) {
debugPrint(
'Backlog: ${event.reason}, ${event.ops} ops, ${event.bytes} bytes',
);
});
// ── Cleanup ───────────────────────────────────────────
await sub1.cancel();
await sub2.cancel();
await app.clearAuth();
await app.dispose();
}