amplify-swift/Amplify/Categories/DataStore/Model/Model.swift

74 lines
2.7 KiB
Swift

//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
import Foundation
// MARK: - Model
/// All persistent models should conform to the Model protocol.
public protocol Model: Codable {
/// Alias of Model identifier (i.e. primary key)
@available(*, deprecated, message: "Use ModelIdentifier")
typealias Identifier = String
/// A reference to the `ModelSchema` associated with this model.
static var schema: ModelSchema { get }
/// The name of the model, as registered in `ModelRegistry`.
static var modelName: String { get }
/// Convenience property to return the Type's `modelName`. Developers are strongly encouraged not to override the
/// instance property, as an implementation that returns a different value for the instance property will cause
/// undefined behavior.
var modelName: String { get }
/// For internal use only when a model schema is provided
/// (i.e. calls from Flutter)
func identifier(schema: ModelSchema) -> ModelIdentifierProtocol
/// Convenience property to access the serialized value of a model identifier
var identifier: String { get }
}
extension Model {
public var identifier: String {
guard let schema = ModelRegistry.modelSchema(from: modelName) else {
preconditionFailure("Schema not found for \(modelName).")
}
return identifier(schema: schema).stringValue
}
public func identifier(schema modelSchema: ModelSchema) -> ModelIdentifierProtocol {
// resolve current instance identifier fields
let fields: ModelIdentifierProtocol.Fields = modelSchema.primaryKey.fields.map {
guard let fieldValue = self[$0.name] else {
preconditionFailure("Identifier field named \($0.name) for model \(modelSchema.name) not found.")
}
switch fieldValue {
case let value as Persistable:
return (name: $0.name, value: value)
case let value as EnumPersistable:
return (name: $0.name, value: value.rawValue)
default:
preconditionFailure(
"Invalid identifier value \(String(describing: fieldValue)) for field \($0.name) in model \(modelSchema.name)")
}
}
guard !modelSchema.fields.isEmpty else {
return DefaultModelIdentifier<Self>.makeDefault(fromModel: self)
}
if fields.count == 1, fields[0].name == ModelIdentifierFormat.Default.name {
return ModelIdentifier<Self, ModelIdentifierFormat.Default>(fields: fields)
} else {
return ModelIdentifier<Self, ModelIdentifierFormat.Custom>(fields: fields)
}
}
}