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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e4159aee06a7a17669675f80c482c0cef41c456
4
- data.tar.gz: 73c3f008cffa0e014230287e8e21bd751f9dca5d
3
+ metadata.gz: 4ca83058a084e81380741e9f398d491ded74fb38
4
+ data.tar.gz: 7a3da15d054b1de39f696cca1357d66b2586a47c
5
5
  SHA512:
6
- metadata.gz: 21ce21b6ac607663ad50317d5a1de945984bdc509c8c521e385c3fdaad119b6e3aea286d4150b46ca9dfcc44f52e09996ba28b24df1270116332123b929b7639
7
- data.tar.gz: 495a1bf8692bf6c45762e78698870065ab4bb8df01a32185b46ff6d2b1bf1a65fea8652543fbd1f585a273941571a00daa43cc08562d3c720cfdf24f16f8a647
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.
@@ -1,4 +1,4 @@
1
1
 
2
2
  module CDQ
3
- VERSION = '1.0.2'
3
+ VERSION = '1.0.3'
4
4
  end
@@ -22,8 +22,12 @@ module CDQ
22
22
  @objects
23
23
  end
24
24
 
25
- def first
26
- @objects.first
25
+ def first(n = 1)
26
+ n == 1 ? @objects.first : @objects.first(n)
27
+ end
28
+
29
+ def last(n = 1)
30
+ n == 1 ? @objects.last : @objects.last(n)
27
31
  end
28
32
 
29
33
  end
@@ -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] 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
- # [icloud] If it's true, CDQ works with iCloud.
16
- # [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.
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
- dir = NSSearchPathForDirectoriesInDomains(database_dir, NSUserDomainMask, true).last
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(@owner).predicate
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(1).array.first
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
@@ -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
- self.class.send(:define_method, name) do
45
+ define_method(name) do
46
46
  where(query)
47
47
  end
48
48
  else
49
- self.class.send(:define_method, name) do |*args|
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.2
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-03-18 00:00:00.000000000 Z
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.8
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.8
33
+ version: 0.0.9
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: motion-yaml
36
36
  requirement: !ruby/object:Gem::Requirement