feat: add alot
This commit is contained in:
@@ -1,9 +1,23 @@
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:drift_flutter/drift_flutter.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import '../models/payment_method.dart';
|
||||
import '../models/remote_command.dart';
|
||||
|
||||
part 'app_database.g.dart';
|
||||
|
||||
class PaymentMethodConverter extends TypeConverter<PaymentMethod, String> {
|
||||
const PaymentMethodConverter();
|
||||
|
||||
@override
|
||||
PaymentMethod fromSql(String fromDb) => PaymentMethod.fromValue(fromDb);
|
||||
|
||||
@override
|
||||
String toSql(PaymentMethod value) => value.value;
|
||||
}
|
||||
|
||||
@DataClassName('ProductRow')
|
||||
class Products extends Table {
|
||||
TextColumn get id => text()();
|
||||
@@ -32,12 +46,8 @@ class BarTabs extends Table {
|
||||
|
||||
TextColumn get customerName => text()();
|
||||
|
||||
TextColumn get status => text().withDefault(const Constant('open'))();
|
||||
|
||||
DateTimeColumn get openedAt => dateTime()();
|
||||
|
||||
DateTimeColumn get closedAt => dateTime().nullable()();
|
||||
|
||||
IntColumn get version => integer().withDefault(const Constant(0))();
|
||||
|
||||
@override
|
||||
@@ -90,7 +100,9 @@ class ClosedTabs extends Table {
|
||||
|
||||
DateTimeColumn get closedAt => dateTime()();
|
||||
|
||||
TextColumn get paymentMethod => text().withDefault(const Constant('cash'))();
|
||||
TextColumn get paymentMethod => text()
|
||||
.map(const PaymentMethodConverter())
|
||||
.withDefault(const Constant('cash'))();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {id};
|
||||
@@ -150,7 +162,8 @@ class RemoteSyncState extends Table {
|
||||
|
||||
DateTimeColumn get lastAttemptedSyncAt => dateTime().nullable()();
|
||||
|
||||
IntColumn get consecutiveFailureCount => integer().withDefault(const Constant(0))();
|
||||
IntColumn get consecutiveFailureCount =>
|
||||
integer().withDefault(const Constant(0))();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {deviceId};
|
||||
@@ -159,9 +172,12 @@ class RemoteSyncState extends Table {
|
||||
@DataClassName('ProcessedRemoteCommandRow')
|
||||
class ProcessedRemoteCommands extends Table {
|
||||
TextColumn get commandId => text()();
|
||||
|
||||
TextColumn get commandType => text()();
|
||||
|
||||
DateTimeColumn get processedAt => dateTime()();
|
||||
TextColumn get result => text()();
|
||||
|
||||
TextColumn get result => textEnum<CommandResult>()();
|
||||
|
||||
@override
|
||||
Set<Column> get primaryKey => {commandId};
|
||||
@@ -184,7 +200,7 @@ class AppDatabase extends _$AppDatabase {
|
||||
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
|
||||
|
||||
@override
|
||||
int get schemaVersion => 12;
|
||||
int get schemaVersion => 13;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration {
|
||||
@@ -269,16 +285,68 @@ class AppDatabase extends _$AppDatabase {
|
||||
await migrator.createTable(remoteSyncState);
|
||||
await migrator.createTable(processedRemoteCommands);
|
||||
}
|
||||
|
||||
if (from < 13) {
|
||||
// Tabs never close (only their items are archived), so the status
|
||||
// and closed_at columns were never anything but 'open' and null.
|
||||
if (await hasTableColumn('bar_tabs', 'status')) {
|
||||
await migrator.alterTable(TableMigration(barTabs));
|
||||
}
|
||||
await _backfillPurchaseRows();
|
||||
await _deleteOrphanedPurchaseRows();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Items added before purchases were tracked have fewer active purchase
|
||||
/// rows than their quantity. Insert the missing ones once, here, so the
|
||||
/// services can rely on `quantity == active purchases`.
|
||||
Future<void> _backfillPurchaseRows() async {
|
||||
const uuid = Uuid();
|
||||
|
||||
final rows = await customSelect(
|
||||
'SELECT i.id, i.quantity, i.created_at, '
|
||||
'(SELECT COUNT(*) FROM tab_item_purchases p '
|
||||
'WHERE p.tab_item_id = i.id AND p.removed_at IS NULL) AS active_count '
|
||||
'FROM tab_items i',
|
||||
readsFrom: {tabItems, tabItemPurchases},
|
||||
).get();
|
||||
|
||||
for (final row in rows) {
|
||||
final missing = row.read<int>('quantity') - row.read<int>('active_count');
|
||||
if (missing <= 0) continue;
|
||||
|
||||
final itemId = row.read<String>('id');
|
||||
final createdAt = row.read<DateTime>('created_at');
|
||||
|
||||
for (var index = 0; index < missing; index++) {
|
||||
await into(tabItemPurchases).insert(
|
||||
TabItemPurchasesCompanion.insert(
|
||||
id: uuid.v4(),
|
||||
tabItemId: itemId,
|
||||
purchasedAt: createdAt,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Foreign keys aren't enforced, so deleting tab items used to leave their
|
||||
/// purchase rows behind.
|
||||
Future<void> _deleteOrphanedPurchaseRows() async {
|
||||
await customStatement(
|
||||
'DELETE FROM tab_item_purchases '
|
||||
'WHERE tab_item_id NOT IN (SELECT id FROM tab_items)',
|
||||
);
|
||||
}
|
||||
|
||||
static QueryExecutor _openConnection() {
|
||||
return driftDatabase(
|
||||
name: 'kooltab',
|
||||
name: 'kooltap',
|
||||
native: const DriftNativeOptions(
|
||||
databaseDirectory: getApplicationSupportDirectory,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user