Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/MistDemo-Integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ on:
branches:
- main
- 'v*.*.*'
- 'claude/**'
workflow_dispatch:

concurrency:
Expand Down
8 changes: 0 additions & 8 deletions Sources/MistKit/Models/ConversionError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,6 @@ public import Foundation
public enum ConversionError: LocalizedError, Sendable, Equatable {
/// A field value's structure matched no known `FieldValue` case.
case unmappableFieldValue(fieldName: String, value: String, type: String?)
/// A location field was missing its latitude and/or longitude.
case locationMissingCoordinates(fieldName: String)
/// A reference field was missing its `recordName`.
case referenceMissingRecordName(fieldName: String)
/// A list element matched no known `FieldValue` case.
case unmappableListItem(fieldName: String, item: String)
/// A nested-list element was not one of the supported basic types.
Expand Down Expand Up @@ -73,10 +69,6 @@ public enum ConversionError: LocalizedError, Sendable, Equatable {
case .unmappableFieldValue(let fieldName, let value, let type):
return "Unmappable FieldValue for field '\(fieldName)' "
+ "(value: \(value), type: \(type ?? "nil"))"
case .locationMissingCoordinates(let fieldName):
return "Location field '\(fieldName)' missing latitude/longitude"
case .referenceMissingRecordName(let fieldName):
return "Reference field '\(fieldName)' missing recordName"
case .unmappableListItem(let fieldName, let item):
return "Unmappable list item for field '\(fieldName)' (\(item))"
case .unmappableNestedListItem(let fieldName, let item):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ extension FieldValue {
fieldName: String
) throws(ConversionError) -> FieldValue? {
if case .LocationValue(let locationValue) = listItem {
return try Self(locationValue: locationValue, fieldName: fieldName)
return Self(locationValue: locationValue)
}
if case .ReferenceValue(let referenceValue) = listItem {
return try Self(referenceValue: referenceValue, fieldName: fieldName)
return Self(referenceValue: referenceValue)
}
if case .AssetValue(let assetValue) = listItem {
return Self(assetValue: assetValue)
Expand Down
28 changes: 9 additions & 19 deletions Sources/MistKit/Models/FieldValues/FieldValue+Components.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,11 @@ extension FieldValue {

/// Initialize from location field value
internal init(
locationValue: Components.Schemas.LocationValue,
fieldName: String
) throws(ConversionError) {
guard let latitude = locationValue.latitude,
let longitude = locationValue.longitude
else {
try ConversionError.locationMissingCoordinates(fieldName: fieldName).reportAndThrow()
}

locationValue: Components.Schemas.LocationValue
) {
let location = Location(
latitude: latitude,
longitude: longitude,
latitude: locationValue.latitude,
longitude: locationValue.longitude,
horizontalAccuracy: locationValue.horizontalAccuracy,
verticalAccuracy: locationValue.verticalAccuracy,
altitude: locationValue.altitude,
Expand All @@ -94,12 +87,9 @@ extension FieldValue {

/// Initialize from reference field value
internal init(
referenceValue: Components.Schemas.ReferenceValue,
fieldName: String
) throws(ConversionError) {
guard let recordName = referenceValue.recordName else {
try ConversionError.referenceMissingRecordName(fieldName: fieldName).reportAndThrow()
}
referenceValue: Components.Schemas.ReferenceValue
) {
let recordName = referenceValue.recordName
let action: Reference.Action?
switch referenceValue.action {
case .DELETE_SELF:
Expand Down Expand Up @@ -158,10 +148,10 @@ extension FieldValue {
fieldName: String
) throws(ConversionError) -> FieldValue? {
if case .LocationValue(let locationValue) = value {
return try Self(locationValue: locationValue, fieldName: fieldName)
return Self(locationValue: locationValue)
}
if case .ReferenceValue(let referenceValue) = value {
return try Self(referenceValue: referenceValue, fieldName: fieldName)
return Self(referenceValue: referenceValue)
}
if case .AssetValue(let assetValue) = value {
return Self(assetValue: assetValue)
Expand Down
12 changes: 6 additions & 6 deletions Sources/MistKitOpenAPI/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1157,11 +1157,11 @@ public enum Components {
/// Latitude in degrees
///
/// - Remark: Generated from `#/components/schemas/LocationValue/latitude`.
public var latitude: Swift.Double?
public var latitude: Swift.Double
/// Longitude in degrees
///
/// - Remark: Generated from `#/components/schemas/LocationValue/longitude`.
public var longitude: Swift.Double?
public var longitude: Swift.Double
/// Horizontal accuracy in meters
///
/// - Remark: Generated from `#/components/schemas/LocationValue/horizontalAccuracy`.
Expand Down Expand Up @@ -1198,8 +1198,8 @@ public enum Components {
/// - course: Course in degrees
/// - timestamp: Timestamp in milliseconds since epoch
public init(
latitude: Swift.Double? = nil,
longitude: Swift.Double? = nil,
latitude: Swift.Double,
longitude: Swift.Double,
horizontalAccuracy: Swift.Double? = nil,
verticalAccuracy: Swift.Double? = nil,
altitude: Swift.Double? = nil,
Expand Down Expand Up @@ -1234,7 +1234,7 @@ public enum Components {
/// The record name being referenced
///
/// - Remark: Generated from `#/components/schemas/ReferenceValue/recordName`.
public var recordName: Swift.String?
public var recordName: Swift.String
/// Action to perform on the referenced record
///
/// - Remark: Generated from `#/components/schemas/ReferenceValue/action`.
Expand All @@ -1252,7 +1252,7 @@ public enum Components {
/// - recordName: The record name being referenced
/// - action: Action to perform on the referenced record
public init(
recordName: Swift.String? = nil,
recordName: Swift.String,
action: Components.Schemas.ReferenceValue.actionPayload? = nil
) {
self.recordName = recordName
Expand Down
37 changes: 18 additions & 19 deletions Tests/MistKitTests/Models/ConversionFailureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,28 +53,27 @@ internal struct ConversionFailureTests {
)
}

@Test("FieldValue throws on a reference field missing recordName")
internal func referenceMissingRecordNameThrows() {
let response = Components.Schemas.FieldValueResponse(
value: .ReferenceValue(.init(recordName: nil))
@Test("An asset field value converts to .asset rather than a mis-typed location")
internal func assetFieldValueConvertsToAsset() throws {
// Regression: an asset value object carries no latitude/longitude, but while
// LocationValue's coordinates were optional the oneOf decoder greedily
// matched assets as locations, so conversion failed on a missing coordinate.
let json = Data(
#"{"value":{"fileChecksum":"chk","size":51200,"downloadURL":"https://example.com/a.bin"}}"#
.utf8
)
expectConversionThrow {
_ = try FieldValue(response, fieldName: "owner")
}
}

@Test("RecordInfo throws on a field that cannot be mapped")
internal func recordInfoThrowsOnReferenceWithoutRecordName() {
let record = Components.Schemas.RecordResponse(
recordName: "rec-1",
recordType: "Article",
fields: .init(additionalProperties: [
"owner": .init(value: .ReferenceValue(.init(recordName: nil)))
])
let response = try JSONDecoder().decode(
Components.Schemas.FieldValueResponse.self,
from: json
)
expectConversionThrow {
_ = try RecordInfo(from: record)

let field = try FieldValue(response, fieldName: "image")

guard case .asset(let asset) = field else {
Issue.record("Expected .asset, got \(field)")
return
}
#expect(asset.fileChecksum == "chk")
}

@Test("UserIdentity faithfully converts a non-discoverable user (nil userRecordName)")
Expand Down
5 changes: 5 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,9 @@ components:
LocationValue:
type: object
description: Location dictionary as defined in CloudKit Web Services
required:
- latitude
- longitude
properties:
latitude:
type: number
Expand Down Expand Up @@ -1116,6 +1119,8 @@ components:
ReferenceValue:
type: object
description: Reference dictionary as defined in CloudKit Web Services
required:
- recordName
properties:
recordName:
type: string
Expand Down