|
|
|
@@ -55,11 +55,11 @@ public protocol UnidentifiedEntityDescription: EntityDescription where Identifie
|
|
|
|
|
/// encoded to or decoded from a JSON API
|
|
|
|
|
/// "Resource Object."
|
|
|
|
|
/// See https://jsonapi.org/format/#document-resource-objects
|
|
|
|
|
public struct Entity<EntityType: JSONAPI.EntityDescription>: Codable, Equatable {
|
|
|
|
|
public typealias Identifier = EntityType.Identifier
|
|
|
|
|
public struct Entity<EntityDescription: JSONAPI.EntityDescription>: Codable, Equatable {
|
|
|
|
|
public typealias Identifier = EntityDescription.Identifier
|
|
|
|
|
|
|
|
|
|
/// The JSON API compliant "type" of this `Entity`.
|
|
|
|
|
public static var type: String { return EntityType.type }
|
|
|
|
|
public static var type: String { return EntityDescription.type }
|
|
|
|
|
|
|
|
|
|
/// The `Entity`'s Id. This can be of type `Unidentified` if
|
|
|
|
|
/// the entity is being created clientside and the
|
|
|
|
@@ -68,12 +68,12 @@ public struct Entity<EntityType: JSONAPI.EntityDescription>: Codable, Equatable
|
|
|
|
|
public let id: Identifier
|
|
|
|
|
|
|
|
|
|
/// The JSON API compliant attributes of this `Entity`.
|
|
|
|
|
public let attributes: EntityType.Attributes
|
|
|
|
|
public let attributes: EntityDescription.Attributes
|
|
|
|
|
|
|
|
|
|
/// The JSON API compliant relationships of this `Entity`.
|
|
|
|
|
public let relationships: EntityType.Relationships
|
|
|
|
|
public let relationships: EntityDescription.Relationships
|
|
|
|
|
|
|
|
|
|
public init(id: EntityType.Identifier, attributes: EntityType.Attributes, relationships: EntityType.Relationships) {
|
|
|
|
|
public init(id: EntityDescription.Identifier, attributes: EntityDescription.Attributes, relationships: EntityDescription.Relationships) {
|
|
|
|
|
self.id = id
|
|
|
|
|
self.attributes = attributes
|
|
|
|
|
self.relationships = relationships
|
|
|
|
@@ -81,52 +81,52 @@ public struct Entity<EntityType: JSONAPI.EntityDescription>: Codable, Equatable
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Convenience initializers
|
|
|
|
|
extension Entity where EntityType.Identifier: CreatableIdType {
|
|
|
|
|
public init(attributes: EntityType.Attributes, relationships: EntityType.Relationships) {
|
|
|
|
|
self.id = EntityType.Identifier()
|
|
|
|
|
extension Entity where EntityDescription.Identifier: CreatableIdType {
|
|
|
|
|
public init(attributes: EntityDescription.Attributes, relationships: EntityDescription.Relationships) {
|
|
|
|
|
self.id = EntityDescription.Identifier()
|
|
|
|
|
self.attributes = attributes
|
|
|
|
|
self.relationships = relationships
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Attributes == NoAttributes {
|
|
|
|
|
public init(id: EntityType.Identifier, relationships: EntityType.Relationships) {
|
|
|
|
|
extension Entity where EntityDescription.Attributes == NoAttributes {
|
|
|
|
|
public init(id: EntityDescription.Identifier, relationships: EntityDescription.Relationships) {
|
|
|
|
|
self.init(id: id, attributes: NoAttributes(), relationships: relationships)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Attributes == NoAttributes, EntityType.Identifier: CreatableIdType {
|
|
|
|
|
public init(relationships: EntityType.Relationships) {
|
|
|
|
|
extension Entity where EntityDescription.Attributes == NoAttributes, EntityDescription.Identifier: CreatableIdType {
|
|
|
|
|
public init(relationships: EntityDescription.Relationships) {
|
|
|
|
|
self.init(attributes: NoAttributes(), relationships: relationships)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Relationships == NoRelatives {
|
|
|
|
|
public init(id: EntityType.Identifier, attributes: EntityType.Attributes) {
|
|
|
|
|
extension Entity where EntityDescription.Relationships == NoRelatives {
|
|
|
|
|
public init(id: EntityDescription.Identifier, attributes: EntityDescription.Attributes) {
|
|
|
|
|
self.init(id: id, attributes: attributes, relationships: NoRelatives())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Relationships == NoRelatives, EntityType.Identifier: CreatableIdType {
|
|
|
|
|
public init(attributes: EntityType.Attributes) {
|
|
|
|
|
extension Entity where EntityDescription.Relationships == NoRelatives, EntityDescription.Identifier: CreatableIdType {
|
|
|
|
|
public init(attributes: EntityDescription.Attributes) {
|
|
|
|
|
self.init(attributes: attributes, relationships: NoRelatives())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Attributes == NoAttributes, EntityType.Relationships == NoRelatives {
|
|
|
|
|
public init(id: EntityType.Identifier) {
|
|
|
|
|
extension Entity where EntityDescription.Attributes == NoAttributes, EntityDescription.Relationships == NoRelatives {
|
|
|
|
|
public init(id: EntityDescription.Identifier) {
|
|
|
|
|
self.init(id: id, attributes: NoAttributes(), relationships: NoRelatives())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Entity where EntityType.Attributes == NoAttributes, EntityType.Relationships == NoRelatives, EntityType.Identifier: CreatableIdType {
|
|
|
|
|
extension Entity where EntityDescription.Attributes == NoAttributes, EntityDescription.Relationships == NoRelatives, EntityDescription.Identifier: CreatableIdType {
|
|
|
|
|
public init() {
|
|
|
|
|
self.init(attributes: NoAttributes(), relationships: NoRelatives())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Pointer for Relationships use.
|
|
|
|
|
public extension Entity where EntityType.Identifier: IdType {
|
|
|
|
|
public extension Entity where EntityDescription.Identifier: IdType {
|
|
|
|
|
/// Get a pointer to this entity that can be used as a
|
|
|
|
|
/// relationship to another entity.
|
|
|
|
|
public var pointer: ToOneRelationship<Entity> {
|
|
|
|
@@ -139,21 +139,21 @@ public extension Entity {
|
|
|
|
|
/// Access the attribute at the given keypath. This just
|
|
|
|
|
/// allows you to write `entity[\.propertyName]` instead
|
|
|
|
|
/// of `entity.relationships.propertyName`.
|
|
|
|
|
subscript<T, TFRM: Transformer>(_ path: KeyPath<EntityType.Attributes, TransformAttribute<T, TFRM>>) -> TFRM.To {
|
|
|
|
|
subscript<T, TFRM: Transformer>(_ path: KeyPath<EntityDescription.Attributes, TransformAttribute<T, TFRM>>) -> TFRM.To {
|
|
|
|
|
return attributes[keyPath: path].value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Access the attribute at the given keypath. This just
|
|
|
|
|
/// allows you to write `entity[\.propertyName]` instead
|
|
|
|
|
/// of `entity.relationships.propertyName`.
|
|
|
|
|
subscript<T, TFRM: Transformer>(_ path: KeyPath<EntityType.Attributes, TransformAttribute<T, TFRM>?>) -> TFRM.To? {
|
|
|
|
|
subscript<T, TFRM: Transformer>(_ path: KeyPath<EntityDescription.Attributes, TransformAttribute<T, TFRM>?>) -> TFRM.To? {
|
|
|
|
|
return attributes[keyPath: path]?.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Access the attribute at the given keypath. This just
|
|
|
|
|
/// allows you to write `entity[\.propertyName]` instead
|
|
|
|
|
/// of `entity.relationships.propertyName`.
|
|
|
|
|
subscript<T, TFRM: Transformer, U>(_ path: KeyPath<EntityType.Attributes, TransformAttribute<T, TFRM>?>) -> U? where TFRM.To == U? {
|
|
|
|
|
subscript<T, TFRM: Transformer, U>(_ path: KeyPath<EntityDescription.Attributes, TransformAttribute<T, TFRM>?>) -> U? where TFRM.To == U? {
|
|
|
|
|
return attributes[keyPath: path].flatMap { $0.value }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -163,14 +163,14 @@ public extension Entity {
|
|
|
|
|
/// Access to an Id of a `ToOneRelationship`.
|
|
|
|
|
/// This allows you to write `entity ~> \.other` instead
|
|
|
|
|
/// of `entity.relationships.other.id`.
|
|
|
|
|
public static func ~><OtherEntity: OptionalRelatable>(entity: Entity, path: KeyPath<EntityType.Relationships, ToOneRelationship<OtherEntity>>) -> OtherEntity.Identifier {
|
|
|
|
|
public static func ~><OtherEntity: OptionalRelatable>(entity: Entity, path: KeyPath<EntityDescription.Relationships, ToOneRelationship<OtherEntity>>) -> OtherEntity.Identifier {
|
|
|
|
|
return entity.relationships[keyPath: path].id
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Access to all Ids of a `ToManyRelationship`.
|
|
|
|
|
/// This allows you to write `entity ~> \.others` instead
|
|
|
|
|
/// of `entity.relationships.others.ids`.
|
|
|
|
|
public static func ~><OtherEntity: Relatable>(entity: Entity, path: KeyPath<EntityType.Relationships, ToManyRelationship<OtherEntity>>) -> [OtherEntity.Identifier] {
|
|
|
|
|
public static func ~><OtherEntity: Relatable>(entity: Entity, path: KeyPath<EntityDescription.Relationships, ToManyRelationship<OtherEntity>>) -> [OtherEntity.Identifier] {
|
|
|
|
|
return entity.relationships[keyPath: path].ids
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -191,15 +191,15 @@ public extension Entity {
|
|
|
|
|
|
|
|
|
|
try container.encode(Entity.type, forKey: .type)
|
|
|
|
|
|
|
|
|
|
if EntityType.Identifier.self != Unidentified.self {
|
|
|
|
|
if EntityDescription.Identifier.self != Unidentified.self {
|
|
|
|
|
try container.encode(id, forKey: .id)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if EntityType.Attributes.self != NoAttributes.self {
|
|
|
|
|
if EntityDescription.Attributes.self != NoAttributes.self {
|
|
|
|
|
try container.encode(attributes, forKey: .attributes)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if EntityType.Relationships.self != NoRelatives.self {
|
|
|
|
|
if EntityDescription.Relationships.self != NoRelatives.self {
|
|
|
|
|
try container.encode(relationships, forKey: .relationships)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -211,13 +211,13 @@ public extension Entity {
|
|
|
|
|
let type = try container.decode(String.self, forKey: .type)
|
|
|
|
|
|
|
|
|
|
guard Entity.type == type else {
|
|
|
|
|
throw JSONAPIEncodingError.typeMismatch(expected: EntityType.type, found: type)
|
|
|
|
|
throw JSONAPIEncodingError.typeMismatch(expected: EntityDescription.type, found: type)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
id = try (Unidentified() as? EntityType.Identifier) ?? container.decode(EntityType.Identifier.self, forKey: .id)
|
|
|
|
|
id = try (Unidentified() as? EntityDescription.Identifier) ?? container.decode(EntityDescription.Identifier.self, forKey: .id)
|
|
|
|
|
|
|
|
|
|
attributes = try (NoAttributes() as? EntityType.Attributes) ?? container.decode(EntityType.Attributes.self, forKey: .attributes)
|
|
|
|
|
attributes = try (NoAttributes() as? EntityDescription.Attributes) ?? container.decode(EntityDescription.Attributes.self, forKey: .attributes)
|
|
|
|
|
|
|
|
|
|
relationships = try (NoRelatives() as? EntityType.Relationships) ?? container.decode(EntityType.Relationships.self, forKey: .relationships)
|
|
|
|
|
relationships = try (NoRelatives() as? EntityDescription.Relationships) ?? container.decode(EntityDescription.Relationships.self, forKey: .relationships)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|