fix data import and export
This commit is contained in:
@@ -15,6 +15,43 @@
|
|||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"createdAt",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"games": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ruleset": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"type": ["integer", "null"]
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"type": ["string", "null"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
@@ -25,6 +62,38 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"groups": {
|
"groups": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": ["string", "null"]
|
||||||
|
},
|
||||||
|
"memberIds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"createdAt",
|
||||||
|
"memberIds"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"teams": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -67,6 +136,12 @@
|
|||||||
"createdAt": {
|
"createdAt": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"gameId": {
|
||||||
|
"anyOf": [
|
||||||
|
{"type": "string"},
|
||||||
|
{"type": "null"}
|
||||||
|
]
|
||||||
|
},
|
||||||
"groupId": {
|
"groupId": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
@@ -79,7 +154,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"winnerId": {
|
"notes": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
{"type": "string"},
|
{"type": "string"},
|
||||||
{"type": "null"}
|
{"type": "null"}
|
||||||
@@ -90,7 +165,6 @@
|
|||||||
"id",
|
"id",
|
||||||
"name",
|
"name",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"groupId",
|
|
||||||
"playerIds"
|
"playerIds"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -98,7 +172,9 @@
|
|||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"players",
|
"players",
|
||||||
|
"games",
|
||||||
"groups",
|
"groups",
|
||||||
|
"teams",
|
||||||
"matches"
|
"matches"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -23,22 +23,21 @@ class Group {
|
|||||||
return 'Group{id: $id, name: $name, description: $description, members: $members}';
|
return 'Group{id: $id, name: $name, description: $description, members: $members}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a Group instance from a JSON object.
|
/// Creates a Group instance from a JSON object (memberIds format).
|
||||||
|
/// Player objects are reconstructed from memberIds by the DataTransferService.
|
||||||
Group.fromJson(Map<String, dynamic> json)
|
Group.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
createdAt = DateTime.parse(json['createdAt']),
|
||||||
name = json['name'],
|
name = json['name'],
|
||||||
description = json['description'],
|
description = json['description'],
|
||||||
members = (json['members'] as List)
|
members = []; // Populated during import via DataTransferService
|
||||||
.map((memberJson) => Player.fromJson(memberJson))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
/// Converts the Group instance to a JSON object.
|
/// Converts the Group instance to a JSON object using normalized format (memberIds only).
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
'createdAt': createdAt.toIso8601String(),
|
'createdAt': createdAt.toIso8601String(),
|
||||||
'name': name,
|
'name': name,
|
||||||
'description': description,
|
'description': description,
|
||||||
'members': members.map((member) => member.toJson()).toList(),
|
'memberIds': members.map((member) => member.id).toList(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,31 +28,28 @@ class Match {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Match{id: $id, name: $name, game: $game, group: $group, players: $players, notes: $notes, winner: $winner}';
|
return 'Match{id: $id, name: $name, game: $game, group: $group, players: $players, notes: $notes}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a Match instance from a JSON object.
|
/// Creates a Match instance from a JSON object (ID references format).
|
||||||
|
/// Related objects are reconstructed from IDs by the DataTransferService.
|
||||||
Match.fromJson(Map<String, dynamic> json)
|
Match.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
createdAt = DateTime.parse(json['createdAt']),
|
||||||
name = json['name'],
|
name = json['name'],
|
||||||
game = json['game'] != null ? Game.fromJson(json['game']) : null,
|
game = null, // Populated during import via DataTransferService
|
||||||
group = json['group'] != null ? Group.fromJson(json['group']) : null,
|
group = null, // Populated during import via DataTransferService
|
||||||
players = json['players'] != null
|
players = [], // Populated during import via DataTransferService
|
||||||
? (json['players'] as List)
|
|
||||||
.map((playerJson) => Player.fromJson(playerJson))
|
|
||||||
.toList()
|
|
||||||
: null,
|
|
||||||
notes = json['notes'];
|
notes = json['notes'];
|
||||||
|
|
||||||
/// Converts the Match instance to a JSON object.
|
/// Converts the Match instance to a JSON object using normalized format (ID references only).
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
'createdAt': createdAt.toIso8601String(),
|
'createdAt': createdAt.toIso8601String(),
|
||||||
'name': name,
|
'name': name,
|
||||||
'game': game?.toJson(),
|
'gameId': game?.id,
|
||||||
'group': group?.toJson(),
|
'groupId': group?.id,
|
||||||
'players': players?.map((player) => player.toJson()).toList(),
|
'playerIds': (players ?? []).map((player) => player.id).toList(),
|
||||||
'notes': notes,
|
'notes': notes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,21 +21,20 @@ class Team {
|
|||||||
return 'Team{id: $id, name: $name, members: $members}';
|
return 'Team{id: $id, name: $name, members: $members}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a Team instance from a JSON object.
|
/// Creates a Team instance from a JSON object (memberIds format).
|
||||||
|
/// Player objects are reconstructed from memberIds by the DataTransferService.
|
||||||
Team.fromJson(Map<String, dynamic> json)
|
Team.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
name = json['name'],
|
name = json['name'],
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
createdAt = DateTime.parse(json['createdAt']),
|
||||||
members = (json['members'] as List)
|
members = []; // Populated during import via DataTransferService
|
||||||
.map((memberJson) => Player.fromJson(memberJson))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
/// Converts the Team instance to a JSON object.
|
/// Converts the Team instance to a JSON object using normalized format (memberIds only).
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
'name': name,
|
'name': name,
|
||||||
'createdAt': createdAt.toIso8601String(),
|
'createdAt': createdAt.toIso8601String(),
|
||||||
'members': members.map((member) => member.toJson()).toList(),
|
'memberIds': members.map((member) => member.id).toList(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:game_tracker/core/enums.dart';
|
import 'package:game_tracker/core/enums.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:game_tracker/data/db/database.dart';
|
||||||
|
import 'package:game_tracker/data/dto/game.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:game_tracker/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
import 'package:game_tracker/data/dto/match.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:game_tracker/data/dto/player.dart';
|
||||||
|
import 'package:game_tracker/data/dto/team.dart';
|
||||||
import 'package:json_schema/json_schema.dart';
|
import 'package:json_schema/json_schema.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@@ -17,39 +19,54 @@ class DataTransferService {
|
|||||||
static Future<void> deleteAllData(BuildContext context) async {
|
static Future<void> deleteAllData(BuildContext context) async {
|
||||||
final db = Provider.of<AppDatabase>(context, listen: false);
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
await db.matchDao.deleteAllMatches();
|
await db.matchDao.deleteAllMatches();
|
||||||
|
await db.teamDao.deleteAllTeams();
|
||||||
await db.groupDao.deleteAllGroups();
|
await db.groupDao.deleteAllGroups();
|
||||||
|
await db.gameDao.deleteAllGames();
|
||||||
await db.playerDao.deleteAllPlayers();
|
await db.playerDao.deleteAllPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves all application data and converts it to a JSON string.
|
/// Retrieves all application data and converts it to a JSON string.
|
||||||
/// Returns the JSON string representation of the data.
|
/// Returns the JSON string representation of the data in normalized format.
|
||||||
static Future<String> getAppDataAsJson(BuildContext context) async {
|
static Future<String> getAppDataAsJson(BuildContext context) async {
|
||||||
final db = Provider.of<AppDatabase>(context, listen: false);
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
final matches = await db.matchDao.getAllMatches();
|
final matches = await db.matchDao.getAllMatches();
|
||||||
final groups = await db.groupDao.getAllGroups();
|
final groups = await db.groupDao.getAllGroups();
|
||||||
final players = await db.playerDao.getAllPlayers();
|
final players = await db.playerDao.getAllPlayers();
|
||||||
|
final games = await db.gameDao.getAllGames();
|
||||||
|
final teams = await db.teamDao.getAllTeams();
|
||||||
|
|
||||||
// Construct a JSON representation of the data
|
// Construct a JSON representation of the data in normalized format
|
||||||
final Map<String, dynamic> jsonMap = {
|
final Map<String, dynamic> jsonMap = {
|
||||||
'players': players.map((p) => p.toJson()).toList(),
|
'players': players.map((p) => p.toJson()).toList(),
|
||||||
|
'games': games.map((g) => g.toJson()).toList(),
|
||||||
'groups': groups
|
'groups': groups
|
||||||
.map((g) => {
|
.map((g) => {
|
||||||
'id': g.id,
|
'id': g.id,
|
||||||
'name': g.name,
|
'name': g.name,
|
||||||
'createdAt': g.createdAt.toIso8601String(),
|
'description': g.description,
|
||||||
'memberIds': (g.members).map((m) => m.id).toList(),
|
'createdAt': g.createdAt.toIso8601String(),
|
||||||
}).toList(),
|
'memberIds': (g.members).map((m) => m.id).toList(),
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
|
'teams': teams
|
||||||
|
.map((t) => {
|
||||||
|
'id': t.id,
|
||||||
|
'name': t.name,
|
||||||
|
'createdAt': t.createdAt.toIso8601String(),
|
||||||
|
'memberIds': (t.members).map((m) => m.id).toList(),
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
'matches': matches
|
'matches': matches
|
||||||
.map((m) => {
|
.map((m) => {
|
||||||
'id': m.id,
|
'id': m.id,
|
||||||
'name': m.name,
|
'name': m.name,
|
||||||
'createdAt': m.createdAt.toIso8601String(),
|
'createdAt': m.createdAt.toIso8601String(),
|
||||||
'groupId': m.group?.id,
|
'gameId': m.game?.id,
|
||||||
'playerIds': (m.players ?? []).map((p) => p.id).toList(),
|
'groupId': m.group?.id,
|
||||||
'winnerId': m.winner?.id,
|
'playerIds': (m.players ?? []).map((p) => p.id).toList(),
|
||||||
}).toList(),
|
'notes': m.notes,
|
||||||
|
})
|
||||||
|
.toList(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return json.encode(jsonMap);
|
return json.encode(jsonMap);
|
||||||
@@ -107,10 +124,12 @@ class DataTransferService {
|
|||||||
final Map<String, dynamic> decoded = json.decode(jsonString) as Map<String, dynamic>;
|
final Map<String, dynamic> decoded = json.decode(jsonString) as Map<String, dynamic>;
|
||||||
|
|
||||||
final List<dynamic> playersJson = (decoded['players'] as List<dynamic>?) ?? [];
|
final List<dynamic> playersJson = (decoded['players'] as List<dynamic>?) ?? [];
|
||||||
|
final List<dynamic> gamesJson = (decoded['games'] as List<dynamic>?) ?? [];
|
||||||
final List<dynamic> groupsJson = (decoded['groups'] as List<dynamic>?) ?? [];
|
final List<dynamic> groupsJson = (decoded['groups'] as List<dynamic>?) ?? [];
|
||||||
|
final List<dynamic> teamsJson = (decoded['teams'] as List<dynamic>?) ?? [];
|
||||||
final List<dynamic> matchesJson = (decoded['matches'] as List<dynamic>?) ?? [];
|
final List<dynamic> matchesJson = (decoded['matches'] as List<dynamic>?) ?? [];
|
||||||
|
|
||||||
// Players
|
// Import Players
|
||||||
final List<Player> importedPlayers = playersJson
|
final List<Player> importedPlayers = playersJson
|
||||||
.map((p) => Player.fromJson(p as Map<String, dynamic>))
|
.map((p) => Player.fromJson(p as Map<String, dynamic>))
|
||||||
.toList();
|
.toList();
|
||||||
@@ -119,7 +138,16 @@ class DataTransferService {
|
|||||||
for (final p in importedPlayers) p.id: p,
|
for (final p in importedPlayers) p.id: p,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Groups
|
// Import Games
|
||||||
|
final List<Game> importedGames = gamesJson
|
||||||
|
.map((g) => Game.fromJson(g as Map<String, dynamic>))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final Map<String, Game> gameById = {
|
||||||
|
for (final g in importedGames) g.id: g,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import Groups
|
||||||
final List<Group> importedGroups = groupsJson.map((g) {
|
final List<Group> importedGroups = groupsJson.map((g) {
|
||||||
final map = g as Map<String, dynamic>;
|
final map = g as Map<String, dynamic>;
|
||||||
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>();
|
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>();
|
||||||
@@ -132,6 +160,7 @@ class DataTransferService {
|
|||||||
return Group(
|
return Group(
|
||||||
id: map['id'] as String,
|
id: map['id'] as String,
|
||||||
name: map['name'] as String,
|
name: map['name'] as String,
|
||||||
|
description: map['description'] as String?,
|
||||||
members: members,
|
members: members,
|
||||||
createdAt: DateTime.parse(map['createdAt'] as String),
|
createdAt: DateTime.parse(map['createdAt'] as String),
|
||||||
);
|
);
|
||||||
@@ -141,33 +170,59 @@ class DataTransferService {
|
|||||||
for (final g in importedGroups) g.id: g,
|
for (final g in importedGroups) g.id: g,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Matches
|
// Import Teams
|
||||||
|
final List<Team> importedTeams = teamsJson.map((t) {
|
||||||
|
final map = t as Map<String, dynamic>;
|
||||||
|
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>();
|
||||||
|
|
||||||
|
final members = memberIds
|
||||||
|
.map((id) => playerById[id])
|
||||||
|
.whereType<Player>()
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return Team(
|
||||||
|
id: map['id'] as String,
|
||||||
|
name: map['name'] as String,
|
||||||
|
members: members,
|
||||||
|
createdAt: DateTime.parse(map['createdAt'] as String),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final Map<String, Team> teamById = {
|
||||||
|
for (final t in importedTeams) t.id: t,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Import Matches
|
||||||
final List<Match> importedMatches = matchesJson.map((m) {
|
final List<Match> importedMatches = matchesJson.map((m) {
|
||||||
final map = m as Map<String, dynamic>;
|
final map = m as Map<String, dynamic>;
|
||||||
|
|
||||||
|
final String? gameId = map['gameId'] as String?;
|
||||||
final String? groupId = map['groupId'] as String?;
|
final String? groupId = map['groupId'] as String?;
|
||||||
final List<String> playerIds = (map['playerIds'] as List<dynamic>? ?? []).cast<String>();
|
final List<String> playerIds = (map['playerIds'] as List<dynamic>? ?? []).cast<String>();
|
||||||
final String? winnerId = map['winnerId'] as String?;
|
|
||||||
|
|
||||||
|
final game = (gameId == null) ? null : gameById[gameId];
|
||||||
final group = (groupId == null) ? null : groupById[groupId];
|
final group = (groupId == null) ? null : groupById[groupId];
|
||||||
final players = playerIds
|
final players = playerIds
|
||||||
.map((id) => playerById[id])
|
.map((id) => playerById[id])
|
||||||
.whereType<Player>()
|
.whereType<Player>()
|
||||||
.toList();
|
.toList();
|
||||||
final winner = (winnerId == null) ? null : playerById[winnerId];
|
|
||||||
|
|
||||||
return Match(
|
return Match(
|
||||||
id: map['id'] as String,
|
id: map['id'] as String,
|
||||||
name: map['name'] as String,
|
name: map['name'] as String,
|
||||||
|
game: game,
|
||||||
group: group,
|
group: group,
|
||||||
players: players,
|
players: players.isNotEmpty ? players : null,
|
||||||
createdAt: DateTime.parse(map['createdAt'] as String),
|
createdAt: DateTime.parse(map['createdAt'] as String),
|
||||||
winner: winner,
|
notes: map['notes'] as String?,
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
// Import all data into the database
|
||||||
await db.playerDao.addPlayersAsList(players: importedPlayers);
|
await db.playerDao.addPlayersAsList(players: importedPlayers);
|
||||||
|
await db.gameDao.addGamesAsList(games: importedGames);
|
||||||
await db.groupDao.addGroupsAsList(groups: importedGroups);
|
await db.groupDao.addGroupsAsList(groups: importedGroups);
|
||||||
|
await db.teamDao.addTeamsAsList(teams: importedTeams);
|
||||||
await db.matchDao.addMatchAsList(matches: importedMatches);
|
await db.matchDao.addMatchAsList(matches: importedMatches);
|
||||||
|
|
||||||
return ImportResult.success;
|
return ImportResult.success;
|
||||||
|
|||||||
Reference in New Issue
Block a user