Skip to content

Commit c3bce1f

Browse files
author
Geor Kasapidi
committed
concurrency
1 parent bff7561 commit c3bce1f

26 files changed

+392
-338
lines changed

.github/workflows/swift.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ on:
99
jobs:
1010
build:
1111

12-
runs-on: macos-latest
12+
runs-on: macos-11
1313

1414
steps:
1515
- uses: actions/checkout@v2
16-
- name: Test
17-
run: xcodebuild -scheme Sworm-Package -destination 'platform=macOS,arch=x86_64' clean test
16+
- uses: maxim-lobanov/setup-xcode@v1.3.0
17+
with:
18+
xcode-version: '13.2'
19+
- name: Test 15
20+
run: xcodebuild -scheme Sworm-Package -destination 'platform=iOS Simulator,name=iPhone 13,OS=15.2' clean test

.swiftformat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
--self insert
2+
--wrapcollections before-first
3+
--wraparguments before-first
4+
--wrapparameters before-first
5+
--header strip
6+
--ifdef no-indent
7+
--enable wrapSwitchCases
8+
--swiftversion 5.5

Package.swift

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.3
1+
// swift-tools-version:5.5
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -22,14 +22,8 @@ let package = Package(
2222
),
2323
],
2424
targets: [
25-
.target(
26-
name: "Sworm",
27-
dependencies: []
28-
),
29-
.target(
30-
name: "SwormTools",
31-
dependencies: []
32-
),
25+
.target(name: "Sworm"),
26+
.target(name: "SwormTools"),
3327
.testTarget(
3428
name: "SwormTests",
3529
dependencies: ["Sworm", "SwormTools"]

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,6 @@ Use SPM:
4545

4646
``` swift
4747
dependencies: [
48-
.package(url: "https://github.com/geor-kasapidi/Sworm.git", .upToNextMajor(from: "1.0.0"))
48+
.package(url: "https://github.com/prisma-ai/Sworm.git", .upToNextMajor(from: "1.0.0"))
4949
]
5050
```
51-
52-
## Code style
53-
54-
`swiftformat --self insert --swiftversion 5.3 .`

Sources/Sworm/Attributes/Attribute.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
11
import CoreData
22

33
public final class Attribute<PlainObject: ManagedObjectConvertible>: Hashable {
4-
let name: String
5-
let keyPath: PartialKeyPath<PlainObject>
6-
7-
let encode: (PlainObject, NSManagedObject) -> Void
8-
let decode: (inout PlainObject, NSManagedObject) throws -> Void
9-
10-
public func hash(into hasher: inout Hasher) {
11-
self.keyPath.hash(into: &hasher)
12-
}
13-
14-
public static func == (lhs: Attribute<PlainObject>, rhs: Attribute<PlainObject>) -> Bool {
15-
lhs.keyPath == rhs.keyPath
16-
}
17-
184
public init<Attribute: SupportedAttributeType>(
195
_ keyPath: WritableKeyPath<PlainObject, Attribute>,
206
_ name: String
@@ -62,6 +48,20 @@ public final class Attribute<PlainObject: ManagedObjectConvertible>: Hashable {
6248
}
6349
}
6450
}
51+
52+
public static func == (lhs: Attribute<PlainObject>, rhs: Attribute<PlainObject>) -> Bool {
53+
lhs.keyPath == rhs.keyPath
54+
}
55+
56+
public func hash(into hasher: inout Hasher) {
57+
self.keyPath.hash(into: &hasher)
58+
}
59+
60+
let name: String
61+
let keyPath: PartialKeyPath<PlainObject>
62+
63+
let encode: (PlainObject, NSManagedObject) -> Void
64+
let decode: (inout PlainObject, NSManagedObject) throws -> Void
6565
}
6666

6767
extension ManagedObjectConvertible {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
public enum AttributeError: Swift.Error {
2+
case badInput(Any?)
3+
case badAttribute(Context)
4+
25
public struct Context {
36
public let name: String
47
public let entity: String
58
public let originalError: Swift.Error
69
}
7-
8-
case badInput(Any?)
9-
case badAttribute(Context)
1010
}

Sources/Sworm/DataHelper.swift

Lines changed: 0 additions & 67 deletions
This file was deleted.

Sources/Sworm/Extensions.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import CoreData
2+
3+
internal extension NSManagedObject {
4+
subscript(primitiveValue key: String) -> Any? {
5+
get {
6+
self.willAccessValue(forKey: key)
7+
defer { self.didAccessValue(forKey: key) }
8+
return self.primitiveValue(forKey: key)
9+
}
10+
set {
11+
self.willChangeValue(forKey: key)
12+
self.setPrimitiveValue(newValue, forKey: key)
13+
self.didChangeValue(forKey: key)
14+
}
15+
}
16+
}
17+
18+
internal extension NSManagedObjectContext {
19+
func execute<T>(
20+
_ reset: Bool,
21+
_ action: @escaping (ManagedObjectContext) throws -> T
22+
) throws -> T {
23+
defer {
24+
if reset {
25+
self.reset()
26+
}
27+
}
28+
let result = try action(.init(self))
29+
if self.hasChanges {
30+
try self.save()
31+
}
32+
return result
33+
}
34+
35+
func insert(entity name: String) -> NSManagedObject? {
36+
self.persistentStoreCoordinator
37+
.flatMap { $0.managedObjectModel.entitiesByName[name] }
38+
.flatMap { .init(entity: $0, insertInto: self) }
39+
}
40+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import CoreData
2+
3+
public final class PersistentContainer {
4+
public init(
5+
managedObjectContext: @escaping () throws -> NSManagedObjectContext,
6+
logError: ((Swift.Error) -> Void)? = nil,
7+
cleanUpAfterExecution: Bool = true
8+
) {
9+
self.managedObjectContext = managedObjectContext
10+
self.logError = logError
11+
self.cleanUpAfterExecution = cleanUpAfterExecution
12+
}
13+
14+
public enum Error: Swift.Error {
15+
case noResult
16+
}
17+
18+
@discardableResult
19+
public func perform<T>(
20+
action: @escaping (ManagedObjectContext) throws -> T
21+
) throws -> T {
22+
do {
23+
let context = try self.managedObjectContext()
24+
let reset = self.cleanUpAfterExecution
25+
26+
if #available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) {
27+
return try context.performAndWait {
28+
try context.execute(reset, action)
29+
}
30+
}
31+
32+
var result: Result<T, Swift.Error>?
33+
34+
context.performAndWait {
35+
result = Result(catching: {
36+
try context.execute(reset, action)
37+
})
38+
}
39+
40+
switch result {
41+
case let .success(value):
42+
return value
43+
case let .failure(error):
44+
throw error
45+
case .none:
46+
throw Self.Error.noResult
47+
}
48+
} catch {
49+
self.logError?(error)
50+
51+
throw error
52+
}
53+
}
54+
55+
#if canImport(_Concurrency)
56+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
57+
@discardableResult
58+
public func schedule<T>(
59+
action: @escaping (ManagedObjectContext) throws -> T
60+
) async throws -> T {
61+
do {
62+
let context = try self.managedObjectContext()
63+
let reset = self.cleanUpAfterExecution
64+
65+
if #available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *) {
66+
return try await context.perform(schedule: .immediate) {
67+
try context.execute(reset, action)
68+
}
69+
}
70+
71+
#if DEBUG
72+
return try await withCheckedThrowingContinuation { continuation in
73+
context.perform {
74+
continuation.resume(with: .init(catching: {
75+
try context.execute(reset, action)
76+
}))
77+
}
78+
}
79+
#else
80+
return try await withUnsafeThrowingContinuation { continuation in
81+
context.perform {
82+
continuation.resume(with: .init(catching: {
83+
try context.execute(reset, action)
84+
}))
85+
}
86+
}
87+
#endif
88+
} catch {
89+
self.logError?(error)
90+
91+
throw error
92+
}
93+
}
94+
#endif
95+
96+
private let managedObjectContext: () throws -> NSManagedObjectContext
97+
private let logError: ((Swift.Error) -> Void)?
98+
private let cleanUpAfterExecution: Bool
99+
}

Sources/Sworm/Relations.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
public struct ToOneRelation<Destination: ManagedObjectConvertible> {
2-
let name: String
3-
42
public init(_ name: String) {
53
self.name = name
64
}
7-
}
85

9-
public struct ToManyRelation<Destination: ManagedObjectConvertible> {
106
let name: String
7+
}
118

9+
public struct ToManyRelation<Destination: ManagedObjectConvertible> {
1210
public init(_ name: String) {
1311
self.name = name
1412
}
15-
}
1613

17-
public struct ToManyOrderedRelation<Destination: ManagedObjectConvertible> {
1814
let name: String
15+
}
1916

17+
public struct ToManyOrderedRelation<Destination: ManagedObjectConvertible> {
2018
public init(_ name: String) {
2119
self.name = name
2220
}
21+
22+
let name: String
2323
}

0 commit comments

Comments
 (0)