Skip to content

Commit 96b164f

Browse files
committed
powersync based nutrition
1 parent e02bf6b commit 96b164f

File tree

10 files changed

+245
-254
lines changed

10 files changed

+245
-254
lines changed

lib/models/muscle.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ class Muscle {
3131
/// Watch all lists.
3232
static Stream<List<Muscle>> watchMuscles() {
3333
return db.watch('SELECT * FROM $tableMuscles ORDER BY id').map((results) {
34-
print('watchMuscles triggered' + results.toString());
3534
return results.map(Muscle.fromRow).toList(growable: false);
3635
});
3736
}

lib/models/nutrition/log.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:wger/models/nutrition/meal_item.dart';
2525
import 'package:wger/models/nutrition/nutritional_values.dart';
2626
import 'package:wger/models/schema.dart';
2727
import 'package:wger/powersync.dart';
28+
import 'package:powersync/sqlite3.dart' as sqlite;
2829

2930
part 'log.g.dart';
3031

@@ -80,13 +81,13 @@ class Log {
8081

8182
factory Log.fromRow(sqlite.Row row) {
8283
return Log(
83-
id: row['id'],
84-
mealId: row['meal_id'],
85-
ingredientId: row['ingredient_id'],
86-
weightUnitId: row['weight_unit_id'],
84+
id: int.parse(row['id']),
85+
mealId: int.parse(row['meal_id']),
86+
ingredientId: int.parse(row['ingredient_id']),
87+
weightUnitId: int.parse(row['weight_unit_id']),
8788
amount: row['amount'],
88-
planId: row['plan_id'],
89-
datetime: row['datetime'],
89+
planId: int.parse(row['plan_id']),
90+
datetime: DateTime.parse(row['datetime']),
9091
comment: row['comment'],
9192
);
9293
}
@@ -105,6 +106,12 @@ class Log {
105106

106107
return ingredient.nutritionalValues / (100 / weight);
107108
}
109+
110+
static Future<List<Log>> readByPlanId(int planId) async {
111+
final results = await db.getAll('SELECT * FROM $tableLogItems WHERE plan_id = ?', [planId]);
112+
return results.map((r) => Log.fromRow(r)).toList();
113+
}
114+
108115
/*
109116
Future<void> delete() async {
110117
await db.execute('DELETE FROM $logItemsTable WHERE id = ?', [id]);

lib/models/nutrition/meal.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import 'package:wger/helpers/misc.dart';
2424
import 'package:wger/models/nutrition/log.dart';
2525
import 'package:wger/models/nutrition/meal_item.dart';
2626
import 'package:wger/models/nutrition/nutritional_values.dart';
27+
import 'package:powersync/sqlite3.dart' as sqlite;
28+
import 'package:wger/models/schema.dart';
29+
import 'package:wger/powersync.dart';
2730

2831
part 'meal.g.dart';
2932

@@ -87,6 +90,15 @@ class Meal {
8790
// Boilerplate
8891
factory Meal.fromJson(Map<String, dynamic> json) => _$MealFromJson(json);
8992

93+
factory Meal.fromRow(sqlite.Row row) {
94+
return Meal(
95+
id: int.parse(row['id']),
96+
plan: int.parse(row['plan']),
97+
time: stringToTime(row['time']),
98+
name: row['name'],
99+
);
100+
}
101+
90102
Map<String, dynamic> toJson() => _$MealToJson(this);
91103

92104
Meal copyWith({
@@ -106,4 +118,14 @@ class Meal {
106118
diaryEntries: diaryEntries ?? this.diaryEntries,
107119
);
108120
}
121+
122+
static Future<Meal> read(int id) async {
123+
final results = await db.get('SELECT * FROM $tableMeals WHERE id = ?', [id]);
124+
return Meal.fromRow(results);
125+
}
126+
127+
static Future<List<Meal>> readByPlanId(int planId) async {
128+
final results = await db.getAll('SELECT * FROM $tableMeals WHERE plan_id = ?', [planId]);
129+
return results.map((r) => Meal.fromRow(r)).toList();
130+
}
109131
}

lib/models/nutrition/nutritional_plan.dart

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ import 'package:collection/collection.dart';
2020
import 'package:flutter/widgets.dart';
2121
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
2222
import 'package:json_annotation/json_annotation.dart';
23+
import 'package:powersync/sqlite3.dart' as sqlite;
2324
import 'package:wger/helpers/consts.dart';
2425
import 'package:wger/helpers/json.dart';
2526
import 'package:wger/models/nutrition/log.dart';
2627
import 'package:wger/models/nutrition/meal.dart';
2728
import 'package:wger/models/nutrition/meal_item.dart';
2829
import 'package:wger/models/nutrition/nutritional_goals.dart';
2930
import 'package:wger/models/nutrition/nutritional_values.dart';
31+
import 'package:wger/models/schema.dart';
32+
import 'package:wger/powersync.dart';
3033

3134
part 'nutritional_plan.g.dart';
3235

@@ -82,6 +85,55 @@ class NutritionalPlan {
8285
this.diaryEntries = diaryEntries ?? [];
8386
}
8487

88+
factory NutritionalPlan.fromRow(sqlite.Row row) {
89+
return NutritionalPlan(
90+
id: int.parse(row['id']),
91+
description: row['description'],
92+
creationDate: DateTime.parse(row['creation_date']),
93+
onlyLogging: row['only_logging'] == 1,
94+
goalEnergy: row['goal_energy'],
95+
goalProtein: row['goal_protein'],
96+
goalCarbohydrates: row['goal_carbohydrates'],
97+
goalFat: row['goal_fat'],
98+
goalFiber: row['goal_fiber'],
99+
);
100+
}
101+
102+
NutritionalPlan copyWith({
103+
int? id,
104+
String? description,
105+
DateTime? creationDate,
106+
bool? onlyLogging,
107+
num? goalEnergy,
108+
num? goalProtein,
109+
num? goalCarbohydrates,
110+
num? goalFat,
111+
num? goalFiber,
112+
List<Meal>? meals,
113+
List<Log>? diaryEntries,
114+
}) {
115+
return NutritionalPlan(
116+
id: id ?? this.id,
117+
description: description ?? this.description,
118+
creationDate: creationDate ?? this.creationDate,
119+
onlyLogging: onlyLogging ?? this.onlyLogging,
120+
goalEnergy: goalEnergy ?? this.goalEnergy,
121+
goalProtein: goalProtein ?? this.goalProtein,
122+
goalCarbohydrates: goalCarbohydrates ?? this.goalCarbohydrates,
123+
goalFat: goalFat ?? this.goalFat,
124+
goalFiber: goalFiber ?? this.goalFiber,
125+
meals: meals ?? this.meals,
126+
diaryEntries: diaryEntries ?? this.diaryEntries,
127+
);
128+
}
129+
130+
Future<NutritionalPlan> loadChildren() async {
131+
return copyWith(
132+
diaryEntries: await Log.readByPlanId(id!),
133+
meals: await Meal.readByPlanId(id!),
134+
);
135+
}
136+
85137
NutritionalPlan.empty() {
86138
creationDate = DateTime.now();
87139
description = '';
@@ -246,4 +298,65 @@ class NutritionalPlan {
246298
diaryEntries: diaryEntries.where((e) => e.mealId == null).toList(),
247299
);
248300
}
301+
302+
static Future<NutritionalPlan> read(int id) async {
303+
final row = await db.get('SELECT * FROM $tableNutritionPlans WHERE id = ?', [id]);
304+
return NutritionalPlan.fromRow(row).loadChildren();
305+
}
306+
307+
// this is a bit complicated.
308+
// what we need at the end of the day, is a stream of List<NutritionPlan>, where
309+
// a new value is emitted any time a plan is changed. But the plan is not just the plan record
310+
// we need to load data for Logs and Meals corresponding to the plan also.
311+
// so our options are:
312+
// 1) db.watch with a select query on plans; and extra dart code to load the logs/meals stuff,
313+
// but this only triggers for updates on the plans table, and misses logs/meals updates
314+
// 2) db.watch with a huge join query across all tables from which we need info,
315+
// so we have all the data in our resultset to create the datastructures with, but:
316+
// - this creates long rows with lots of duplicated data (e.g. all the plan data) for every row
317+
// which would only differ for e.g. the meal or the log item
318+
// - it would probably get a bit messy to parse the resultset into the datastructures
319+
// 3) the best of both worlds: load the data we need in dart at runtime, but explicitly
320+
// trigger our code execution when *any* of the relevant tables changes
321+
//
322+
static Stream<List<NutritionalPlan>> watchNutritionPlans() {
323+
return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async {
324+
final data = await db.getAll('SELECT * FROM $tableNutritionPlans ORDER BY creation_date');
325+
final futures = Future.wait(data.map((row) => NutritionalPlan.fromRow(row).loadChildren()));
326+
return (await futures).toList(growable: false);
327+
});
328+
}
329+
330+
static Stream<NutritionalPlan> watchNutritionPlan(int id) {
331+
return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async {
332+
final row = await db.get('SELECT * FROM $tableNutritionPlans WHERE id = ?', [id]);
333+
return NutritionalPlan.fromRow(row).loadChildren();
334+
});
335+
}
336+
337+
static Stream<NutritionalPlan> watchNutritionPlanLast() {
338+
return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async {
339+
final row =
340+
await db.get('SELECT * FROM $tableNutritionPlans ORDER BY creation_date DESC LIMIT 1');
341+
return NutritionalPlan.fromRow(row).loadChildren();
342+
});
343+
}
344+
/*
345+
static Stream<List<NutritionalPlan>> watchNutritionPlan(int id) {
346+
return db
347+
.watch('SELECT * FROM $tableNutritionPlans WHERE id = ?', parameters: [id]).map((results) {
348+
return results.map(NutritionalPlan.fromRow).toList(growable: false);
349+
});
350+
}
351+
352+
static Stream<List<NutritionalPlan>> watchNutritionPlans() {
353+
return db.watch('SELECT * FROM $tableNutritionPlans ORDER BY creation_date').map((results) {
354+
return results.map(NutritionalPlan.fromRow).toList(growable: false);
355+
});
356+
}
357+
*/
358+
359+
Future<void> delete() async {
360+
await db.execute('DELETE FROM $tableNutritionPlans WHERE id = ?', [id]);
361+
}
249362
}

lib/models/todo_list.dart

Lines changed: 0 additions & 100 deletions
This file was deleted.

0 commit comments

Comments
 (0)