diff --git a/flatpak/scripts/flatpak_shared.dart b/flatpak/scripts/flatpak_shared.dart index d3ad12ad..f9432f5c 100644 --- a/flatpak/scripts/flatpak_shared.dart +++ b/flatpak/scripts/flatpak_shared.dart @@ -44,9 +44,8 @@ class Icon { _fileExtension = path.split('.').last; } - String getFilename(String appId) => (type == _symbolicType) - ? '$appId-symbolic.$_fileExtension' - : '$appId.$_fileExtension'; + String getFilename(String appId) => + (type == _symbolicType) ? '$appId-symbolic.$_fileExtension' : '$appId.$_fileExtension'; } class GithubReleases { @@ -75,8 +74,7 @@ class GithubReleases { final releaseJsonContent = (await http.get(Uri( scheme: 'https', host: 'api.github.com', - path: - '/repos/$githubReleaseOrganization/$githubReleaseProject/releases'))) + path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases'))) .body; final decodedJson = jsonDecode(releaseJsonContent) as List; @@ -87,23 +85,19 @@ class GithubReleases { await Future.forEach(decodedJson, (dynamic releaseDynamic) async { final releaseMap = releaseDynamic as Map; - final releaseDateAndTime = - DateTime.parse(releaseMap['published_at'] as String); - final releaseDateString = - releaseDateAndTime.toIso8601String().split('T').first; + final releaseDateAndTime = DateTime.parse(releaseMap['published_at'] as String); + final releaseDateString = releaseDateAndTime.toIso8601String().split('T').first; if (latestReleaseAssetDate == null || (latestReleaseAssetDate?.compareTo(releaseDateAndTime) == -1)) { - final assets = - await _parseGithubReleaseAssets(releaseMap['assets'] as List); + final assets = await _parseGithubReleaseAssets(releaseMap['assets'] as List); if (assets != null) { _latestReleaseAssets = assets; latestReleaseAssetDate = releaseDateAndTime; } } - releases.add(Release( - version: releaseMap['name'] as String, date: releaseDateString)); + releases.add(Release(version: releaseMap['name'] as String, date: releaseDateString)); }); if (releases.isNotEmpty || canBeEmpty) { @@ -124,8 +118,7 @@ class GithubReleases { final downloadUrl = amMap['browser_download_url'] as String; final filename = amMap['name'] as String; final fileExtension = filename.substring(filename.indexOf('.') + 1); - final filenameWithoutExtension = - filename.substring(0, filename.indexOf('.')); + final filenameWithoutExtension = filename.substring(0, filename.indexOf('.')); final arch = filenameWithoutExtension.endsWith('aarch64') ? CPUArchitecture.aarch64 @@ -221,8 +214,7 @@ class FlatpakMeta { : _localReleases = localReleases, _localReleaseAssets = localReleaseAssets { if (githubReleaseOrganization != null && githubReleaseProject != null) { - _githubReleases = - GithubReleases(githubReleaseOrganization!, githubReleaseProject!); + _githubReleases = GithubReleases(githubReleaseOrganization!, githubReleaseProject!); } } @@ -231,20 +223,17 @@ class FlatpakMeta { final releases = List.empty(growable: true); if (addedTodaysVersion != null) { releases.add(Release( - version: addedTodaysVersion, - date: DateTime.now().toIso8601String().split("T").first)); + version: addedTodaysVersion, date: DateTime.now().toIso8601String().split("T").first)); } if (fetchReleasesFromGithub) { if (_githubReleases == null) { throw Exception( 'Metadata must include Github repository info if fetching releases from Github.'); } - releases.addAll( - await _githubReleases!.getReleases(addedTodaysVersion != null)); + releases.addAll(await _githubReleases!.getReleases(addedTodaysVersion != null)); } else { if (_localReleases == null && addedTodaysVersion == null) { - throw Exception( - 'Metadata must include releases if not fetching releases from Github.'); + throw Exception('Metadata must include releases if not fetching releases from Github.'); } if (_localReleases?.isNotEmpty ?? false) { releases.addAll(_localReleases!); @@ -253,8 +242,7 @@ class FlatpakMeta { return releases; } - Future?> getLatestReleaseAssets( - bool fetchReleasesFromGithub) async { + Future?> getLatestReleaseAssets(bool fetchReleasesFromGithub) async { if (fetchReleasesFromGithub) { if (_githubReleases == null) { throw Exception( @@ -263,8 +251,7 @@ class FlatpakMeta { return await _githubReleases!.getLatestReleaseAssets(); } else { if (_localReleases == null) { - throw Exception( - 'Metadata must include releases if not fetching releases from Github.'); + throw Exception('Metadata must include releases if not fetching releases from Github.'); } return _localReleaseAssets; } @@ -276,24 +263,20 @@ class FlatpakMeta { return FlatpakMeta( appId: json['appId'] as String, lowercaseAppName: json['lowercaseAppName'] as String, - githubReleaseOrganization: - json['githubReleaseOrganization'] as String?, + githubReleaseOrganization: json['githubReleaseOrganization'] as String?, githubReleaseProject: json['githubReleaseProject'] as String?, localReleases: skipLocalReleases ? null : (json['localReleases'] as List?)?.map((dynamic r) { final rMap = r as Map; - return Release( - version: rMap['version'] as String, - date: rMap['date'] as String); + return Release(version: rMap['version'] as String, date: rMap['date'] as String); }).toList(), localReleaseAssets: skipLocalReleases ? null : (json['localReleaseAssets'] as List?)?.map((dynamic ra) { final raMap = ra as Map; final archString = raMap['arch'] as String; - final arch = (archString == - CPUArchitecture.x86_64.flatpakArchCode) + final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode) ? CPUArchitecture.x86_64 : (archString == CPUArchitecture.aarch64.flatpakArchCode) ? CPUArchitecture.aarch64 @@ -302,11 +285,10 @@ class FlatpakMeta { throw Exception( 'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"'); } - final tarballFile = File( - '${jsonFile.parent.path}/${raMap['tarballPath'] as String}'); + final tarballFile = + File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}'); final tarballPath = tarballFile.absolute.path; - final preShasum = - Process.runSync('shasum', ['-a', '256', tarballPath]); + final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]); final shasum = preShasum.stdout.toString().split(' ').first; if (preShasum.exitCode != 0) { throw Exception(preShasum.stderr); @@ -321,17 +303,14 @@ class FlatpakMeta { appStreamPath: json['appStreamPath'] as String, desktopPath: json['desktopPath'] as String, icons: (json['icons'] as Map).entries.map((mapEntry) { - return Icon( - type: mapEntry.key as String, path: mapEntry.value as String); + return Icon(type: mapEntry.key as String, path: mapEntry.value as String); }).toList(), freedesktopRuntime: json['freedesktopRuntime'] as String, buildCommandsAfterUnpack: (json['buildCommandsAfterUnpack'] as List?) ?.map((dynamic bc) => bc as String) .toList(), extraModules: json['extraModules'] as List?, - finishArgs: (json['finishArgs'] as List) - .map((dynamic fa) => fa as String) - .toList()); + finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList()); } catch (e) { throw Exception('Could not parse JSON file, due to this error:\n$e'); } diff --git a/flatpak/scripts/manifest_generator.dart b/flatpak/scripts/manifest_generator.dart index 8957a3d1..254bb1ae 100644 --- a/flatpak/scripts/manifest_generator.dart +++ b/flatpak/scripts/manifest_generator.dart @@ -26,8 +26,7 @@ void main(List arguments) async { 'You must run this script with a metadata file argument, using the --meta flag.'); } if (arguments.length == metaIndex + 1) { - throw Exception( - 'The --meta flag must be followed by the path to the metadata file.'); + throw Exception('The --meta flag must be followed by the path to the metadata file.'); } final metaFile = File(arguments[metaIndex + 1]); @@ -37,23 +36,19 @@ void main(List arguments) async { final fetchFromGithub = arguments.contains('--github'); - final meta = - FlatpakMeta.fromJson(metaFile, skipLocalReleases: fetchFromGithub); + final meta = FlatpakMeta.fromJson(metaFile, skipLocalReleases: fetchFromGithub); - final outputDir = - Directory('${Directory.current.path}/flatpak_generator_exports'); + final outputDir = Directory('${Directory.current.path}/flatpak_generator_exports'); outputDir.createSync(); final manifestGenerator = FlatpakManifestGenerator(meta); - final manifestContent = - await manifestGenerator.generateFlatpakManifest(fetchFromGithub); + final manifestContent = await manifestGenerator.generateFlatpakManifest(fetchFromGithub); final manifestPath = '${outputDir.path}/${meta.appId}.json'; final manifestFile = File(manifestPath); manifestFile.writeAsStringSync(manifestContent); print('Generated $manifestPath'); - final flathubJsonContent = - await manifestGenerator.generateFlathubJson(fetchFromGithub); + final flathubJsonContent = await manifestGenerator.generateFlathubJson(fetchFromGithub); if (flathubJsonContent != null) { final flathubJsonPath = '${outputDir.path}/flathub.json'; final flathubJsonFile = File(flathubJsonPath); @@ -132,8 +127,7 @@ class FlatpakManifestGenerator { const encoder = JsonEncoder.withIndent(' '); - final onlyArchListInput = - fetchFromGithub ? _githubArchSupport! : _localArchSupport!; + final onlyArchListInput = fetchFromGithub ? _githubArchSupport! : _localArchSupport!; final onlyArchList = List.empty(growable: true); for (final e in onlyArchListInput.entries) { @@ -149,8 +143,7 @@ class FlatpakManifestGenerator { } } - void _lazyGenerateArchSupportMap( - bool fetchFromGithub, List assets) { + void _lazyGenerateArchSupportMap(bool fetchFromGithub, List assets) { if (fetchFromGithub) { if (_githubArchSupport == null) { _githubArchSupport = { diff --git a/integration_test/3_gym_mode.dart b/integration_test/3_gym_mode.dart index 2d134372..51ccbc75 100644 --- a/integration_test/3_gym_mode.dart +++ b/integration_test/3_gym_mode.dart @@ -20,8 +20,8 @@ Widget createGymModeScreen({locale = 'en'}) { final mockExerciseProvider = MockExercisesProvider(); - when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); // bench press - when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); // side raises + when(mockExerciseProvider.findExerciseById(1)).thenReturn(bases[0]); // bench press + when(mockExerciseProvider.findExerciseById(6)).thenReturn(bases[5]); // side raises //when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); // crunches //when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift diff --git a/lib/core/locator.dart b/lib/core/locator.dart new file mode 100644 index 00000000..62aeef7e --- /dev/null +++ b/lib/core/locator.dart @@ -0,0 +1,44 @@ +import 'dart:developer'; +import 'dart:io'; + +import 'package:drift/native.dart'; +import 'package:get_it/get_it.dart'; +import 'package:wger/database/exercises/exercise_database.dart'; +import 'package:wger/database/ingredients/ingredients_database.dart'; + +final locator = GetIt.asNewInstance(); + +class ServiceLocator { + factory ServiceLocator() => _singleton; + + ServiceLocator._internal(); + + static final ServiceLocator _singleton = ServiceLocator._internal(); + + Future _initDB() async { + ExerciseDatabase exerciseDB; + IngredientDatabase ingredientDB; + // final exerciseDB = ExerciseDatabase(); + // final ingredientDB = IngredientDatabase(); + + if (Platform.environment.containsKey('FLUTTER_TEST')) { + exerciseDB = ExerciseDatabase.inMemory(NativeDatabase.memory()); + ingredientDB = IngredientDatabase.inMemory(NativeDatabase.memory()); + } else { + exerciseDB = ExerciseDatabase(); + ingredientDB = IngredientDatabase(); + } + + locator.registerSingleton(exerciseDB); + locator.registerSingleton(ingredientDB); + } + + Future configure() async { + try { + await _initDB(); + } catch (e, _) { + log(e.toString()); + rethrow; + } + } +} diff --git a/lib/database/exercises/exercise_database.dart b/lib/database/exercises/exercise_database.dart new file mode 100644 index 00000000..b68d1980 --- /dev/null +++ b/lib/database/exercises/exercise_database.dart @@ -0,0 +1,85 @@ +import 'dart:io'; + +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'package:wger/database/exercises/type_converters.dart'; +import 'package:wger/models/exercises/category.dart'; +import 'package:wger/models/exercises/equipment.dart'; +import 'package:wger/models/exercises/language.dart'; +import 'package:wger/models/exercises/muscle.dart'; + +part 'exercise_database.g.dart'; + +@DataClassName('ExerciseTable') +class Exercises extends Table { + IntColumn get id => integer()(); + + TextColumn get data => text()(); + + // TextColumn get data => text().map(const ExerciseBaseConverter())(); + + DateTimeColumn get lastUpdate => dateTime()(); + + /// The date when the exercise was last fetched from the API. While we know + /// when the exercise itself was last updated in `lastUpdate`, we can save + /// ourselves a lot of requests if we don't check too often + DateTimeColumn get lastFetched => dateTime()(); +} + +@DataClassName('MuscleTable') +class Muscles extends Table { + IntColumn get id => integer()(); + + TextColumn get data => text().map(const MuscleConverter())(); +} + +@DataClassName('CategoryTable') +class Categories extends Table { + IntColumn get id => integer()(); + + TextColumn get data => text().map(const ExerciseCategoryConverter())(); +} + +@DataClassName('LanguagesTable') +class Languages extends Table { + IntColumn get id => integer()(); + + TextColumn get data => text().map(const LanguageConverter())(); +} + +@DataClassName('EquipmentTable') +class Equipments extends Table { + IntColumn get id => integer()(); + + TextColumn get data => text().map(const EquipmentConverter())(); +} + +@DriftDatabase(tables: [Exercises, Muscles, Equipments, Categories, Languages]) +class ExerciseDatabase extends _$ExerciseDatabase { + ExerciseDatabase() : super(_openConnection()); + + // Named constructor for creating in-memory database + ExerciseDatabase.inMemory(super.e); + + @override + // TODO: implement schemaVersion + int get schemaVersion => 1; + + Future deleteEverything() { + return transaction(() async { + for (final table in allTables) { + await delete(table).go(); + } + }); + } +} + +LazyDatabase _openConnection() { + return LazyDatabase(() async { + final dbFolder = await getApplicationCacheDirectory(); + final file = File(p.join(dbFolder.path, 'exercises.sqlite')); + return NativeDatabase.createInBackground(file); + }); +} diff --git a/lib/database/exercises/exercise_database.g.dart b/lib/database/exercises/exercise_database.g.dart new file mode 100644 index 00000000..3e09c0ef --- /dev/null +++ b/lib/database/exercises/exercise_database.g.dart @@ -0,0 +1,968 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'exercise_database.dart'; + +// ignore_for_file: type=lint +class $ExercisesTable extends Exercises with TableInfo<$ExercisesTable, ExerciseTable> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $ExercisesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumn data = GeneratedColumn('data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true); + static const VerificationMeta _lastUpdateMeta = const VerificationMeta('lastUpdate'); + @override + late final GeneratedColumn lastUpdate = GeneratedColumn( + 'last_update', aliasedName, false, + type: DriftSqlType.dateTime, requiredDuringInsert: true); + static const VerificationMeta _lastFetchedMeta = const VerificationMeta('lastFetched'); + @override + late final GeneratedColumn lastFetched = GeneratedColumn( + 'last_fetched', aliasedName, false, + type: DriftSqlType.dateTime, requiredDuringInsert: true); + @override + List get $columns => [id, data, lastUpdate, lastFetched]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'exercises'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + if (data.containsKey('data')) { + context.handle(_dataMeta, this.data.isAcceptableOrUnknown(data['data']!, _dataMeta)); + } else if (isInserting) { + context.missing(_dataMeta); + } + if (data.containsKey('last_update')) { + context.handle( + _lastUpdateMeta, lastUpdate.isAcceptableOrUnknown(data['last_update']!, _lastUpdateMeta)); + } else if (isInserting) { + context.missing(_lastUpdateMeta); + } + if (data.containsKey('last_fetched')) { + context.handle(_lastFetchedMeta, + lastFetched.isAcceptableOrUnknown(data['last_fetched']!, _lastFetchedMeta)); + } else if (isInserting) { + context.missing(_lastFetchedMeta); + } + return context; + } + + @override + Set get $primaryKey => const {}; + @override + ExerciseTable map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return ExerciseTable( + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, + data: attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}data'])!, + lastUpdate: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}last_update'])!, + lastFetched: attachedDatabase.typeMapping + .read(DriftSqlType.dateTime, data['${effectivePrefix}last_fetched'])!, + ); + } + + @override + $ExercisesTable createAlias(String alias) { + return $ExercisesTable(attachedDatabase, alias); + } +} + +class ExerciseTable extends DataClass implements Insertable { + final int id; + final String data; + final DateTime lastUpdate; + + /// The date when the exercise was last fetched from the API. While we know + /// when the exercise itself was last updated in `lastUpdate`, we can save + /// ourselves a lot of requests if we don't check too often + final DateTime lastFetched; + const ExerciseTable( + {required this.id, required this.data, required this.lastUpdate, required this.lastFetched}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['data'] = Variable(data); + map['last_update'] = Variable(lastUpdate); + map['last_fetched'] = Variable(lastFetched); + return map; + } + + ExercisesCompanion toCompanion(bool nullToAbsent) { + return ExercisesCompanion( + id: Value(id), + data: Value(data), + lastUpdate: Value(lastUpdate), + lastFetched: Value(lastFetched), + ); + } + + factory ExerciseTable.fromJson(Map json, {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return ExerciseTable( + id: serializer.fromJson(json['id']), + data: serializer.fromJson(json['data']), + lastUpdate: serializer.fromJson(json['lastUpdate']), + lastFetched: serializer.fromJson(json['lastFetched']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'data': serializer.toJson(data), + 'lastUpdate': serializer.toJson(lastUpdate), + 'lastFetched': serializer.toJson(lastFetched), + }; + } + + ExerciseTable copyWith({int? id, String? data, DateTime? lastUpdate, DateTime? lastFetched}) => + ExerciseTable( + id: id ?? this.id, + data: data ?? this.data, + lastUpdate: lastUpdate ?? this.lastUpdate, + lastFetched: lastFetched ?? this.lastFetched, + ); + @override + String toString() { + return (StringBuffer('ExerciseTable(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('lastUpdate: $lastUpdate, ') + ..write('lastFetched: $lastFetched') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, data, lastUpdate, lastFetched); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is ExerciseTable && + other.id == this.id && + other.data == this.data && + other.lastUpdate == this.lastUpdate && + other.lastFetched == this.lastFetched); +} + +class ExercisesCompanion extends UpdateCompanion { + final Value id; + final Value data; + final Value lastUpdate; + final Value lastFetched; + final Value rowid; + const ExercisesCompanion({ + this.id = const Value.absent(), + this.data = const Value.absent(), + this.lastUpdate = const Value.absent(), + this.lastFetched = const Value.absent(), + this.rowid = const Value.absent(), + }); + ExercisesCompanion.insert({ + required int id, + required String data, + required DateTime lastUpdate, + required DateTime lastFetched, + this.rowid = const Value.absent(), + }) : id = Value(id), + data = Value(data), + lastUpdate = Value(lastUpdate), + lastFetched = Value(lastFetched); + static Insertable custom({ + Expression? id, + Expression? data, + Expression? lastUpdate, + Expression? lastFetched, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (data != null) 'data': data, + if (lastUpdate != null) 'last_update': lastUpdate, + if (lastFetched != null) 'last_fetched': lastFetched, + if (rowid != null) 'rowid': rowid, + }); + } + + ExercisesCompanion copyWith( + {Value? id, + Value? data, + Value? lastUpdate, + Value? lastFetched, + Value? rowid}) { + return ExercisesCompanion( + id: id ?? this.id, + data: data ?? this.data, + lastUpdate: lastUpdate ?? this.lastUpdate, + lastFetched: lastFetched ?? this.lastFetched, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (data.present) { + map['data'] = Variable(data.value); + } + if (lastUpdate.present) { + map['last_update'] = Variable(lastUpdate.value); + } + if (lastFetched.present) { + map['last_fetched'] = Variable(lastFetched.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ExercisesCompanion(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('lastUpdate: $lastUpdate, ') + ..write('lastFetched: $lastFetched, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $MusclesTable extends Muscles with TableInfo<$MusclesTable, MuscleTable> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $MusclesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumnWithTypeConverter data = GeneratedColumn( + 'data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter($MusclesTable.$converterdata); + @override + List get $columns => [id, data]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'muscles'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + context.handle(_dataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => const {}; + @override + MuscleTable map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return MuscleTable( + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, + data: $MusclesTable.$converterdata.fromSql( + attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}data'])!), + ); + } + + @override + $MusclesTable createAlias(String alias) { + return $MusclesTable(attachedDatabase, alias); + } + + static TypeConverter $converterdata = const MuscleConverter(); +} + +class MuscleTable extends DataClass implements Insertable { + final int id; + final Muscle data; + const MuscleTable({required this.id, required this.data}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + { + map['data'] = Variable($MusclesTable.$converterdata.toSql(data)); + } + return map; + } + + MusclesCompanion toCompanion(bool nullToAbsent) { + return MusclesCompanion( + id: Value(id), + data: Value(data), + ); + } + + factory MuscleTable.fromJson(Map json, {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return MuscleTable( + id: serializer.fromJson(json['id']), + data: serializer.fromJson(json['data']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'data': serializer.toJson(data), + }; + } + + MuscleTable copyWith({int? id, Muscle? data}) => MuscleTable( + id: id ?? this.id, + data: data ?? this.data, + ); + @override + String toString() { + return (StringBuffer('MuscleTable(') + ..write('id: $id, ') + ..write('data: $data') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, data); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is MuscleTable && other.id == this.id && other.data == this.data); +} + +class MusclesCompanion extends UpdateCompanion { + final Value id; + final Value data; + final Value rowid; + const MusclesCompanion({ + this.id = const Value.absent(), + this.data = const Value.absent(), + this.rowid = const Value.absent(), + }); + MusclesCompanion.insert({ + required int id, + required Muscle data, + this.rowid = const Value.absent(), + }) : id = Value(id), + data = Value(data); + static Insertable custom({ + Expression? id, + Expression? data, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (data != null) 'data': data, + if (rowid != null) 'rowid': rowid, + }); + } + + MusclesCompanion copyWith({Value? id, Value? data, Value? rowid}) { + return MusclesCompanion( + id: id ?? this.id, + data: data ?? this.data, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (data.present) { + map['data'] = Variable($MusclesTable.$converterdata.toSql(data.value)); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('MusclesCompanion(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $EquipmentsTable extends Equipments with TableInfo<$EquipmentsTable, EquipmentTable> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $EquipmentsTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumnWithTypeConverter data = GeneratedColumn( + 'data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter($EquipmentsTable.$converterdata); + @override + List get $columns => [id, data]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'equipments'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + context.handle(_dataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => const {}; + @override + EquipmentTable map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return EquipmentTable( + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, + data: $EquipmentsTable.$converterdata.fromSql( + attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}data'])!), + ); + } + + @override + $EquipmentsTable createAlias(String alias) { + return $EquipmentsTable(attachedDatabase, alias); + } + + static TypeConverter $converterdata = const EquipmentConverter(); +} + +class EquipmentTable extends DataClass implements Insertable { + final int id; + final Equipment data; + const EquipmentTable({required this.id, required this.data}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + { + map['data'] = Variable($EquipmentsTable.$converterdata.toSql(data)); + } + return map; + } + + EquipmentsCompanion toCompanion(bool nullToAbsent) { + return EquipmentsCompanion( + id: Value(id), + data: Value(data), + ); + } + + factory EquipmentTable.fromJson(Map json, {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return EquipmentTable( + id: serializer.fromJson(json['id']), + data: serializer.fromJson(json['data']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'data': serializer.toJson(data), + }; + } + + EquipmentTable copyWith({int? id, Equipment? data}) => EquipmentTable( + id: id ?? this.id, + data: data ?? this.data, + ); + @override + String toString() { + return (StringBuffer('EquipmentTable(') + ..write('id: $id, ') + ..write('data: $data') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, data); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is EquipmentTable && other.id == this.id && other.data == this.data); +} + +class EquipmentsCompanion extends UpdateCompanion { + final Value id; + final Value data; + final Value rowid; + const EquipmentsCompanion({ + this.id = const Value.absent(), + this.data = const Value.absent(), + this.rowid = const Value.absent(), + }); + EquipmentsCompanion.insert({ + required int id, + required Equipment data, + this.rowid = const Value.absent(), + }) : id = Value(id), + data = Value(data); + static Insertable custom({ + Expression? id, + Expression? data, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (data != null) 'data': data, + if (rowid != null) 'rowid': rowid, + }); + } + + EquipmentsCompanion copyWith({Value? id, Value? data, Value? rowid}) { + return EquipmentsCompanion( + id: id ?? this.id, + data: data ?? this.data, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (data.present) { + map['data'] = Variable($EquipmentsTable.$converterdata.toSql(data.value)); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('EquipmentsCompanion(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $CategoriesTable extends Categories with TableInfo<$CategoriesTable, CategoryTable> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $CategoriesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumnWithTypeConverter data = + GeneratedColumn('data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter($CategoriesTable.$converterdata); + @override + List get $columns => [id, data]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'categories'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + context.handle(_dataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => const {}; + @override + CategoryTable map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return CategoryTable( + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, + data: $CategoriesTable.$converterdata.fromSql( + attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}data'])!), + ); + } + + @override + $CategoriesTable createAlias(String alias) { + return $CategoriesTable(attachedDatabase, alias); + } + + static TypeConverter $converterdata = const ExerciseCategoryConverter(); +} + +class CategoryTable extends DataClass implements Insertable { + final int id; + final ExerciseCategory data; + const CategoryTable({required this.id, required this.data}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + { + map['data'] = Variable($CategoriesTable.$converterdata.toSql(data)); + } + return map; + } + + CategoriesCompanion toCompanion(bool nullToAbsent) { + return CategoriesCompanion( + id: Value(id), + data: Value(data), + ); + } + + factory CategoryTable.fromJson(Map json, {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return CategoryTable( + id: serializer.fromJson(json['id']), + data: serializer.fromJson(json['data']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'data': serializer.toJson(data), + }; + } + + CategoryTable copyWith({int? id, ExerciseCategory? data}) => CategoryTable( + id: id ?? this.id, + data: data ?? this.data, + ); + @override + String toString() { + return (StringBuffer('CategoryTable(') + ..write('id: $id, ') + ..write('data: $data') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, data); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is CategoryTable && other.id == this.id && other.data == this.data); +} + +class CategoriesCompanion extends UpdateCompanion { + final Value id; + final Value data; + final Value rowid; + const CategoriesCompanion({ + this.id = const Value.absent(), + this.data = const Value.absent(), + this.rowid = const Value.absent(), + }); + CategoriesCompanion.insert({ + required int id, + required ExerciseCategory data, + this.rowid = const Value.absent(), + }) : id = Value(id), + data = Value(data); + static Insertable custom({ + Expression? id, + Expression? data, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (data != null) 'data': data, + if (rowid != null) 'rowid': rowid, + }); + } + + CategoriesCompanion copyWith({Value? id, Value? data, Value? rowid}) { + return CategoriesCompanion( + id: id ?? this.id, + data: data ?? this.data, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (data.present) { + map['data'] = Variable($CategoriesTable.$converterdata.toSql(data.value)); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('CategoriesCompanion(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +class $LanguagesTable extends Languages with TableInfo<$LanguagesTable, LanguagesTable> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $LanguagesTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn('id', aliasedName, false, + type: DriftSqlType.int, requiredDuringInsert: true); + static const VerificationMeta _dataMeta = const VerificationMeta('data'); + @override + late final GeneratedColumnWithTypeConverter data = GeneratedColumn( + 'data', aliasedName, false, + type: DriftSqlType.string, requiredDuringInsert: true) + .withConverter($LanguagesTable.$converterdata); + @override + List get $columns => [id, data]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'languages'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } else if (isInserting) { + context.missing(_idMeta); + } + context.handle(_dataMeta, const VerificationResult.success()); + return context; + } + + @override + Set get $primaryKey => const {}; + @override + LanguagesTable map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return LanguagesTable( + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, + data: $LanguagesTable.$converterdata.fromSql( + attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}data'])!), + ); + } + + @override + $LanguagesTable createAlias(String alias) { + return $LanguagesTable(attachedDatabase, alias); + } + + static TypeConverter $converterdata = const LanguageConverter(); +} + +class LanguagesTable extends DataClass implements Insertable { + final int id; + final Language data; + const LanguagesTable({required this.id, required this.data}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + { + map['data'] = Variable($LanguagesTable.$converterdata.toSql(data)); + } + return map; + } + + LanguagesCompanion toCompanion(bool nullToAbsent) { + return LanguagesCompanion( + id: Value(id), + data: Value(data), + ); + } + + factory LanguagesTable.fromJson(Map json, {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return LanguagesTable( + id: serializer.fromJson(json['id']), + data: serializer.fromJson(json['data']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'data': serializer.toJson(data), + }; + } + + LanguagesTable copyWith({int? id, Language? data}) => LanguagesTable( + id: id ?? this.id, + data: data ?? this.data, + ); + @override + String toString() { + return (StringBuffer('LanguagesTable(') + ..write('id: $id, ') + ..write('data: $data') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, data); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is LanguagesTable && other.id == this.id && other.data == this.data); +} + +class LanguagesCompanion extends UpdateCompanion { + final Value id; + final Value data; + final Value rowid; + const LanguagesCompanion({ + this.id = const Value.absent(), + this.data = const Value.absent(), + this.rowid = const Value.absent(), + }); + LanguagesCompanion.insert({ + required int id, + required Language data, + this.rowid = const Value.absent(), + }) : id = Value(id), + data = Value(data); + static Insertable custom({ + Expression? id, + Expression? data, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (data != null) 'data': data, + if (rowid != null) 'rowid': rowid, + }); + } + + LanguagesCompanion copyWith({Value? id, Value? data, Value? rowid}) { + return LanguagesCompanion( + id: id ?? this.id, + data: data ?? this.data, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (data.present) { + map['data'] = Variable($LanguagesTable.$converterdata.toSql(data.value)); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('LanguagesCompanion(') + ..write('id: $id, ') + ..write('data: $data, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + +abstract class _$ExerciseDatabase extends GeneratedDatabase { + _$ExerciseDatabase(QueryExecutor e) : super(e); + late final $ExercisesTable exercises = $ExercisesTable(this); + late final $MusclesTable muscles = $MusclesTable(this); + late final $EquipmentsTable equipments = $EquipmentsTable(this); + late final $CategoriesTable categories = $CategoriesTable(this); + late final $LanguagesTable languages = $LanguagesTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => + [exercises, muscles, equipments, categories, languages]; +} diff --git a/lib/database/exercises/type_converters.dart b/lib/database/exercises/type_converters.dart new file mode 100644 index 00000000..b494aa2a --- /dev/null +++ b/lib/database/exercises/type_converters.dart @@ -0,0 +1,134 @@ +import 'dart:convert'; + +import 'package:drift/drift.dart'; +import 'package:wger/models/exercises/alias.dart'; +import 'package:wger/models/exercises/category.dart'; +import 'package:wger/models/exercises/comment.dart'; +import 'package:wger/models/exercises/equipment.dart'; +import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/image.dart'; +import 'package:wger/models/exercises/language.dart'; +import 'package:wger/models/exercises/muscle.dart'; +import 'package:wger/models/exercises/translation.dart'; +import 'package:wger/models/exercises/variation.dart'; +import 'package:wger/models/exercises/video.dart'; + +class ExerciseBaseConverter extends TypeConverter { + const ExerciseBaseConverter(); + + @override + Exercise fromSql(String fromDb) { + final Map baseData = json.decode(fromDb); + + final category = ExerciseCategory.fromJson(baseData['categories']); + final musclesPrimary = baseData['muscless'].map((e) => Muscle.fromJson(e)).toList(); + final musclesSecondary = baseData['musclesSecondary'].map((e) => Muscle.fromJson(e)).toList(); + final equipment = baseData['equipments'].map((e) => Equipment.fromJson(e)).toList(); + final images = baseData['images'].map((e) => ExerciseImage.fromJson(e)).toList(); + final videos = baseData['videos'].map((e) => Video.fromJson(e)).toList(); + + final List translations = []; + for (final exerciseData in baseData['translations']) { + final translation = Translation( + id: exerciseData['id'], + name: exerciseData['name'], + description: exerciseData['description'], + exerciseId: baseData['id'], + ); + translation.aliases = exerciseData['aliases'].map((e) => Alias.fromJson(e)).toList(); + translation.notes = exerciseData['notes'].map((e) => Comment.fromJson(e)).toList(); + translation.language = Language.fromJson(exerciseData['languageObj']); + translations.add(translation); + } + + final exerciseBase = Exercise( + id: baseData['id'], + uuid: baseData['uuid'], + created: null, + //creationDate: toDate(baseData['creation_date']), + musclesSecondary: musclesSecondary.cast(), + muscles: musclesPrimary.cast(), + equipment: equipment.cast(), + category: category, + images: images.cast(), + translations: translations, + videos: videos.cast