perf(inventory): lazy list, photo thumbnails, indexes, debounced reload
Scale the local inventory to 10k+ varieties: - Render the list with ListView.builder over a flattened header/item model instead of building every tile upfront. - Store a small regenerable JPEG thumbnail per photo (schema v14) and use it for the 48px list avatar; full bytes stay for offer image hosting. Existing photos are backfilled lazily at startup. Thumbnail is local-only (excluded from CRDT sync and backups by the JSON codec). - Add indexes on varieties(is_deleted,is_draft), attachments(parent_type, parent_id,kind), lots(variety_id) via @TableIndex. - Debounce watchInventoryView (~250ms) so a burst of table writes triggers one reload, not seven. - cacheWidth/cacheHeight on the list avatar decode. - Scale test raised 3k -> 10k; migration test v13 -> v14.
This commit is contained in:
parent
2884ddd3c7
commit
3de01bd948
12 changed files with 5114 additions and 34 deletions
|
|
@ -32,7 +32,7 @@ class AppDatabase extends _$AppDatabase {
|
|||
|
||||
/// Current schema version; also stamped into interchange exports so an
|
||||
/// importer knows which app generation wrote the file (data-model §7).
|
||||
static const int currentSchemaVersion = 13;
|
||||
static const int currentSchemaVersion = 14;
|
||||
|
||||
@override
|
||||
int get schemaVersion => currentSchemaVersion;
|
||||
|
|
@ -196,9 +196,40 @@ class AppDatabase extends _$AppDatabase {
|
|||
await m.createTable(gardenOutcomes);
|
||||
}
|
||||
}
|
||||
// v14: scalability for large inventories. A local, regenerable [thumbnail]
|
||||
// BLOB on attachments (so the list never decodes full-resolution photos)
|
||||
// plus indexes on the columns the inventory list filters/joins on. All
|
||||
// additive and guarded, so a half-migrated dev database re-runs cleanly
|
||||
// (see the v7 note above). Existing thumbnails are backfilled lazily in
|
||||
// the background, not here (image decoding in a migration is slow/fragile).
|
||||
if (from < 14) {
|
||||
if (!await _hasColumn('attachments', 'thumbnail')) {
|
||||
await m.addColumn(attachments, attachments.thumbnail);
|
||||
}
|
||||
// Declared as `@TableIndex` on the tables, so a fresh install gets them
|
||||
// via createAll(); existing databases get them here. Guarded against a
|
||||
// half-migrated dev database (see the v7 note above).
|
||||
for (final index in [
|
||||
idxVarietiesDeletedDraft,
|
||||
idxAttachmentsParent,
|
||||
idxLotsVariety,
|
||||
]) {
|
||||
if (!await _hasIndex(index.entityName)) await m.create(index);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
/// Whether an index named [name] already exists — keeps the additive v14
|
||||
/// index creation idempotent against partially-migrated databases.
|
||||
Future<bool> _hasIndex(String name) async {
|
||||
final rows = await customSelect(
|
||||
"SELECT 1 FROM sqlite_master WHERE type = 'index' AND name = ?",
|
||||
variables: [Variable.withString(name)],
|
||||
).get();
|
||||
return rows.isNotEmpty;
|
||||
}
|
||||
|
||||
/// Whether a table named [table] already exists. Keeps the additive v8
|
||||
/// table creation idempotent against partially-migrated databases.
|
||||
Future<bool> _hasTable(String table) async {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue