import 'package:drift/drift.dart'; import 'package:uuid/uuid.dart'; import '../database/app_database.dart'; import '../database/stock_queries.dart'; import '../models/product.dart'; export '../database/stock_queries.dart' show InsufficientStockException, ProductNotFoundException; abstract class ProductService { /// Active products, re-emitted whenever the products table changes. Stream> watchProducts(); Future> getProducts(); Future getProductById(String id); Future createProduct({ required String name, required String category, required int stockQuantity, required int lowStockThreshold, required int priceInCents, required String? imagePath, }); Future updateProduct(Product product); Future deleteProduct(String id); Future decreaseStock(String productId, int amount); Future increaseStock(String productId, int amount); } class DriftProductService implements ProductService { final AppDatabase database; final _uuid = const Uuid(); DriftProductService({required this.database}); Product _mapRowToProduct(ProductRow row) { return Product( id: row.id, name: row.name, category: row.category, stockQuantity: row.stockQuantity, lowStockThreshold: row.lowStockThreshold, priceInCents: row.priceInCents, imagePath: row.imagePath, active: row.active, ); } SimpleSelectStatement<$ProductsTable, ProductRow> _activeProductsQuery() { return database.select(database.products) ..where((product) => product.active.equals(true)) ..orderBy([(product) => OrderingTerm.asc(product.name)]); } @override Stream> watchProducts() { return _activeProductsQuery().map(_mapRowToProduct).watch(); } @override Future> getProducts() { return _activeProductsQuery().map(_mapRowToProduct).get(); } @override Future getProductById(String id) async { final query = database.select(database.products) ..where((product) => product.id.equals(id)); final row = await query.getSingleOrNull(); if (row == null) { return null; } return _mapRowToProduct(row); } @override Future createProduct({ required String name, required String category, required int stockQuantity, required int lowStockThreshold, required int priceInCents, required String? imagePath, }) async { await database .into(database.products) .insert( ProductsCompanion.insert( id: _uuid.v4(), name: name, category: category, stockQuantity: stockQuantity, lowStockThreshold: lowStockThreshold, priceInCents: priceInCents, imagePath: Value(imagePath), ), ); } @override Future updateProduct(Product product) async { final query = database.update(database.products) ..where((row) => row.id.equals(product.id)); await query.write( ProductsCompanion( name: Value(product.name), category: Value(product.category), stockQuantity: Value(product.stockQuantity), lowStockThreshold: Value(product.lowStockThreshold), priceInCents: Value(product.priceInCents), imagePath: Value(product.imagePath), active: Value(product.active), ), ); } @override Future deleteProduct(String id) async { final query = database.delete(database.products) ..where((product) => product.id.equals(id)); await query.go(); } @override Future decreaseStock(String productId, int amount) { return database.decreaseStock(productId, amount); } @override Future increaseStock(String productId, int amount) { return database.increaseStock(productId, amount); } }