Skip to content

Commit

Permalink
Fix Codable&RawRepresentable properties
Browse files Browse the repository at this point in the history
Should fix issue #29

This was missing overloads for RawRepresentable & Codable,
not sure why this didn't produce an ambiguity warning.
  • Loading branch information
helje5 committed Feb 15, 2024
1 parent 5d7c1ac commit b4db7ac
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Sources/ManagedModels/PersistentModel/PersistentModel+KVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,28 @@ public extension PersistentModel {
}
return wrapped
}

// Overloads for RawRepresentables that are ALSO Codable

@inlinable
func setValue<T>(forKey key: String, to value: T)
where T: RawRepresentable & Codable,
T.RawValue: Codable & CoreDataPrimitiveValue
{
setValue(forKey: key, to: value.rawValue)
}

@inlinable
func getValue<T>(forKey key: String) -> T
where T: RawRepresentable & Codable,
T.RawValue: Codable & CoreDataPrimitiveValue
{
let rawValue : T.RawValue = getValue(forKey: key)
guard let wrapped = T.init(rawValue: rawValue) else {
fatalError("Could not wrap raw value \(rawValue) for \(key)")
}
return wrapped
}
}

// MARK: - Codable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ final class CodablePropertiesTests: XCTestCase {
)

func testEntityName() throws {
_ = container
let entityType = Fixtures.CodablePropertiesSchema.StoredAccess.self
XCTAssertEqual(entityType.entity().name, "StoredAccess")
}
Expand Down
44 changes: 44 additions & 0 deletions Tests/ManagedModelTests/CodableRawRepresentableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Created by Helge Heß.
// Copyright © 2024 ZeeZide GmbH.
//

import XCTest
import Foundation
import CoreData
@testable import ManagedModels

final class CodableRawRepresentableTests: XCTestCase {
// https://github.com/Data-swift/ManagedModels/issues/29

private lazy var container = try? ModelContainer(
for: Fixtures.ToDoListSchema.managedObjectModel,
configurations: ModelConfiguration(isStoredInMemoryOnly: true)
)

func testEntityName() throws {
_ = container // required to register the entity type mapping
let entityType = Fixtures.ToDoListSchema.ToDo.self
XCTAssertEqual(entityType.entity().name, "ToDo")
}

func testPropertySetup() throws {
let valueType = Fixtures.ToDoListSchema.ToDo.Priority.self
let attribute = CoreData.NSAttributeDescription(
name: "priority",
valueType: valueType,
defaultValue: nil
)
XCTAssertEqual(attribute.name, "priority")
XCTAssertEqual(attribute.attributeType, .integer64AttributeType)

XCTAssertTrue(attribute.valueType == Int.self)
XCTAssertNil(attribute.valueTransformerName)
}

func testModel() throws {
_ = container // required to register the entity type mapping
let todo = Fixtures.ToDoListSchema.ToDo()
todo.priority = .high
}
}
91 changes: 91 additions & 0 deletions Tests/ManagedModelTests/Schemas/ToDoListSchema.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// Created by Helge Heß.
// Copyright © 2024 ZeeZide GmbH.
//

import ManagedModels

extension Fixtures {

enum ToDoListSchema: VersionedSchema {
static var models : [ any PersistentModel.Type ] = [
ToDo.self, ToDoList.self
]

public static let versionIdentifier = Schema.Version(0, 1, 0)

@Model
final class ToDo: NSManagedObject {

var title : String
var isDone : Bool
var priority : Priority
var created : Date
var due : Date?
var list : ToDoList

enum Priority: Int, Comparable, CaseIterable, Codable {
case veryLow = 1
case low = 2
case medium = 3
case high = 4
case veryHigh = 5

static func < (lhs: Self, rhs: Self) -> Bool {
lhs.rawValue < rhs.rawValue
}
}

convenience init(list : ToDoList,
title : String,
isDone : Bool = false,
priority : Priority = .medium,
created : Date = Date(),
due : Date? = nil)
{
// This is important so that the objects don't end up in different
// contexts.
self.init(context: list.modelContext)

self.list = list
self.title = title
self.isDone = isDone
self.priority = priority
self.created = created
self.due = due
}

var isOverDue : Bool {
guard let due else { return false }
return due < Date()
}
}

@Model
final class ToDoList: NSManagedObject {

var title = ""
var toDos = [ ToDo ]()

convenience init(title: String) {
self.init()
self.title = title
}

var hasOverdueItems : Bool { toDos.contains { $0.isOverDue && !$0.isDone } }

enum Doneness { case all, none, some }

var doneness : Doneness {
let hasDone = toDos.contains { $0.isDone }
let hasUndone = toDos.contains { !$0.isDone }
switch ( hasDone, hasUndone ) {
case ( true , true ) : return .some
case ( true , false ) : return .all
case ( false , true ) : return .none
case ( false , false ) : return .all // empty
}
}
}
}
}

0 comments on commit b4db7ac

Please sign in to comment.