cdq 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +41 -0
- data/lib/cdq/version.rb +1 -1
- data/motion/cdq/collection_proxy.rb +6 -2
- data/motion/cdq/config.rb +29 -9
- data/motion/cdq/relationship_query.rb +17 -5
- data/motion/cdq/targeted_query.rb +63 -2
- data/motion/managed_object.rb +11 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ca83058a084e81380741e9f398d491ded74fb38
|
4
|
+
data.tar.gz: 7a3da15d054b1de39f696cca1357d66b2586a47c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25e10d54dede83dcc44ead98586d04260a8618cb41aff696e5c2290091adf0838a70c8d84fa6a9f802fd56c376205b5003c8137d8288dfb3c8caa65a52078fa0
|
7
|
+
data.tar.gz: 88dd18915e1222995a1b6334bbe72e51f182274ae327ec04d646038bd2d1b93a8c9a41da47c40d1866e0db971d36b818567a72065fb8fd620cb488a3e9808e98
|
data/README.md
CHANGED
@@ -117,6 +117,25 @@ app root, and they are versioned for automatic migrations, and this is what they
|
|
117
117
|
|
118
118
|
Ruby-xcdm translates these files straight into the XML format that Xcode uses for datamodels.
|
119
119
|
|
120
|
+
### Boolean Values
|
121
|
+
|
122
|
+
Since CoreData stores boolean values as an `NSNumber`, cdq provides helper
|
123
|
+
methods to allow you to get the boolean value of the property. Take the `Article`
|
124
|
+
model from above with the `boolean`:`published`. If you call `published` directly
|
125
|
+
you'll get the `NSNumber` `0` or `1`. If you call `published?` you'll get a
|
126
|
+
boolean `true` or `false`
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
article_1 = Article.create(published: true)
|
130
|
+
article_2 = Article.create(published: false)
|
131
|
+
|
132
|
+
article_1.published # => 1
|
133
|
+
article_2.published # => 0
|
134
|
+
|
135
|
+
article_1.published? # => true
|
136
|
+
article_2.published? # => false
|
137
|
+
```
|
138
|
+
|
120
139
|
## Context Management
|
121
140
|
|
122
141
|
Managing NSManagedObjectContext objects in Core Data can be tricky, especially
|
@@ -191,6 +210,8 @@ all the data over to your main context all at once. CDQ makes that easy too:
|
|
191
210
|
cdq.save
|
192
211
|
```
|
193
212
|
|
213
|
+
**NOTE** Custom class methods will have to `include CDQ` in order to have access to the `cdq` object. If you're calling `cdq` from a class method, you also have to `extend CDQ`.
|
214
|
+
|
194
215
|
### Deleting
|
195
216
|
```ruby
|
196
217
|
author = Author.first
|
@@ -249,6 +270,16 @@ Here are some examples. **See the [cheat sheet](https://github.com/infinitered/
|
|
249
270
|
Author.where(:name).contains("Emily").and(cdq(:pub_count).gt(100).or.lt(10))
|
250
271
|
```
|
251
272
|
|
273
|
+
### Calculations
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
Author.sum(:fee)
|
277
|
+
Author.average(:fee)
|
278
|
+
Author.min(:fee)
|
279
|
+
Author.max(:fee)
|
280
|
+
Author.where(:name).eq("Emily").sum(:fee)
|
281
|
+
```
|
282
|
+
|
252
283
|
### Fetching
|
253
284
|
|
254
285
|
Like ActiveRecord, CDQ will not run a fetch until you actually request specific
|
@@ -256,6 +287,7 @@ objects. There are several methods for getting at the data:
|
|
256
287
|
|
257
288
|
* `array`
|
258
289
|
* `first`
|
290
|
+
* `last`
|
259
291
|
* `each`
|
260
292
|
* `[]`
|
261
293
|
* `map`
|
@@ -355,3 +387,12 @@ You can also set up iCloud in your cdq.yml file.
|
|
355
387
|
* There are no explicit validations (but you can define them on your data model)
|
356
388
|
* Lifecycle Callbacks or Observers
|
357
389
|
|
390
|
+
## Tips
|
391
|
+
|
392
|
+
If you need, you could watch SQL statements by setting the following launch argument through `args` environment variable:
|
393
|
+
|
394
|
+
```
|
395
|
+
$ rake args='-com.apple.CoreData.SQLDebug 3'
|
396
|
+
```
|
397
|
+
|
398
|
+
`com.apple.CoreData.SQLDebug` takes a value between 1 and 3; the higher the value, the more verbose the output.
|
data/lib/cdq/version.rb
CHANGED
data/motion/cdq/config.rb
CHANGED
@@ -8,12 +8,14 @@ module CDQ
|
|
8
8
|
# model file. This file is named <tt>cdq.yml</tt> and must be found at the
|
9
9
|
# root of your resources directory. It supports the following top-level keys:
|
10
10
|
#
|
11
|
-
# [name]
|
12
|
-
# [database_dir]
|
13
|
-
# [database_name]
|
14
|
-
# [model_name]
|
15
|
-
# [
|
16
|
-
# [
|
11
|
+
# [name] The root name for both database and model
|
12
|
+
# [database_dir] The root name for the database directory (NSDocumentDirectory or NSApplicationSupportDirectory)
|
13
|
+
# [database_name] The root name for the database file (relative to the database_dir)
|
14
|
+
# [model_name] The root name for the model file (relative to the bundle directory)
|
15
|
+
# [app_group_id] The app group id set in iTunes member center (group.com.mycompany.myapp)
|
16
|
+
# [app_group_container_uuid] WORKAROUND: The app group's UUID for iOS Simulator 8.1 which doesn't return an app group container path from the id
|
17
|
+
# [icloud] If it's true, CDQ works with iCloud.
|
18
|
+
# [icloud_container] Set id of iCloud container if you use iCloud. If it's nil, use first container listed in the com.apple.developer.ubiquity-container-identifiers entitlement array.
|
17
19
|
#
|
18
20
|
# Using the config file is not necessary. If you do not include it, the bundle display name
|
19
21
|
# will be used. For most people with a new app, this is what you want to do, especially if
|
@@ -24,7 +26,7 @@ module CDQ
|
|
24
26
|
#
|
25
27
|
class CDQConfig
|
26
28
|
|
27
|
-
attr_reader :config_file, :database_name, :database_dir, :model_name, :name, :icloud, :icloud_container
|
29
|
+
attr_reader :config_file, :database_name, :database_dir, :model_name, :name, :icloud, :icloud_container, :app_group_id, :app_group_container_uuid
|
28
30
|
|
29
31
|
def initialize(config_file)
|
30
32
|
h = nil
|
@@ -46,6 +48,8 @@ module CDQ
|
|
46
48
|
@database_dir = search_directory_for h['database_dir'] || h[:database_dir]
|
47
49
|
@database_name = h['database_name'] || h[:database_name] || name
|
48
50
|
@model_name = h['model_name'] || h[:model_name] || name
|
51
|
+
@app_group_id = h['app_group_id'] || h[:app_group_id]
|
52
|
+
@app_group_container_uuid = h['app_group_container_uuid'] || h[:app_group_container_uuid]
|
49
53
|
@icloud = begin
|
50
54
|
case h['icloud'] || h[:icloud]
|
51
55
|
when true, 1
|
@@ -56,9 +60,14 @@ module CDQ
|
|
56
60
|
end
|
57
61
|
@icloud_container = h['icloud_container'] || h[:icloud_container]
|
58
62
|
end
|
59
|
-
|
63
|
+
|
60
64
|
def database_url
|
61
|
-
|
65
|
+
if app_group_id.nil?
|
66
|
+
dir = NSSearchPathForDirectoriesInDomains(database_dir, NSUserDomainMask, true).last
|
67
|
+
else
|
68
|
+
dir = app_group_container
|
69
|
+
end
|
70
|
+
|
62
71
|
path = File.join(dir, database_name + '.sqlite')
|
63
72
|
NSURL.fileURLWithPath(path)
|
64
73
|
end
|
@@ -67,6 +76,17 @@ module CDQ
|
|
67
76
|
NSBundle.mainBundle.URLForResource(model_name, withExtension: "momd");
|
68
77
|
end
|
69
78
|
|
79
|
+
def app_group_container
|
80
|
+
if (UIDevice.currentDevice.model =~ /simulator/i).nil? # device
|
81
|
+
dir = NSFileManager.defaultManager.containerURLForSecurityApplicationGroupIdentifier(app_group_id).path
|
82
|
+
elsif ! app_group_container_uuid.nil? # simulator with app group uuid workaround
|
83
|
+
dev_container = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true).last.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent.stringByDeletingLastPathComponent
|
84
|
+
dir = dev_container.stringByAppendingPathComponent("Shared").stringByAppendingPathComponent("AppGroup").stringByAppendingPathComponent(app_group_container_uuid)
|
85
|
+
else # simulator no workaround, fallback to default dir
|
86
|
+
dir = NSSearchPathForDirectoriesInDomains(database_dir, NSUserDomainMask, true).last
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
70
90
|
def self.default
|
71
91
|
@default ||=
|
72
92
|
begin
|
@@ -4,9 +4,9 @@ module CDQ
|
|
4
4
|
class CDQRelationshipQuery < CDQTargetedQuery
|
5
5
|
|
6
6
|
def initialize(owner, name, set = nil, opts = {})
|
7
|
-
@owner = owner
|
7
|
+
@owner = owner ? WeakRef.new(owner) : nil
|
8
8
|
@relationship_name = name
|
9
|
-
@set = set
|
9
|
+
@set = set ? WeakRef.new(set) : nil
|
10
10
|
relationship = owner.entity.relationshipsByName[name]
|
11
11
|
if relationship.isToMany
|
12
12
|
if @owner.ordered_set?(name)
|
@@ -20,12 +20,16 @@ module CDQ
|
|
20
20
|
target_class = constantize(entity_description.managedObjectClassName)
|
21
21
|
super(entity_description, target_class, opts)
|
22
22
|
if @inverse_rel.isToMany
|
23
|
-
@predicate = self.where(@inverse_rel.name.to_sym).contains(
|
23
|
+
@predicate = self.where(@inverse_rel.name.to_sym).contains(owner).predicate
|
24
24
|
else
|
25
25
|
@predicate = self.where(@inverse_rel.name.to_sym => @owner).predicate
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def dealloc
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
29
33
|
# Creates a new managed object within the target relationship
|
30
34
|
#
|
31
35
|
def new(opts = {})
|
@@ -47,6 +51,10 @@ module CDQ
|
|
47
51
|
@set.removeObject obj
|
48
52
|
end
|
49
53
|
|
54
|
+
def remove_all
|
55
|
+
@set.removeAllObjects
|
56
|
+
end
|
57
|
+
|
50
58
|
def self.extend_set(set, owner, name)
|
51
59
|
set.extend SetExt
|
52
60
|
set.extend Enumerable
|
@@ -72,8 +80,12 @@ module CDQ
|
|
72
80
|
self.allObjects
|
73
81
|
end
|
74
82
|
|
75
|
-
def first
|
76
|
-
array.first
|
83
|
+
def first(n = 1)
|
84
|
+
n == 1 ? array.first : array.first(n)
|
85
|
+
end
|
86
|
+
|
87
|
+
def last(n = 1)
|
88
|
+
n == 1 ? array.last : array.last(n)
|
77
89
|
end
|
78
90
|
|
79
91
|
# duplicating a lot of common methods because it's way faster than using method_missing
|
@@ -62,8 +62,18 @@ module CDQ #:nodoc:
|
|
62
62
|
#
|
63
63
|
# Causes execution.
|
64
64
|
#
|
65
|
-
def first
|
66
|
-
limit(
|
65
|
+
def first(n = 1)
|
66
|
+
result = limit(n).array
|
67
|
+
n == 1 ? result.first : result
|
68
|
+
end
|
69
|
+
|
70
|
+
# Return the last entity matching the query.
|
71
|
+
#
|
72
|
+
# Causes execution.
|
73
|
+
#
|
74
|
+
def last(n = 1)
|
75
|
+
result = offset(count - n).limit(n).array
|
76
|
+
n == 1 ? result.first : result
|
67
77
|
end
|
68
78
|
|
69
79
|
# Fetch a single entity from the query by index. If the optional
|
@@ -89,6 +99,57 @@ module CDQ #:nodoc:
|
|
89
99
|
array.each(*args, &block)
|
90
100
|
end
|
91
101
|
|
102
|
+
# Calculation method based on core data aggregate functions.
|
103
|
+
def calculate(operation, column_name)
|
104
|
+
raise("No context has been set. Probably need to run cdq.setup") unless context
|
105
|
+
raise("Cannot find attribute #{column_name} while calculating #{operation}") unless @entity_description.attributesByName[column_name.to_s]
|
106
|
+
desc_name = operation.to_s + '_of_' + column_name.to_s
|
107
|
+
fr = fetch_request.tap do |req|
|
108
|
+
req.propertiesToFetch = [
|
109
|
+
NSExpressionDescription.alloc.init.tap do |desc|
|
110
|
+
desc.name = desc_name
|
111
|
+
desc.expression = NSExpression.expressionForFunction(operation.to_s + ':', arguments: [ NSExpression.expressionForKeyPath(column_name.to_s) ])
|
112
|
+
desc.expressionResultType = @entity_description.attributesByName[column_name.to_s].attributeType
|
113
|
+
end
|
114
|
+
]
|
115
|
+
req.resultType = NSDictionaryResultType
|
116
|
+
end
|
117
|
+
with_error_object([]) do |error|
|
118
|
+
r = context.executeFetchRequest(fr, error:error)
|
119
|
+
r.first[desc_name]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Calculates the sum of values on a given column.
|
124
|
+
#
|
125
|
+
# Author.sum(:fee) # => 6.0
|
126
|
+
def sum(column_name)
|
127
|
+
calculate(:sum, column_name)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Calculates the average of values on a given column.
|
131
|
+
#
|
132
|
+
# Author.average(:fee) # => 2.0
|
133
|
+
def average(column_name)
|
134
|
+
calculate(:average, column_name)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Calculates the minimum of values on a given column.
|
138
|
+
#
|
139
|
+
# Author.min(:fee) # => 1.0
|
140
|
+
def min(column_name)
|
141
|
+
calculate(:min, column_name)
|
142
|
+
end
|
143
|
+
alias :minimum :min
|
144
|
+
|
145
|
+
# Calculates the maximum of values on a given column.
|
146
|
+
#
|
147
|
+
# Author.max(:fee) # => 3.0
|
148
|
+
def max(column_name)
|
149
|
+
calculate(:max, column_name)
|
150
|
+
end
|
151
|
+
alias :maximum :max
|
152
|
+
|
92
153
|
# Returns the fully-contstructed fetch request, which can be executed outside of CDQ.
|
93
154
|
#
|
94
155
|
def fetch_request
|
data/motion/managed_object.rb
CHANGED
@@ -42,11 +42,11 @@ class CDQManagedObject < CoreDataQueryManagedObjectBase
|
|
42
42
|
def scope(name, query = nil, &block)
|
43
43
|
cdq.scope(name, query, &block)
|
44
44
|
if query
|
45
|
-
|
45
|
+
define_method(name) do
|
46
46
|
where(query)
|
47
47
|
end
|
48
48
|
else
|
49
|
-
|
49
|
+
define_method(name) do |*args|
|
50
50
|
where(block.call(*args))
|
51
51
|
end
|
52
52
|
end
|
@@ -174,6 +174,15 @@ class CDQManagedObject < CoreDataQueryManagedObjectBase
|
|
174
174
|
objectID.URIRepresentation.absoluteString.inspect
|
175
175
|
end
|
176
176
|
|
177
|
+
def method_missing(name, *args, &block)
|
178
|
+
if name[-1] == "?"
|
179
|
+
property_name = name[0...-1]
|
180
|
+
if entity.propertiesByName[property_name] && entity.propertiesByName[property_name].attributeType == NSBooleanAttributeType
|
181
|
+
send(property_name) == 1 ? true : false
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
177
186
|
protected
|
178
187
|
|
179
188
|
# Called from method that's dynamically added from
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cdq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- infinitered
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-xcdm
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
version: '0.0'
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.
|
23
|
+
version: 0.0.9
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
version: '0.0'
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.0.
|
33
|
+
version: 0.0.9
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: motion-yaml
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|