mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-15 05:33:31 +01:00
removed Median and StandardDeviation from supported aggregates as core data doesn't seem to support them either
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "0.1.1"
|
||||
s.version = "0.1.2"
|
||||
s.license = "MIT"
|
||||
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
|
||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||
|
||||
@@ -108,7 +108,8 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
return ._Aggregate(
|
||||
function: "average:",
|
||||
keyPath,
|
||||
As: alias ?? "average(\(keyPath))"
|
||||
As: alias ?? "average(\(keyPath))",
|
||||
nativeType: .DecimalAttributeType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -129,7 +130,8 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
return ._Aggregate(
|
||||
function: "count:",
|
||||
keyPath,
|
||||
As: alias ?? "count(\(keyPath))"
|
||||
As: alias ?? "count(\(keyPath))",
|
||||
nativeType: .Integer64AttributeType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -150,28 +152,8 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
return ._Aggregate(
|
||||
function: "max:",
|
||||
keyPath,
|
||||
As: alias ?? "max(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Provides a `SelectTerm` to a `Select` clause for querying the median value for an attribute.
|
||||
|
||||
let medianAge = CoreStore.queryValue(
|
||||
From(MyPersonEntity),
|
||||
Select<Int>(.Median("age"))
|
||||
)
|
||||
|
||||
:param: keyPath the attribute name
|
||||
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "max(<attributeName>)" is used
|
||||
:returns: a `SelectTerm` to a `Select` clause for querying the median value for an attribute
|
||||
*/
|
||||
public static func Median(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return ._Aggregate(
|
||||
function: "median:",
|
||||
keyPath, As:
|
||||
alias ?? "median(\(keyPath))"
|
||||
As: alias ?? "max(\(keyPath))",
|
||||
nativeType: .UndefinedAttributeType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,7 +162,7 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
|
||||
let minimumAge = CoreStore.queryValue(
|
||||
From(MyPersonEntity),
|
||||
Select<Int>(.Median("age"))
|
||||
Select<Int>(.Minimum("age"))
|
||||
)
|
||||
|
||||
:param: keyPath the attribute name
|
||||
@@ -192,28 +174,8 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
return ._Aggregate(
|
||||
function: "min:",
|
||||
keyPath,
|
||||
As: alias ?? "min(\(keyPath))"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Provides a `SelectTerm` to a `Select` clause for querying the standard deviation value for an attribute.
|
||||
|
||||
let stddevAge = CoreStore.queryValue(
|
||||
From(MyPersonEntity),
|
||||
Select<Int>(.StandardDeviation("age"))
|
||||
)
|
||||
|
||||
:param: keyPath the attribute name
|
||||
:param: alias the dictionary key to use to access the result. Ignored when the query return value is not an `NSDictionary`. If `nil`, the default key "stddev(<attributeName>)" is used
|
||||
:returns: a `SelectTerm` to a `Select` clause for querying the standard deviation value for an attribute
|
||||
*/
|
||||
public static func StandardDeviation(keyPath: KeyPath, As alias: KeyPath? = nil) -> SelectTerm {
|
||||
|
||||
return ._Aggregate(
|
||||
function: "stddev:",
|
||||
keyPath,
|
||||
As: alias ?? "stddev(\(keyPath))"
|
||||
As: alias ?? "min(\(keyPath))",
|
||||
nativeType: .UndefinedAttributeType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -234,7 +196,8 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
return ._Aggregate(
|
||||
function: "sum:",
|
||||
keyPath,
|
||||
As: alias ?? "sum(\(keyPath))"
|
||||
As: alias ?? "sum(\(keyPath))",
|
||||
nativeType: .DecimalAttributeType
|
||||
)
|
||||
}
|
||||
|
||||
@@ -260,7 +223,7 @@ public enum SelectTerm: StringLiteralConvertible {
|
||||
// MARK: Internal
|
||||
|
||||
case _Attribute(KeyPath)
|
||||
case _Aggregate(function: String, KeyPath, As: String)
|
||||
case _Aggregate(function: String, KeyPath, As: String, nativeType: NSAttributeType)
|
||||
}
|
||||
|
||||
|
||||
@@ -358,12 +321,19 @@ public struct Select<T: SelectResultType> {
|
||||
CoreStore.log(.Warning, message: "The property \"\(keyPath)\" does not exist in entity <\(entityDescription.managedObjectClassName)> and will be ignored by \(typeName(self)) query clause.")
|
||||
}
|
||||
|
||||
case ._Aggregate(let function, let keyPath, let alias):
|
||||
case ._Aggregate(let function, let keyPath, let alias, let nativeType):
|
||||
if let attributeDescription = attributesByName[keyPath] as? NSAttributeDescription {
|
||||
|
||||
let expressionDescription = NSExpressionDescription()
|
||||
expressionDescription.name = alias
|
||||
expressionDescription.expressionResultType = attributeDescription.attributeType
|
||||
if nativeType == .UndefinedAttributeType {
|
||||
|
||||
expressionDescription.expressionResultType = attributeDescription.attributeType
|
||||
}
|
||||
else {
|
||||
|
||||
expressionDescription.expressionResultType = nativeType
|
||||
}
|
||||
expressionDescription.expression = NSExpression(
|
||||
forFunction: function,
|
||||
arguments: [NSExpression(forKeyPath: keyPath)]
|
||||
@@ -388,7 +358,7 @@ public struct Select<T: SelectResultType> {
|
||||
case ._Attribute(let keyPath):
|
||||
return keyPath
|
||||
|
||||
case ._Aggregate(_, _, let alias):
|
||||
case ._Aggregate(_, _, let alias, _):
|
||||
return alias
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.1</string>
|
||||
<string>0.1.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</configuration>
|
||||
<elements>
|
||||
<element name="Palette" positionX="261" positionY="189" width="128" height="105"/>
|
||||
<element name="UserAccount" positionX="261" positionY="216" width="128" height="90"/>
|
||||
<element name="Place" positionX="261" positionY="225" width="128" height="105"/>
|
||||
<element name="UserAccount" positionX="261" positionY="216" width="128" height="90"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -22,13 +22,15 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
CoreStore.logger = DefaultLogger()
|
||||
}
|
||||
|
||||
let dataStack = DataStack()
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
self.dataStack.addSQLiteStore("emptyStore.sqlite")
|
||||
CoreStore.logger = self
|
||||
}
|
||||
|
||||
@@ -52,7 +54,15 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
GCDQueue.Main.async { [weak self] in
|
||||
|
||||
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log] \(message)\n\n")
|
||||
let levelString: String
|
||||
switch level {
|
||||
|
||||
case .Trace: levelString = "Trace"
|
||||
case .Notice: levelString = "Notice"
|
||||
case .Warning: levelString = "Warning"
|
||||
case .Fatal: levelString = "Fatal"
|
||||
}
|
||||
self?.textView?.insertText("\(fileName.stringValue.lastPathComponent):\(lineNumber) \(functionName)\n ↪︎ [Log:\(levelString)] \(message)\n\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,21 +98,23 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(0):
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.create(Into(UserAccount))
|
||||
}
|
||||
|
||||
case .Some(1):
|
||||
CoreStore.addSQLiteStore("dummy.sqlite", configuration: "test1")
|
||||
CoreStore.addSQLiteStore("dummy.sqlite", configuration: "test2")
|
||||
self.dataStack.addSQLiteStore("emptyStore.sqlite", configuration: "invalidStore")
|
||||
|
||||
case .Some(2):
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.commit()
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
default: return
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,9 +168,16 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
switch section {
|
||||
|
||||
case 0: return "Facebook Accounts"
|
||||
case 1: return "Twitter Accounts"
|
||||
default: return nil
|
||||
case 0:
|
||||
let count = Static.facebookStack.fetchCount(From(UserAccount)) ?? 0
|
||||
return "Facebook Accounts (\(count) users)"
|
||||
|
||||
case 1:
|
||||
let count = Static.twitterStack.fetchCount(From(UserAccount)) ?? 0
|
||||
return "Twitter Accounts (\(count) users)"
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
34
README.md
34
README.md
@@ -1,7 +1,7 @@
|
||||
# CoreStore
|
||||
[](http://cocoadocs.org/docsets/CoreStore)
|
||||
[](http://cocoadocs.org/docsets/CoreStore)
|
||||
[](http://cocoadocs.org/docsets/CoreStore)
|
||||
[](https://raw.githubusercontent.com/JohnEstropia/CoreStore/master/LICENSE)
|
||||
|
||||
Simple, elegant, and smart Core Data programming with Swift
|
||||
(Swift, iOS 8+)
|
||||
@@ -11,8 +11,8 @@ Simple, elegant, and smart Core Data programming with Swift
|
||||
|
||||
## What CoreStore does better:
|
||||
- Heavily supports multiple persistent stores per data stack, just the way .xcdatamodeld files are designed to. CoreStore will also manage one data stack by default, but you can create and manage as many as you need.
|
||||
- Ability to plug-in your own logging framework (or any of your favorite 3rd-party logger)
|
||||
- Gets around a limitation with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the .xcdatamodeld file, so you are free to name them independently.
|
||||
- Ability to plug-in your own logging framework
|
||||
- Gets around a limitation with other Core Data wrappers where the entity name should be the same as the `NSManagedObject` subclass name. CoreStore loads entity-to-class mappings from the managed object model file, so you are free to name them independently.
|
||||
- Provides type-safe, easy to configure observers to replace `NSFetchedResultsController` and KVO
|
||||
- Exposes API not just for fetching, but also for querying aggregates and property values
|
||||
- Makes it hard to fall into common concurrency mistakes. All `NSManagedObjectContext` tasks are encapsulated into safer, higher-level abstractions without sacrificing flexibility and customizability.
|
||||
@@ -31,9 +31,9 @@ CoreStore.addSQLiteStore("MyStore.sqlite")
|
||||
Simple transactions:
|
||||
```swift
|
||||
CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
let object = transaction.create(Into(MyEntity))
|
||||
object.entityID = 1
|
||||
object.name = "test entity"
|
||||
let person = transaction.create(Into(MyPersonEntity))
|
||||
person.name = "John Smith"
|
||||
person.age = 42
|
||||
|
||||
transaction.commit { (result) -> Void in
|
||||
switch result {
|
||||
@@ -46,24 +46,24 @@ CoreStore.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
Easy fetching:
|
||||
```swift
|
||||
let objects = CoreStore.fetchAll(From(MyEntity))
|
||||
let people = CoreStore.fetchAll(From(MyPersonEntity))
|
||||
```
|
||||
```swift
|
||||
let objects = CoreStore.fetchAll(
|
||||
From(MyEntity),
|
||||
Where("entityID", isEqualTo: 1),
|
||||
OrderBy(.Ascending("entityID"), .Descending("name")),
|
||||
let people = CoreStore.fetchAll(
|
||||
From(MyPersonEntity),
|
||||
Where("age > 30"),
|
||||
OrderBy(.Ascending("name"), .Descending("age")),
|
||||
Tweak { (fetchRequest) -> Void in
|
||||
fetchRequest.includesPendingChanges = true
|
||||
fetchRequest.includesPendingChanges = false
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Simple queries:
|
||||
```swift
|
||||
let count = CoreStore.queryValue(
|
||||
From(MyEntity),
|
||||
Select<Int>(.Count("entityID"))
|
||||
let maxAge = CoreStore.queryValue(
|
||||
From(MyPersonEntity),
|
||||
Select<Int>(.Maximum("age"))
|
||||
)
|
||||
```
|
||||
|
||||
@@ -497,9 +497,7 @@ If you only need a value for a particular attribute, you can just specify the ke
|
||||
- `.Average(...)`
|
||||
- `.Count(...)`
|
||||
- `.Maximum(...)`
|
||||
- `.Median(...)`
|
||||
- `.Minimum(...)`
|
||||
- `.StandardDeviation(...)`
|
||||
- `.Sum(...)`
|
||||
|
||||
```swift
|
||||
@@ -572,7 +570,7 @@ which now returns:
|
||||
|
||||
**`GroupBy` clause**
|
||||
|
||||
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is only useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value anyway.
|
||||
The `GroupBy` clause lets you group results by a specified attribute/aggregate. This is useful only for `queryAttributes(...)` since `queryValue(...)` just returns the first value.
|
||||
```swift
|
||||
let personJSON = CoreStore.queryAttributes(
|
||||
From(MyPersonEntity),
|
||||
|
||||
Reference in New Issue
Block a user