cdq 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|