Skip to content

Commit

Permalink
Upgrade to Spezi 1.0 releases (#45)
Browse files Browse the repository at this point in the history
# Upgrade to Spezi 1.0 releases

## ♻️ Current situation & Problem
This PR upgrades to the latest Spezi 1.0 releases. Further, we made our
Standard constraints protocol naming consistent with the rest of the
ecosystem. Lastly, we replaced a `preconditionFailure` with a log
message to avoid some unnecessary crashes.


## ⚙️ Release Notes 
* Upgrade to latest Spezi 1.0 releases
* Renamed `AccountNotifyStandard` and `AccountStorageStandard` to
`AccountNotifyConstraint` and `AccountStorageConstraint` to be more
consistent with the rest of the Spezi framework ecosystem.

## 📝 Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordSpezi/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordSpezi/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
Supereg authored Jan 10, 2024
1 parent 3de710c commit f1d9262
Show file tree
Hide file tree
Showing 22 changed files with 47 additions and 49 deletions.
10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ let package = Package(
.library(name: "SpeziAccount", targets: ["SpeziAccount"])
],
dependencies: [
.package(url: "https://github.com/StanfordSpezi/SpeziFoundation.git", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/StanfordSpezi/Spezi", .upToNextMinor(from: "0.8.0")),
.package(url: "https://github.com/StanfordSpezi/SpeziViews", .upToNextMinor(from: "0.6.1")),
.package(url: "https://github.com/StanfordBDHG/XCTRuntimeAssertions", .upToNextMinor(from: "0.2.5")),
.package(url: "https://github.com/apple/swift-collections.git", .upToNextMajor(from: "1.0.4"))
.package(url: "https://github.com/StanfordSpezi/SpeziFoundation.git", from: "1.0.0"),
.package(url: "https://github.com/StanfordSpezi/Spezi", from: "1.0.0"),
.package(url: "https://github.com/StanfordSpezi/SpeziViews", from: "1.0.0"),
.package(url: "https://github.com/StanfordBDHG/XCTRuntimeAssertions", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.4")
],
targets: [
.target(
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ framework provides the [`FirebaseAccountConfiguration`](https://swiftpackageinde
you can use to configure an Account Service base on the Google Firebase service.


## Setup
### Setup

You need to add the Spezi Account Swift package to
[your app in Xcode](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#) or
Expand Down
12 changes: 5 additions & 7 deletions Sources/SpeziAccount/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -220,16 +220,14 @@ public final class Account: Sendable {
}
}

if let existingDetails = self.details {
precondition(
existingDetails.accountService.id == details.accountService.id,
"The AccountService \(details.accountService) tried to overwrite `AccountDetails` from \(existingDetails.accountService)!"
)
if let existingDetails = self.details,
existingDetails.accountService.id != details.accountService.id {
logger.warning("The AccountService \(details.accountService.description) is overwriting `AccountDetails` from \(existingDetails.accountService.description)!")
}

// Check if the account service is wrapped with a storage standard. If that's the case, contact them about the signup!
if let standardBacked = details.accountService as? any _StandardBacked,
let storageStandard = standardBacked.standard as? any AccountStorageStandard {
let storageStandard = standardBacked.standard as? any AccountStorageConstraint {
let recordId = AdditionalRecordId(serviceId: standardBacked.backedId, accountId: details.accountId)

try await standardBacked.preUserDetailsSupply(recordId: recordId)
Expand Down Expand Up @@ -257,7 +255,7 @@ public final class Account: Sendable {
public func removeUserDetails() async {
if let details,
let standardBacked = details.accountService as? any _StandardBacked,
let storageStandard = standardBacked.standard as? any AccountStorageStandard {
let storageStandard = standardBacked.standard as? any AccountStorageConstraint {
let recordId = AdditionalRecordId(serviceId: standardBacked.backedId, accountId: details.accountId)

await storageStandard.clear(recordId)
Expand Down
6 changes: 3 additions & 3 deletions Sources/SpeziAccount/AccountConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public final class AccountConfiguration: Module {
// If applicable, wraps the service into an StandardBackedAccountService
let service = verifyConfigurationRequirements(against: service)

if let notifyStandard = standard as? any AccountNotifyStandard {
if let notifyStandard = standard as? any AccountNotifyConstraint {
return service.backedBy(standard: notifyStandard)
}

Expand Down Expand Up @@ -112,7 +112,7 @@ public final class AccountConfiguration: Module {
}


if let accountStandard = standard as? any AccountStorageStandard {
if let accountStandard = standard as? any AccountStorageConstraint {
// we are also fine, we have a standard that can store any unsupported account values
logger.debug("""
The standard \(accountStandard.description) is used to store the following account values that \
Expand All @@ -132,7 +132,7 @@ public final class AccountConfiguration: Module {
The Account Service \(service.description) indicated that it cannot store the above-listed account values.
In order to proceed you may use a Standard inside your Spezi Configuration that conforms to \
`AccountStorageStandard` which handles storage of the above-listed account values. Otherwise, you may \
`AccountStorageConstraint` which handles storage of the above-listed account values. Otherwise, you may \
remove the above-listed account values from your SpeziAccount configuration.
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Spezi
///
/// ### Access Account
/// - ``Spezi/Standard/AccountReference``
public protocol AccountNotifyStandard: Standard {
public protocol AccountNotifyConstraint: Standard {
/// Notifies the Standard that the associated account was requested to be deleted by the user.
///
/// Use this method to cleanup any account related data that might be associated with the account.
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpeziAccount/AccountService/AccountService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public protocol AccountService: AnyObject, Hashable, CustomStringConvertible, Se
/// This identifier is used to uniquely identify an account service that persists across process instances.
///
/// - Important: A default implementation is defined that relies on the type name. If you rename the account service
/// type without supplying a manual `id` implementation, components like a ``AccountStorageStandard`` won't
/// type without supplying a manual `id` implementation, components like a ``AccountStorageConstraint`` won't
/// be able to associate existing user details with this account service.
var id: String { get }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public struct AccountServiceConfiguration: Sendable {
/// - Parameters:
/// - name: The name of the ``AccountService``. Refer to ``AccountServiceName`` for more information.
/// - supportedKeys: The set of ``SupportedAccountKeys`` the ``AccountService`` is capable of storing itself.
/// If ``SupportedAccountKeys/exactly(_:)`` is chosen, the user is responsible of providing a ``AccountStorageStandard``
/// If ``SupportedAccountKeys/exactly(_:)`` is chosen, the user is responsible of providing a ``AccountStorageConstraint``
/// that is capable of handling all non-supported ``AccountKey``s.
public init(name: LocalizedStringResource, supportedKeys: SupportedAccountKeys) {
self.storage = Self.createStorage(name: name, supportedKeys: supportedKeys)
Expand All @@ -68,7 +68,7 @@ public struct AccountServiceConfiguration: Sendable {
/// - Parameters:
/// - name: The name of the ``AccountService``. Refer to ``AccountServiceName`` for more information.
/// - supportedKeys: The set of ``SupportedAccountKeys`` the ``AccountService`` is capable of storing itself.
/// If ``SupportedAccountKeys/exactly(_:)`` is chosen, the user is responsible of providing a ``AccountStorageStandard``
/// If ``SupportedAccountKeys/exactly(_:)`` is chosen, the user is responsible of providing a ``AccountStorageConstraint``
/// that is capable of handling all non-supported ``AccountKey``s.
/// - configuration: A ``AccountServiceConfigurationBuilder`` to provide a list of ``AccountServiceConfigurationKey``s.
public init(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// capable of storing.
///
/// Upon startup, `SpeziAccount` automatically verifies that the user-configured account values match what the
/// ``AccountService`` is capable of storing or that the user provides a ``AccountStorageStandard`` conforming
/// ``AccountService`` is capable of storing or that the user provides a ``AccountStorageConstraint`` conforming
/// `Standard` in their app that is used to handle storage of all unsupported account values.
///
/// Access the configuration via the ``AccountServiceConfiguration/supportedAccountKeys``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import Foundation
/// A embeddable ``AccountService`` allows to render simplified UI in the ``AccountSetup`` view.
///
/// By default, the ``AccountSetup`` renders all ``AccountService`` as a list of buttons that navigate
/// to ``AccountSetupViewStyle/makePrimaryView()`` where login and signup flows are completely defined by the ``AccountService``.
/// to ``AccountSetupViewStyle/makePrimaryView(_:)`` where login and signup flows are completely defined by the ``AccountService``.
///
/// However, if there is a single `EmbeddableAccountService` in the list of all configured account service, this
/// account service is directly embedded into the main ``AccountSetup`` view for easier access.
/// The view is rendered using ``EmbeddableAccountSetupViewStyle/makeEmbeddedAccountView()``
/// The view is rendered using ``EmbeddableAccountSetupViewStyle/makeEmbeddedAccountView(_:)``
public protocol EmbeddableAccountService: AccountService where ViewStyle: EmbeddableAccountSetupViewStyle {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Spezi


actor NotifyStandardBackedAccountService<Service: AccountService, Standard: AccountNotifyStandard>: AccountService, _StandardBacked {
actor NotifyStandardBackedAccountService<Service: AccountService, Standard: AccountNotifyConstraint>: AccountService, _StandardBacked {
@AccountReference private var account

let accountService: Service
Expand Down
10 changes: 5 additions & 5 deletions Sources/SpeziAccount/AccountService/Wrapper/StandardBacked.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Spezi


/// Internal marker protocol to determine what ``AccountService`` require assistance by a ``AccountStorageStandard``.
/// Internal marker protocol to determine what ``AccountService`` require assistance by a ``AccountStorageConstraint``.
public protocol _StandardBacked: AccountService { // swiftlint:disable:this type_name
associatedtype Service: AccountService
associatedtype AccountStandard: Standard
Expand Down Expand Up @@ -88,24 +88,24 @@ extension _StandardBacked where Self: UserIdPasswordAccountService, Service: Use


extension AccountService {
func backedBy(standard: any AccountStorageStandard) -> any AccountService {
func backedBy(standard: any AccountStorageConstraint) -> any AccountService {
standard.backedService(with: self)
}

func backedBy(standard: any AccountNotifyStandard) -> any AccountService {
func backedBy(standard: any AccountNotifyConstraint) -> any AccountService {
standard.backedService(with: self)
}
}


extension AccountStorageStandard {
extension AccountStorageConstraint {
fileprivate nonisolated func backedService<Service: AccountService>(with service: Service) -> any AccountService {
StorageStandardBackedAccountService(service: service, standard: self)
}
}


extension AccountNotifyStandard {
extension AccountNotifyConstraint {
fileprivate nonisolated func backedService<Service: AccountService>(with service: Service) -> any AccountService {
NotifyStandardBackedAccountService(service: service, standard: self)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import Spezi


/// An ``AccountService`` implementation for account services with ``SupportedAccountKeys/exactly(_:)`` configuration
/// to forward unsupported account values to a ``AccountStorageStandard`` implementation.
actor StorageStandardBackedAccountService<Service: AccountService, Standard: AccountStorageStandard>: AccountService, _StandardBacked {
/// to forward unsupported account values to a ``AccountStorageConstraint`` implementation.
actor StorageStandardBackedAccountService<Service: AccountService, Standard: AccountStorageConstraint>: AccountService, _StandardBacked {
@AccountReference private var account

let accountService: Service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public protocol AccountSetupViewStyle {
@ViewBuilder
func makeServiceButtonLabel(_ service: any AccountService) -> ButtonLabel

/// The primary view that is opened as the destination of the ``makeServiceButtonLabel()-6ihdh`` button.
/// The primary view that is opened as the destination of the ``makeServiceButtonLabel(_:)-54dx4`` button.
@ViewBuilder
func makePrimaryView(_ service: any AccountService) -> PrimaryView

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import Spezi
///
/// Certain ``AccountService`` implementations might be limited to supported only a specific set of ``AccountKey``s
/// (see ``SupportedAccountKeys/exactly(_:)``. If you nonetheless want to use ``AccountKey``s that are unsupported
/// by your ``AccountService``, you may add an implementation of the `AccountStorageStandard` protocol to your App's `Standard`,
/// by your ``AccountService``, you may add an implementation of the `AccountStorageConstraint` protocol to your App's `Standard`,
/// inorder to handle storage and retrieval of these additional account values.
///
/// - Note: You can use the ``Spezi/Standard/AccountReference`` property wrapper to get access to the global ``Account`` object if you need it to implement additional functionality.
Expand All @@ -22,7 +22,7 @@ import Spezi
///
/// ### Access Account
/// - ``Spezi/Standard/AccountReference``
public protocol AccountStorageStandard: Standard {
public protocol AccountStorageConstraint: Standard {
/// Create new associated account data.
///
/// - Note: A call to this method might certainly be immediately followed by a call to ``load(_:_:)``.
Expand Down Expand Up @@ -85,7 +85,7 @@ extension Standard {
///
/// Below is a short code example on how to use this property wrapper:
/// ```swift
/// public actor MyStandard: AccountStorageStandard {
/// public actor MyStandard: AccountStorageConstraint {
/// @AccountReference var account
/// }
/// ```
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpeziAccount/AccountValue/AccountKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import XCTRuntimeAssertions
/// can be safely passed between actor boundaries.
/// `Equatable` conformance is required such that views like the ``SignupForm`` can react to changes
/// and validate input.
/// `Codable` conformance is required such that ``AccountService``s of ``AccountStorageStandard``s
/// `Codable` conformance is required such that ``AccountService``s of ``AccountStorageConstraint``s
/// can easily store arbitrarily defined account values.
///
/// ## Topics
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpeziAccount/Model/AdditionalRecordId.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//


/// A stable identifier used by ``AccountStorageStandard`` instances to identity a set of additionally stored records.
/// A stable identifier used by ``AccountStorageConstraint`` instances to identity a set of additionally stored records.
///
/// The identifier is built by combining a stable ``AccountService`` identifier and the primary accountID (see ``AccountIdKey``).
/// Using both, additional data records of a user can be uniquely identified across ``AccountService`` implementations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Your `Value` type requires several protocol conformances.

* The `Value` type must conform to `Sendable` to be safely passed across actor boundaries.
* The `Value` type must conform to `Equatable` to be easily notified about changes at data entry.
* The `Value` type must conform to `Codable` such that ``AccountService``s or a ``AccountStorageStandard`` can easily store and retrieve
* The `Value` type must conform to `Codable` such that ``AccountService``s or a ``AccountStorageConstraint`` can easily store and retrieve
arbitrary `Value` types.

### Accessors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ let encoded = details.acceptAll(&visitor)
You can iterate through a collection of ``AccountKey``s in a type-safe way using the [Visitor Pattern](https://en.wikipedia.org/wiki/Visitor_pattern).
This is provided through the ``AccountKeyVisitor`` protocol and the ``AcceptingAccountKeyVisitor/acceptAll(_:)-1ytax`` method all implemented by
`[any AccountKey.Type]` arrays or ``AccountKeyCollection``s. This is useful when you are accessing the ``AccountValues/keys-572sk`` property or
implement a custom storage provider (see ``AccountStorageStandard/load(_:_:)``).
implement a custom storage provider (see ``AccountStorageConstraint/load(_:_:)``).

An implementation is similarly structured to the code example shown in the previous section.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom Storage Provider

Store arbitrary account values by providing a ``AccountStorageStandard`` implementation.
Store arbitrary account values by providing a ``AccountStorageConstraint`` implementation.

<!--
Expand All @@ -16,13 +16,13 @@ SPDX-License-Identifier: MIT

In certain cases, a given ``AccountService`` implementation might be limited to storing only a fixed set of account values.
If you have ``ConfiguredAccountKey``s that are not part of the ``SupportedAccountKeys`` set of a configured ``AccountService``
you can provide a ``AccountStorageStandard`` conformance to your `Spezi`
you can provide a ``AccountStorageConstraint`` conformance to your `Spezi`
[Standard](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/standard) to handle storage of additional
account values.

### Define the Conformance

Refer to the documentation of the ``AccountStorageStandard`` protocol for more information on the required implementation.
Refer to the documentation of the ``AccountStorageConstraint`` protocol for more information on the required implementation.

Contact the [Standard Conformance](https://swiftpackageindex.com/stanfordspezi/spezi/documentation/spezi/standard#1-Standard-Conformance)
section of the `Spezi` documentation on how to conform to `Standard` constraints.
Expand All @@ -43,15 +43,15 @@ var configuration: Configuration {
}
```

> Note: Your ``AccountStorageStandard`` will be used
> Note: Your ``AccountStorageConstraint`` will be used
to handle data flow for all configured ``AccountService``s that do not support at least one
``ConfiguredAccountKey``.

## Topics

### Providing Storage

- ``AccountStorageStandard``
- ``AccountStorageConstraint``

### Identifying Additional Storage Records

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ operations. ``AccountService``s can be manually provided via the ``AccountConfig
Otherwise, ``AccountService``s might be directly provided by other Spezi `Componet`s (like the `FirebaseAccountConfiguration`).

> Note: A given ``AccountService`` implementation might only support storing a fixed set of account values (see ``SupportedAccountKeys``).
In those cases you may be required to supply your own ``AccountStorageStandard`` implementation
In those cases you may be required to supply your own ``AccountStorageConstraint`` implementation
to handle storage of additional account values. Refer to the <doc:Custom-Storage-Provider> article for information.

### Account Setup
Expand Down Expand Up @@ -132,4 +132,4 @@ struct MyView: View {

### Reacting to Events

- ``AccountNotifyStandard``
- ``AccountNotifyConstraint``
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct AccountServiceButtonModifier: ViewModifier {


extension View {
/// Draw the standard background of a ``AccountService`` button (see ``AccountSetupViewStyle/makeServiceButtonLabel()-6ihdh``.
/// Draw the standard background of a ``AccountService`` button (see ``AccountSetupViewStyle/makeServiceButtonLabel(_:)-54dx4``.
public func accountServiceButtonBackground() -> some View {
modifier(AccountServiceButtonModifier())
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/UITests/TestApp/AccountTests/TestStandard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import SpeziAccount
import SwiftUI


// mock implementation of the AccountStorageStandard
actor TestStandard: AccountStorageStandard, AccountNotifyStandard, EnvironmentAccessible {
// mock implementation of the AccountStorageConstraint
actor TestStandard: AccountStorageConstraint, AccountNotifyConstraint, EnvironmentAccessible {
@MainActor @Published var deleteNotified = false

var records: [AdditionalRecordId: PartialAccountDetails.Builder] = [:]
Expand Down

0 comments on commit f1d9262

Please sign in to comment.