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
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct FileCabinetDetailView: View {
)
}

@ViewBuilder @MainActor
@MainActor
private func sidebar() -> some View {
VStack {
Text(viewModel.state.fileCabinet.id.uuidString)
Expand All @@ -44,12 +44,12 @@ struct FileCabinetDetailView: View {
}
}

@ViewBuilder @MainActor
@MainActor
private func content() -> some View {
EmptyView()
}

@ViewBuilder @MainActor
@MainActor
private func detail() -> some View {
EmptyView()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct FileCabinetsView: View {
)
}

@ViewBuilder @MainActor
@MainActor
private func sidebar() -> some View {
VStack {
Button(
Expand Down Expand Up @@ -55,7 +55,7 @@ struct FileCabinetsView: View {
}
}

@ViewBuilder @MainActor
@MainActor
private func detail() -> some View {
EmptyView()
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/CoreDataRepository/CoreDataBatchError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
/// Batch operations that do not use `NSBatch*Request` are not atomic. Some operations may succeed while others fail. If
/// multiple errors are returned, it would
/// be helpful if each error is associated with the input data for the operation.
public struct CoreDataBatchError<T>: Error where T: Sendable {
public struct CoreDataBatchError<T: Sendable>: Error {
/// The input data used for the batched operation. Usually an ``UnmanagedModel`` instance or URL encoded
/// NSManagedObjectID.
public let item: T
Expand Down
75 changes: 37 additions & 38 deletions Sources/CoreDataRepository/CoreDataRepository+Aggregate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ extension CoreDataRepository {
}

@inlinable
public func aggregate<Value>(
public func aggregate<Value: Numeric & Sendable>(
function: AggregateFunction,
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as valueType: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
switch function {
case .count:
await count(predicate: predicate, entityDesc: entityDesc, as: valueType)
Expand All @@ -46,13 +46,13 @@ extension CoreDataRepository {

/// Get the average of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func average<Value>(
public func average<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
await Self.send(
function: .average,
context: Transaction.current?.context ?? context,
Expand All @@ -65,13 +65,13 @@ extension CoreDataRepository {

/// Subscribe to the average of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func averageSubscription<Value>(
public func averageSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncStream<Result<Value, CoreDataError>> where Value: Numeric, Value: Sendable {
) -> AsyncStream<Result<Value, CoreDataError>> {
AsyncStream { continuation in
let subscription = AggregateSubscription(
function: .average,
Expand All @@ -91,13 +91,13 @@ extension CoreDataRepository {

/// Subscribe to the average of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func averageThrowingSubscription<Value>(
public func averageThrowingSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncThrowingStream<Value, Error> where Value: Numeric, Value: Sendable {
) -> AsyncThrowingStream<Value, Error> {
AsyncThrowingStream { continuation in
let subscription = AggregateThrowingSubscription(
function: .average,
Expand All @@ -119,11 +119,11 @@ extension CoreDataRepository {

/// Get the count or quantity of managed object instances that satisfy the predicate.
@inlinable
public func count<Value>(
public func count<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
as _: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
await context.performInChild { scratchPad in
do {
let request = try NSFetchRequest<NSDictionary>
Expand All @@ -140,11 +140,11 @@ extension CoreDataRepository {

/// Subscribe to the count or quantity of managed object instances that satisfy the predicate.
@inlinable
public func countSubscription<Value>(
public func countSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
as _: Value.Type
) -> AsyncStream<Result<Value, CoreDataError>> where Value: Numeric, Value: Sendable {
) -> AsyncStream<Result<Value, CoreDataError>> {
AsyncStream { continuation in
let subscription = CountSubscription(
context: context.childContext(),
Expand All @@ -161,11 +161,11 @@ extension CoreDataRepository {

/// Subscribe to the count or quantity of managed object instances that satisfy the predicate.
@inlinable
public func countThrowingSubscription<Value>(
public func countThrowingSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
as _: Value.Type
) -> AsyncThrowingStream<Value, Error> where Value: Numeric, Value: Sendable {
) -> AsyncThrowingStream<Value, Error> {
AsyncThrowingStream { continuation in
let subscription = CountThrowingSubscription(
context: context.childContext(),
Expand All @@ -184,13 +184,13 @@ extension CoreDataRepository {

/// Get the max or maximum of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func max<Value>(
public func max<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
await Self.send(
function: .max,
context: Transaction.current?.context ?? context,
Expand All @@ -204,13 +204,13 @@ extension CoreDataRepository {
/// Subscribe to the max or maximum of a managed object's numeric property for all instances that satisfy the
/// predicate.
@inlinable
public func maxSubscription<Value>(
public func maxSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncStream<Result<Value, CoreDataError>> where Value: Numeric, Value: Sendable {
) -> AsyncStream<Result<Value, CoreDataError>> {
AsyncStream { continuation in
let subscription = AggregateSubscription(
function: .max,
Expand All @@ -231,13 +231,13 @@ extension CoreDataRepository {
/// Subscribe to the max or maximum of a managed object's numeric property for all instances that satisfy the
/// predicate.
@inlinable
public func maxThrowingSubscription<Value>(
public func maxThrowingSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncThrowingStream<Value, Error> where Value: Numeric, Value: Sendable {
) -> AsyncThrowingStream<Value, Error> {
AsyncThrowingStream { continuation in
let subscription = AggregateThrowingSubscription(
function: .max,
Expand All @@ -259,13 +259,13 @@ extension CoreDataRepository {

/// Get the min or minimum of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func min<Value>(
public func min<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
await Self.send(
function: .min,
context: Transaction.current?.context ?? context,
Expand All @@ -279,13 +279,13 @@ extension CoreDataRepository {
/// Subscribe to the min or minimum of a managed object's numeric property for all instances that satisfy the
/// predicate.
@inlinable
public func minSubscription<Value>(
public func minSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncStream<Result<Value, CoreDataError>> where Value: Numeric, Value: Sendable {
) -> AsyncStream<Result<Value, CoreDataError>> {
AsyncStream { continuation in
let subscription = AggregateSubscription(
function: .min,
Expand All @@ -306,13 +306,13 @@ extension CoreDataRepository {
/// Subscribe to the min or minimum of a managed object's numeric property for all instances that satisfy the
/// predicate.
@inlinable
public func minThrowingSubscription<Value>(
public func minThrowingSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncThrowingStream<Value, Error> where Value: Numeric, Value: Sendable {
) -> AsyncThrowingStream<Value, Error> {
AsyncThrowingStream { continuation in
let subscription = AggregateThrowingSubscription(
function: .min,
Expand All @@ -334,13 +334,13 @@ extension CoreDataRepository {

/// Get the sum of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func sum<Value>(
public func sum<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
await Self.send(
function: .sum,
context: Transaction.current?.context ?? context,
Expand All @@ -353,13 +353,13 @@ extension CoreDataRepository {

/// Subscribe to the sum of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func sumSubscription<Value>(
public func sumSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncStream<Result<Value, CoreDataError>> where Value: Numeric, Value: Sendable {
) -> AsyncStream<Result<Value, CoreDataError>> {
AsyncStream { continuation in
let subscription = AggregateSubscription(
function: .sum,
Expand All @@ -379,13 +379,13 @@ extension CoreDataRepository {

/// Subscribe to the sum of a managed object's numeric property for all instances that satisfy the predicate.
@inlinable
public func sumThrowingSubscription<Value>(
public func sumThrowingSubscription<Value: Numeric & Sendable>(
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil,
as _: Value.Type
) -> AsyncThrowingStream<Value, Error> where Value: Numeric, Value: Sendable {
) -> AsyncThrowingStream<Value, Error> {
AsyncThrowingStream { continuation in
let subscription = AggregateThrowingSubscription(
function: .sum,
Expand All @@ -405,10 +405,10 @@ extension CoreDataRepository {

// MARK: Internals

private static func aggregate<Value>(
private static func aggregate<Value: Numeric & Sendable>(
context: NSManagedObjectContext,
request: NSFetchRequest<NSDictionary>
) throws -> Value where Value: Numeric, Value: Sendable {
) throws -> Value {
let result = try context.fetch(request)
guard let value: Value = result.asAggregateValue() else {
throw CoreDataError.fetchedObjectFailedToCastToExpectedType
Expand All @@ -417,14 +417,14 @@ extension CoreDataRepository {
}

@usableFromInline
static func send<Value>(
static func send<Value: Numeric & Sendable>(
function: AggregateFunction,
context: NSManagedObjectContext,
predicate: NSPredicate,
entityDesc: NSEntityDescription,
attributeDesc: NSAttributeDescription,
groupBy: NSAttributeDescription? = nil
) async -> Result<Value, CoreDataError> where Value: Numeric, Value: Sendable {
) async -> Result<Value, CoreDataError> {
guard entityDesc == attributeDesc.entity else {
return .failure(.propertyDoesNotMatchEntity)
}
Expand All @@ -437,8 +437,7 @@ extension CoreDataRepository {
groupBy: groupBy
)
do {
let value: Value = try Self.aggregate(context: scratchPad, request: request)
return value
return try Self.aggregate(context: scratchPad, request: request)
} catch let error as CocoaError {
throw CoreDataError.cocoa(error)
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ extension CoreDataRepository {
return await context.performInScratchPad(schedule: .enqueued) { [context] scratchPad in
scratchPad.transactionAuthor = transactionAuthor
let objects = try items.map { item in
let object = try item.asManagedModel(in: scratchPad)
return object
try item.asManagedModel(in: scratchPad)
}
try scratchPad.save()
if notTransaction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ extension CoreDataRepository {
///
/// This operation is non-atomic. Each instance may succeed or fail individually.
@inlinable
public func delete<Model>(
public func delete<Model: ReadableUnmanagedModel>(
_ items: [Model],
transactionAuthor: String? = nil
) async -> (success: [Model], failed: [CoreDataBatchError<Model>]) where Model: ReadableUnmanagedModel {
) async -> (success: [Model], failed: [CoreDataBatchError<Model>]) {
var successes = [Model]()
var failures = [CoreDataBatchError<Model>]()
for item in items {
Expand Down
4 changes: 2 additions & 2 deletions Sources/CoreDataRepository/CoreDataRepository+Fetch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ extension CoreDataRepository {

/// Fetch items from the store with a ``NSFetchRequest`` and transform the results.
@inlinable
public func fetch<Managed, Output>(
public func fetch<Managed: NSManagedObject, Output>(
request: NSFetchRequest<Managed>,
operation: @escaping (_ results: [Managed]) throws -> Output
) async -> Result<Output, CoreDataError> where Managed: NSManagedObject {
) async -> Result<Output, CoreDataError> {
let context = Transaction.current?.context ?? context
return await context.performInChild { fetchContext in
try operation(fetchContext.fetch(request))
Expand Down
Loading