LeStorage consequences

sync3
Laurent 6 months ago
parent 4ed4ca4ae3
commit 5e7662552f
  1. 7
      PadelClubData/Data/Club.swift
  2. 23
      PadelClubData/Data/Event.swift
  3. 3
      PadelClubData/Data/Gen/BaseClub.swift
  4. 3
      PadelClubData/Data/Gen/BaseCourt.swift
  5. 1
      PadelClubData/Data/Gen/BaseCustomUser.swift
  6. 1
      PadelClubData/Data/Gen/BaseDateInterval.swift
  7. 1
      PadelClubData/Data/Gen/BaseDrawLog.swift
  8. 1
      PadelClubData/Data/Gen/BaseEvent.swift
  9. 1
      PadelClubData/Data/Gen/BaseGroupStage.swift
  10. 1
      PadelClubData/Data/Gen/BaseMatch.swift
  11. 1
      PadelClubData/Data/Gen/BaseMatchScheduler.swift
  12. 1
      PadelClubData/Data/Gen/BaseMonthData.swift
  13. 1
      PadelClubData/Data/Gen/BasePlayerRegistration.swift
  14. 1
      PadelClubData/Data/Gen/BasePurchase.swift
  15. 1
      PadelClubData/Data/Gen/BaseRound.swift
  16. 8
      PadelClubData/Data/Gen/BaseTeamRegistration.swift
  17. 1
      PadelClubData/Data/Gen/BaseTeamScore.swift
  18. 1
      PadelClubData/Data/Gen/BaseTournament.swift
  19. 1
      PadelClubData/Data/Gen/Drawlog.json
  20. 1
      PadelClubData/Data/Gen/PlayerRegistration.json
  21. 3
      PadelClubData/Data/Gen/Purchase.json
  22. 1
      PadelClubData/Data/Gen/Round.json
  23. 4
      PadelClubData/Data/Gen/TeamRegistration.json
  24. 1
      PadelClubData/Data/Gen/TeamScore.json
  25. 3
      PadelClubData/Data/Gen/Tournament.json
  26. 8
      PadelClubData/Data/Gen/generator.py
  27. 14
      PadelClubData/Data/GroupStage.swift
  28. 13
      PadelClubData/Data/Match.swift
  29. 10
      PadelClubData/Data/Round.swift
  30. 26
      PadelClubData/Data/TeamRegistration.swift
  31. 8
      PadelClubData/Data/TeamScore.swift
  32. 16
      PadelClubData/Data/Tournament.swift
  33. 12
      PadelClubData/Data/TournamentLibrary.swift
  34. 12
      PadelClubData/Data/TournamentStore.swift
  35. 10
      PadelClubDataTests/SyncDataAccessTests.swift

@ -30,14 +30,13 @@ final public class Club: BaseClub {
}
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: Court.self, actionOption: actionOption) { ($0 as? Court)?.club == self.id }
store.deleteDependencies(type: Court.self, actionOption: actionOption) { $0.club == self.id }
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: Court.self, shouldBeSynchronized: false) { $0.club == self.id }
store.deleteUnusedSharedDependencies(type: Court.self) { $0.club == self.id }
}
}
extension Club {

@ -26,30 +26,15 @@ final public class Event: BaseEvent {
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: Tournament.self, shouldBeSynchronized: false) { $0.event == self.id && $0.isDeleted == false }
store.deleteUnusedSharedDependencies(type: DateInterval.self, shouldBeSynchronized: false) { $0.event == self.id }
store.deleteUnusedSharedDependencies(type: Tournament.self) { $0.event == self.id && $0.isDeleted == false }
store.deleteUnusedSharedDependencies(type: DateInterval.self) { $0.event == self.id }
}
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: Tournament.self, actionOption: actionOption) { storable in
guard let tournament = storable as? Tournament else { return false }
return tournament.event == self.id && tournament.isDeleted == false }
store.deleteDependencies(type: DateInterval.self, actionOption: actionOption) { ($0 as? DateInterval)?.event == self.id }
store.deleteDependencies(type: Tournament.self, actionOption: actionOption) { $0.event == self.id && $0.isDeleted == false }
store.deleteDependencies(type: DateInterval.self, actionOption: actionOption) { $0.event == self.id }
// let tournaments = self.tournaments
// for tournament in tournaments {
// tournament.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
//
// DataStore.shared.tournaments.deleteDependencies(tournaments, shouldBeSynchronized: shouldBeSynchronized)
//
// let courtsUnavailabilities = self.courtsUnavailability
// for courtsUnavailability in courtsUnavailabilities {
// courtsUnavailability.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
// DataStore.shared.dateIntervals.deleteDependencies(courtsUnavailabilities, shouldBeSynchronized: shouldBeSynchronized)
}
// MARK: - Computed dependencies

@ -11,6 +11,7 @@ public class BaseClub: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "clubs" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = true
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var creator: String? = nil
@ -147,4 +148,4 @@ public class BaseClub: SyncedModelObject, SyncedStorable {
]
}
}
}

@ -11,6 +11,7 @@ public class BaseCourt: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "courts" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var index: Int = 0
@ -90,4 +91,4 @@ public class BaseCourt: SyncedModelObject, SyncedStorable {
]
}
}
}

@ -11,6 +11,7 @@ public class BaseCustomUser: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "users" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [.post] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var username: String = ""

@ -11,6 +11,7 @@ public class BaseDateInterval: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "date-intervals" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var event: String = ""

@ -11,6 +11,7 @@ public class BaseDrawLog: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "draw-logs" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var tournament: String = ""

@ -11,6 +11,7 @@ public class BaseEvent: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "events" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var creator: String? = nil

@ -11,6 +11,7 @@ public class BaseGroupStage: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "group-stages" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var tournament: String = ""

@ -11,6 +11,7 @@ public class BaseMatch: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "matches" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var round: String? = nil

@ -11,6 +11,7 @@ public class BaseMatchScheduler: BaseModelObject, Storable {
public static func resourceName() -> String { return "match-scheduler" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var tournament: String = ""

@ -11,6 +11,7 @@ public class BaseMonthData: BaseModelObject, Storable {
public static func resourceName() -> String { return "month-data" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var monthKey: String = ""

@ -11,6 +11,7 @@ public class BasePlayerRegistration: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "player-registrations" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var teamRegistration: String? = nil

@ -9,6 +9,7 @@ public class BasePurchase: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "purchases" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: UInt64 = 0
public var user: String = ""

@ -11,6 +11,7 @@ public class BaseRound: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "rounds" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var tournament: String = ""

@ -11,6 +11,7 @@ public class BaseTeamRegistration: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "team-registrations" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var tournament: String = ""
@ -160,6 +161,10 @@ public class BaseTeamRegistration: SyncedModelObject, SyncedStorable {
try super.encode(to: encoder)
}
func tournamentValue() -> Tournament? {
return self.store?.storeCenter.mainStore.findById(tournament)
}
func groupStageValue() -> GroupStage? {
guard let groupStage = self.groupStage else { return nil }
return self.store?.findById(groupStage)
@ -192,8 +197,9 @@ public class BaseTeamRegistration: SyncedModelObject, SyncedStorable {
public static func relationships() -> [Relationship] {
return [
Relationship(type: Tournament.self, keyPath: \BaseTeamRegistration.tournament, mainStoreLookup: true),
Relationship(type: GroupStage.self, keyPath: \BaseTeamRegistration.groupStage, mainStoreLookup: false),
]
}
}
}

@ -11,6 +11,7 @@ public class BaseTeamScore: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "team-scores" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return false }
public var id: String = Store.randomId()
public var match: String = ""

@ -11,6 +11,7 @@ public class BaseTournament: SyncedModelObject, SyncedStorable {
public static func resourceName() -> String { return "tournaments" }
public static func tokenExemptedMethods() -> [HTTPMethod] { return [] }
public static var copyServerResponse: Bool = false
public static func storeParent() -> Bool { return true }
public var id: String = Store.randomId()
public var event: String? = nil

@ -6,7 +6,6 @@
"synchronizable": true,
"sideStorable": true,
"observable": true,
"relationshipNames": [],
"properties": [
{
"name": "id",

@ -5,7 +5,6 @@
"synchronizable": true,
"sideStorable": true,
"observable": true,
"relationshipNames": ["teamRegistration"],
"properties": [
{
"name": "id",

@ -44,8 +44,7 @@
"defaultValue": "nil"
}
],
"tokenExemptedMethods": [],
"relationshipNames": []
"tokenExemptedMethods": []
}
]
}

@ -5,7 +5,6 @@
"synchronizable": true,
"sideStorable": true,
"observable": true,
"relationshipNames": [],
"properties": [
{
"name": "id",

@ -5,7 +5,6 @@
"synchronizable": true,
"sideStorable": true,
"observable": true,
"relationshipNames": [],
"properties": [
{
"name": "id",
@ -14,7 +13,8 @@
},
{
"name": "tournament",
"type": "String"
"type": "String",
"foreignKey": "Tournament###"
},
{
"name": "groupStage",

@ -5,7 +5,6 @@
"synchronizable": true,
"sideStorable": true,
"observable": true,
"relationshipNames": ["match"],
"properties": [
{
"name": "id",

@ -3,9 +3,8 @@
{
"name": "Tournament",
"synchronizable": true,
"copyable": true,
"observable": true,
"relationshipNames": [],
"storeParent": true,
"properties": [
{
"name": "id",

@ -18,6 +18,7 @@ class LeStorageGenerator:
model_name = model_data["name"]
is_sync = model_data.get("synchronizable", False)
is_observable = model_data.get("observable", False)
store_parent = model_data.get("storeParent", False)
properties = model_data["properties"]
did_set_properties = []
@ -45,7 +46,7 @@ class LeStorageGenerator:
lines.append("")
# Add SyncedStorable protocol requirements
lines.extend(self._generate_protocol_requirements(resource_name, token_exempted, copy_server_response))
lines.extend(self._generate_protocol_requirements(resource_name, token_exempted, copy_server_response, store_parent))
lines.append("")
# Properties
@ -423,16 +424,19 @@ class LeStorageGenerator:
lines.append(" }")
return lines
def _generate_protocol_requirements(self, resource_name: str, token_exempted: List[str], copy_server_response: str) -> List[str]:
def _generate_protocol_requirements(self, resource_name: str, token_exempted: List[str], copy_server_response: str, store_parent: bool) -> List[str]:
"""Generate the static functions required by SyncedStorable protocol."""
# Convert HTTP methods to proper format
formatted_methods = [f".{method.lower()}" for method in token_exempted]
methods_str = ", ".join(formatted_methods) if formatted_methods else ""
store_parent_swift = "true" if store_parent else "false"
return [
f" public static func resourceName() -> String {{ return \"{resource_name}\" }}",
f" public static func tokenExemptedMethods() -> [HTTPMethod] {{ return [{methods_str}] }}",
f" public static var copyServerResponse: Bool = {copy_server_response}",
f" public static func storeParent() -> Bool {{ return {store_parent_swift} }}",
]

@ -608,15 +608,11 @@ final public class GroupStage: BaseGroupStage, SideStorable {
}
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: Match.self, actionOption: actionOption) { ($0 as? Match)?.groupStage == self.id }
//
// let matches = self._matches()
// for match in matches {
// match.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
// self.tournamentStore?.matches.deleteDependencies(matches, shouldBeSynchronized: shouldBeSynchronized)
store.deleteDependencies(type: Match.self, actionOption: actionOption) { $0.groupStage == self.id }
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: Match.self) { $0.groupStage == self.id }
}
func insertOnServer() {

@ -83,14 +83,11 @@ final public class Match: BaseMatch, SideStorable {
// MARK: -
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: TeamScore.self, actionOption: actionOption) { ($0 as? TeamScore)?.match == self.id }
// let teamScores = self.teamScores
// for teamScore in teamScores {
// teamScore.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
// self.tournamentStore?.teamScores.deleteDependencies(teamScores, shouldBeSynchronized: shouldBeSynchronized)
store.deleteDependencies(type: TeamScore.self, actionOption: actionOption) { $0.match == self.id }
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: TeamScore.self) { $0.match == self.id }
}
public func indexInRound(in matches: [Match]? = nil) -> Int {

@ -905,11 +905,15 @@ defer {
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: Match.self, actionOption: actionOption) { ($0 as? Match)?.round == self.id }
store.deleteDependencies(type: Round.self, actionOption: actionOption) { ($0 as? Round)?.parent == self.id }
store.deleteDependencies(type: Match.self, actionOption: actionOption) { $0.round == self.id }
store.deleteDependencies(type: Round.self, actionOption: actionOption) { $0.parent == self.id }
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: Match.self) { $0.round == self.id }
store.deleteUnusedSharedDependencies(type: Round.self) { $0.parent == self.id }
}
// enum CodingKeys: String, CodingKey {
// case _id = "id"

@ -100,23 +100,17 @@ final public class TeamRegistration: BaseTeamRegistration, SideStorable {
let ts = tournamentStore.teamScores.filter({ $0.teamRegistration == id })
tournamentStore.teamScores.delete(contentOfs: ts)
}
public override func deleteUnusedSharedDependencies(store: Store) {
store.deleteUnusedSharedDependencies(type: TeamScore.self) { $0.teamRegistration == self.id }
store.deleteUnusedSharedDependencies(type: PlayerRegistration.self) { $0.teamRegistration == self.id }
}
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
store.deleteDependencies(type: TeamScore.self, actionOption: actionOption) { ($0 as? TeamScore)?.teamRegistration == self.id }
store.deleteDependencies(type: PlayerRegistration.self, actionOption: actionOption) { ($0 as? PlayerRegistration)?.teamRegistration == self.id }
// let unsortedPlayers = unsortedPlayers()
// for player in unsortedPlayers {
// player.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
// self.tournamentStore?.playerRegistrations.deleteDependencies(unsortedPlayers, shouldBeSynchronized: shouldBeSynchronized)
//
// let teamScores = teamScores()
// for teamScore in teamScores {
// teamScore.deleteDependencies(store: store, shouldBeSynchronized: shouldBeSynchronized)
// }
// self.tournamentStore?.teamScores.deleteDependencies(teamScores, shouldBeSynchronized: shouldBeSynchronized)
store.deleteDependencies(type: TeamScore.self, actionOption: actionOption) { $0.teamRegistration == self.id }
store.deleteDependencies(type: PlayerRegistration.self, actionOption: actionOption) { $0.teamRegistration == self.id }
}
public func hasArrived(isHere: Bool = false) {
@ -221,7 +215,7 @@ final public class TeamRegistration: BaseTeamRegistration, SideStorable {
}
public func currentMatch() -> Match? {
return teamScores().compactMap { $0.matchObject() }.first(where: { $0.isRunning() })
return teamScores().compactMap { $0.matchValue() }.first(where: { $0.isRunning() })
}
public func teamScores() -> [TeamScore] {

@ -68,10 +68,10 @@ final public class TeamScore: BaseTeamScore, SideStorable {
// MARK: - Computed dependencies
public func matchObject() -> Match? {
return self.tournamentStore?.matches.findById(self.match)
}
// public func matchObject() -> Match? {
// return self.tournamentStore?.matches.findById(self.match)
// }
//
public var team: TeamRegistration? {
guard let teamRegistration else {
return nil

@ -32,6 +32,22 @@ final public class Tournament: BaseTournament {
return TournamentLibrary.shared.store(tournamentId: self.id)
}
public override func deleteUnusedSharedDependencies(store: Store) {
do {
let tournamentStore = try store.alternateStore(identifier: self.id)
tournamentStore.deleteUnusedSharedDependencies(type: DrawLog.self)
tournamentStore.deleteUnusedSharedDependencies(type: TeamRegistration.self)
tournamentStore.deleteUnusedSharedDependencies(type: GroupStage.self)
tournamentStore.deleteUnusedSharedDependencies(type: Round.self)
} catch {
Logger.error(error)
}
store.deleteUnusedSharedDependencies(type: Court.self) { $0.club == self.id }
}
public override func deleteDependencies(store: Store, actionOption: ActionOption) {
do {

@ -20,10 +20,14 @@ public class TournamentLibrary {
if let store = self._stores[tournamentId] {
return store
}
let store = StoreCenter.main.requestStore(identifier: tournamentId)
let tournamentStore = TournamentStore(store: store)
self._stores[tournamentId] = tournamentStore
return tournamentStore
do {
let store = try StoreCenter.main.store(identifier: tournamentId)
let tournamentStore = TournamentStore(store: store, tournamentId: tournamentId)
self._stores[tournamentId] = tournamentStore
return tournamentStore
} catch {
return nil
}
}
func reset() {

@ -13,6 +13,7 @@ import Combine
public class TournamentStore: ObservableObject {
var store: Store
let tournamentId: String
public fileprivate(set) var groupStages: SyncedCollection<GroupStage> = SyncedCollection.placeholder()
public fileprivate(set) var matches: SyncedCollection<Match> = SyncedCollection.placeholder()
@ -30,13 +31,18 @@ public class TournamentStore: ObservableObject {
// self._initialize()
// }
init(store: Store) {
init(store: Store, tournamentId: String) {
self.store = store
self.tournamentId = tournamentId
self._initialize()
}
fileprivate func _initialize() {
guard let tournament = DataStore.shared.tournaments.findById(self.tournamentId) else {
return
}
let indexed: Bool = true
self.groupStages = self.store.registerSynchronizedCollection(indexed: indexed)
@ -48,7 +54,9 @@ public class TournamentStore: ObservableObject {
self.matchSchedulers = self.store.registerCollection(indexed: indexed)
self.drawLogs = self.store.registerSynchronizedCollection(indexed: indexed)
self.store.loadCollectionsFromServerIfNoFile()
if tournament.sharing == nil {
self.store.loadCollectionsFromServerIfNoFile()
}
NotificationCenter.default.addObserver(
self,

@ -121,10 +121,13 @@ struct SyncDataAccessTests {
var dataB = try await self.storeCenterB.testSynchronizeOnceAsync()
var syncDataB = try SyncData(data: dataB, storeCenter: self.storeCenterB)
#expect(syncDataB.grants.count == 2)
#expect(syncDataB.shared.count == 1) // the tournament
#expect(syncDataB.grants.count == 1) // the granted event
#expect(eventColB.count == 1)
#expect(eventColB.first?.sharing == .granted)
#expect(tournamentColB.count == 1)
#expect(tournamentColB.first?.sharing == .shared)
// Remove sharing from user2
try await self.storeCenterA.setAuthorizedUsersAsync(for: tournamentA, users: [])
@ -188,10 +191,11 @@ struct SyncDataAccessTests {
var dataB = try await self.storeCenterB.testSynchronizeOnceAsync()
var syncDataB = try SyncData(data: dataB, storeCenter: self.storeCenterB)
#expect(syncDataB.grants.count == 2)
#expect(syncDataB.shared.count == 1)
#expect(syncDataB.grants.count == 1)
let clubGrants = syncDataB.grants.first { $0.type == Club.self }
let eventGrants = syncDataB.grants.first { $0.type == Event.self }
let eventGrants = syncDataB.shared.first { $0.type == Event.self }
#expect(clubGrants?.items.count == 1)
#expect(eventGrants?.items.count == 2)

Loading…
Cancel
Save