Parsistence 0.2.1 → 0.3.0

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.
data/README.md CHANGED
@@ -52,7 +52,7 @@ users.map {|u| u.objectId}.include?(user.objectId) #=> true
52
52
  Queries use a somewhat different pattern than ActiveRecord but are relatively familiar. They are most like persistence.js.
53
53
 
54
54
  ```ruby
55
- Car.eq(license: "ABC-123", model: "Camry").order(year: :desc).limit(25).fetch do |cars, error|
55
+ Car.eq(license: "ABC-123", model: "Camry").order(year: :desc).limit(25).fetchAll do |cars, error|
56
56
  if cars
57
57
  cars.each do |car|
58
58
  # `car` is an instance of your `Car` model here.
@@ -66,21 +66,101 @@ Chain multiple conditions together, even the same condition type multiple times,
66
66
  ####Available Conditions
67
67
  (note: each condition can take multiple comma-separated fields and values)
68
68
 
69
- **eq:** Check if equal the passed in values.
70
-
71
- **notEq:** Check if NOT equal to the passed in values.
72
-
73
- **gt:** Check if greater than the passed in values.
74
-
75
- **lt:** Check if less than the passed in values.
76
-
77
- **gte:** Check if greater or equal to than the passed in values.
78
-
79
- **lte:** Check if less than or equal to the passed in values.
80
-
81
- **order:** Order by one or more fields. Specify :asc or :desc.
82
-
83
- **limit:** Limit is slightly different...it takes either one argument (limit) or two (offset, limit).
69
+ <table>
70
+ <tr>
71
+ <th>Method</th>
72
+ <th>Effect</th>
73
+ <th>Example</th>
74
+ </tr>
75
+
76
+ <tr>
77
+ <td>eq</td>
78
+ <td>Equal to</td>
79
+ <td>
80
+ <pre>
81
+ Tree.eq(name: "Fir").fetchAll do |trees|
82
+ ...
83
+ end</pre>
84
+ </td>
85
+ </tr>
86
+
87
+ <tr>
88
+ <td>notEq</td>
89
+ <td>NOT equal to</td>
90
+ <td>
91
+ <pre>
92
+ Tree.notEq(name: "Fir").fetchAll do |trees|
93
+ ...
94
+ end</pre>
95
+ </td>
96
+ </tr>
97
+
98
+ <tr>
99
+ <td>gt</td>
100
+ <td>Greater than</td>
101
+ <td>
102
+ <pre>
103
+ Tree.gt(height: 10).fetchAll do |trees|
104
+ ...
105
+ end</pre>
106
+ </td>
107
+ </tr>
108
+
109
+ <tr>
110
+ <td>lt</td>
111
+ <td>Less than</td>
112
+ <td>
113
+ <pre>
114
+ Tree.lt(height: 10).fetchAll do |trees|
115
+ ...
116
+ end</pre>
117
+ </td>
118
+ </tr>
119
+
120
+ <tr>
121
+ <td>gte</td>
122
+ <td>Greater than or equal to</td>
123
+ <td>
124
+ <pre>
125
+ Tree.gte(height: 10).fetchAll do |trees|
126
+ ...
127
+ end</pre>
128
+ </td>
129
+ </tr>
130
+
131
+ <tr>
132
+ <td>lte</td>
133
+ <td>Less than or equal to</td>
134
+ <td>
135
+ <pre>
136
+ Tree.lte(height: 10).fetchAll do |trees|
137
+ ...
138
+ end</pre>
139
+ </td>
140
+ </tr>
141
+
142
+ <tr>
143
+ <td>order</td>
144
+ <td>Order by one or more fields (:asc/:desc).</td>
145
+ <td>
146
+ <pre>
147
+ Tree.order(height: :asc).fetchAll do |trees|
148
+ ...
149
+ end</pre>
150
+ </td>
151
+ </tr>
152
+
153
+ <tr>
154
+ <td>limit</td>
155
+ <td>Limit and offset.</td>
156
+ <td>
157
+ <pre>
158
+ Tree.limit(25, 10).fetchAll do |trees|
159
+ ...
160
+ end</pre>
161
+ </td>
162
+ </tr>
163
+ </table>
84
164
 
85
165
  ### Relationships
86
166
 
@@ -92,7 +172,7 @@ class Post
92
172
 
93
173
  fields :title, :body, :author
94
174
 
95
- relations :author
175
+ belongs_to :author # Must be a "pointer" object on Parse.com
96
176
  end
97
177
 
98
178
  Author.where(name: "Jamon Holmgren").fetchOne do |fetchedAuthor, error|
@@ -11,32 +11,30 @@ module Parsistence
11
11
  self.PFObject = PFObject.objectWithClassName(self.class.to_s)
12
12
  end
13
13
 
14
- # setupRelations unless pf
15
-
16
14
  self
17
15
  end
18
-
19
- # This code is to correct for a bug where relations aren't initialized when creating a new instance
20
- # def setupRelations
21
- # relations.each do |r|
22
- # self.send("#{r}=", @PFObject.relationforKey(r))
23
- # end
24
- # end
25
16
 
26
17
  def method_missing(method, *args, &block)
27
18
  method = method.to_sym
28
- if fields.include?(method)
29
- return getField(method)
30
- elsif fields.map { |f| "#{f}=".include?(method)}
31
- method = method.split("=")[0]
19
+ setter = false
20
+
21
+ if method.to_s.include?("=")
22
+ setter = true
23
+ method = method.split("=")[0].to_sym
24
+ end
25
+
26
+ # Setters
27
+ if relations.include?(method) && setter
28
+ return setRelation(method, args.first)
29
+ elsif fields.include?(method) && setter
32
30
  return setField(method, args.first)
33
- elsif relations.include?(method)
31
+ # Getters
32
+ elsif relations.include? method
34
33
  return getRelation(method)
35
- elsif relations.map {|r| "#{r}=".include?(method)}
36
- method = method.split("=")[0]
37
- return setRelation(method, args.first)
38
- elsif @PFObject.respond_to?(method)
39
- return @PFObject.send(method, *args, &block)
34
+ elsif fields.include? method
35
+ return getField(method)
36
+ elsif self.PFObject.respond_to?(method)
37
+ return self.PFObject.send(method, *args, &block)
40
38
  else
41
39
  super
42
40
  end
@@ -64,18 +62,33 @@ module Parsistence
64
62
  end
65
63
 
66
64
  def getRelation(field)
67
- return @PFObject.objectForKey(field) if relations.include? field.to_sym
68
- raise "Parsistence Exception: Invalid relation name #{field} for object #{self.class.to_s}"
65
+ if has_many.include?(field.to_sym)
66
+ relation = @PFObject.objectForKey(field) if relations.include? field.to_sym
67
+ # This is not implemented yet
68
+ # return @relation[field] ||= begin
69
+ # r = Relation.new(relation)
70
+ # r.klass = self
71
+ # r.belongs_to = true
72
+ # r
73
+ # end
74
+ raise "Parsistence Exception: has_many relationships aren't implemented yet. Use a regular query instead."
75
+ elsif belongs_to.include?(field.to_sym)
76
+ return self.getField(field)
77
+ else
78
+ raise "Parsistence Exception: Invalid relation name #{field} for object #{self.class.to_s}"
79
+ end
69
80
  end
70
81
 
71
82
  def setRelation(field, value)
72
83
  value = value.PFObject if value.respond_to? :PFObject # unwrap object
73
- # return setRelation(field, value) # This SHOULD work
74
-
75
- relation = @PFObject.relationforKey(field)
84
+ if has_many.include?(field.to_sym)
85
+ relation = @PFObject.relationforKey(field)
86
+ return relation.addObject(value) if relations.include? field.to_sym
87
+ elsif belongs_to.include?(field.to_sym)
88
+ return setField(field, value)
89
+ end
76
90
 
77
- return relation.addObject(value) if relations.include? field.to_sym
78
- raise "Parsistence Exception: Invalid relation name #{field} for object #{self.class.to_s}" unless relations.include? relation.to_sym
91
+ raise "Parsistence Exception: Invalid relation name #{field} for object #{self.class.to_s}"
79
92
  end
80
93
 
81
94
  def attributes
@@ -88,7 +101,9 @@ module Parsistence
88
101
 
89
102
  def attributes=(hashValue)
90
103
  hashValue.each do |k, v|
91
- if self.respond_to? "#{k}="
104
+ if v.respond_to?(:each) && !v.is_a?(PFObject)
105
+ self.attributes = v
106
+ elsif self.respond_to? "#{k}="
92
107
  self.send("#{k}=", v)
93
108
  else
94
109
  setField(k, v) unless k.nil?
@@ -99,11 +114,17 @@ module Parsistence
99
114
  def save
100
115
  saved = false
101
116
  unless before_save == false
117
+ reset_errors
102
118
  self.attributes.each do |field, value|
103
119
  validateField field, value
104
120
  end
105
121
 
106
- saved = @PFObject.save
122
+ if @errors && @errors.length > 0
123
+ saved = false
124
+ else
125
+ saved = @PFObject.save
126
+ end
127
+
107
128
  after_save if saved
108
129
  end
109
130
  saved
@@ -114,18 +135,52 @@ module Parsistence
114
135
 
115
136
  # Validations
116
137
  def presenceValidations
117
- self.class.send(:get_presenceValidations)
138
+ self.class.send(:get_presence_validations)
139
+ end
140
+
141
+ def presenceValidationMessages
142
+ self.class.send(:get_presence_validation_messages)
143
+ end
144
+
145
+ def has_many
146
+ self.class.send(:get_has_many)
147
+ end
148
+
149
+ def belongs_to
150
+ self.class.send(:get_belongs_to)
118
151
  end
119
152
 
120
153
  def validateField(field, value)
121
154
  @errors ||= {}
122
- @errors[field] = "#{field} can't be blank" if presenceValidations.include?(field) && value.nil? || value == ""
155
+ if presenceValidations.include?(field) && value.nil? || value == ""
156
+ messages = presenceValidationMessages
157
+ if messages.include?(field)
158
+ @errors[field] = messages[field]
159
+ else
160
+ @errors[field] = "#{field} can't be blank"
161
+ end
162
+ end
123
163
  end
124
164
 
125
165
  def errorForField(field)
126
166
  @errors[field] || false
127
167
  end
128
168
 
169
+ def errors
170
+ @errors
171
+ end
172
+
173
+ def valid?
174
+ self.errors.nil? || self.errors.length == 0
175
+ end
176
+
177
+ def invalid?
178
+ !self.valid?
179
+ end
180
+
181
+ def reset_errors
182
+ @errors = nil
183
+ end
129
184
 
130
185
  module ClassMethods
131
186
  def fields(*args)
@@ -139,7 +194,7 @@ module Parsistence
139
194
  end
140
195
 
141
196
  def get_fields
142
- @fields
197
+ @fields ||= []
143
198
  end
144
199
 
145
200
  def relations(*args)
@@ -156,12 +211,52 @@ module Parsistence
156
211
  @relations ||= []
157
212
  end
158
213
 
159
- def validates_presence_of(*args)
160
- args.each {|arg| validate_presence(arg)}
214
+ def has_many(field, args={})
215
+ relation(field)
216
+
217
+ @has_many ||= []
218
+ @has_many << field
219
+ @has_many.uniq!
220
+
221
+ @has_many_attributes ||= {}
222
+ @has_many_attributes[field] = args
223
+ end
224
+
225
+ def get_has_many
226
+ @has_many ||= []
161
227
  end
162
228
 
163
- def get_presenceValidations
164
- @presenceValidations ||= []
229
+ def belongs_to(field, args={})
230
+ relation(field)
231
+
232
+ @belongs_to ||= []
233
+ @belongs_to << field
234
+ @belongs_to.uniq!
235
+
236
+ @belongs_to_attributes ||= {}
237
+ @belongs_to_attributes[field] = args
238
+ end
239
+
240
+ def get_belongs_to
241
+ @belongs_to ||= []
242
+ end
243
+
244
+ def get_belongs_to_attributes(field)
245
+ @belongs_to_attributes[field] ||= { class_name: field }
246
+ end
247
+
248
+ def validates_presence_of(field, opts={})
249
+ @presenceValidationMessages ||= {}
250
+ @presenceValidationMessages[field] = opts[:message] if opts[:message]
251
+ validate_presence(field)
252
+ end
253
+
254
+ def get_presence_validations
255
+ @presenceValidations ||= {}
256
+ end
257
+
258
+ def get_presence_validation_messages
259
+ @presenceValidationMessages ||= {}
165
260
  end
166
261
 
167
262
  def validate_presence(field)
@@ -1,21 +1,43 @@
1
1
  module Parsistence
2
2
  module Model
3
3
  module ClassMethods
4
- QUERY_STUBS = [ :fetch, :where, :first, :limit, :order, :eq, :notEq, :lt, :gt, :lte, :gte ] # :limit is different
4
+ QUERY_STUBS = [ :where, :first, :limit, :order, :eq, :notEq, :lt, :gt, :lte, :gte ] # :limit is different
5
+
6
+ def fetchAll(&block)
7
+ q = Parsistence::Query.new
8
+ q.klass = self
9
+ return q.fetchAll &block
10
+ end
11
+
12
+ def fetchOne(&block)
13
+ q = Parsistence::Query.new
14
+ q.klass = self
15
+ q.limit(1).fetchAll &block
16
+ end
17
+
18
+ def all(&block)
19
+ fetchAll(&block)
20
+ end
5
21
 
6
22
  def method_missing(method, *args, &block)
7
- if method == :limit
8
- return self.limit(args.first) if args.length == 1
9
- return self.limit(args.first, args.last)
23
+ if method == :limit && args.length == 2
24
+ q = Parsistence::Query.new
25
+ q.klass = self
26
+ return q.send(method, args[0], args[1])
27
+ elsif QUERY_STUBS.include? method.to_sym && args.length == 0
28
+ q = Parsistence::Query.new
29
+ q.klass = self
30
+ return q.send(method, &block) if block_given?
31
+ return q.send(method)
10
32
  elsif QUERY_STUBS.include? method.to_sym
11
33
  q = Parsistence::Query.new
12
34
  q.klass = self
13
- return q.send(method, args.first, &block) if block
35
+ return q.send(method, args.first, &block) if block_given?
14
36
  return q.send(method, args.first)
15
37
  elsif method.start_with?("find_by_")
16
- attribute = method.gsub("find_by_", "")
17
- cond[attribute] = args.first
18
- return self.limit(1).where(cond, block)
38
+ # attribute = method.gsub("find_by_", "")
39
+ # cond[attribute] = args.first
40
+ # return self.limit(1).where(cond, block)
19
41
  elsif method.start_with?("find_all_by_")
20
42
  # attribute = method.gsub("find_all_by_", "")
21
43
  # cond[attribute] = args.first
@@ -218,6 +240,7 @@ module Parsistence
218
240
  fields.each do |field|
219
241
  @includes << field
220
242
  end
243
+ self
221
244
  end
222
245
  end
223
246
  end
@@ -0,0 +1,28 @@
1
+ # module Parsistence
2
+ # class Relation
3
+ # attr_accessor :PFRelation, :belongs_to, :klass
4
+
5
+ # def initialize(pf_relation)
6
+ # self.PFRelation = pf_relation
7
+
8
+ # end
9
+
10
+ # def fetch(&block)
11
+ # if self.belongs_to
12
+ # self.PFRelation.fetchIfNeededInBackgroundWithBlock do |result, error|
13
+ # if result
14
+ # result = self.klass.new(result)
15
+ # end
16
+
17
+ # block.call(result, error)
18
+ # end
19
+ # else
20
+ # self.PFRelation.
21
+ # end
22
+ # end
23
+
24
+ # def fetchAll(&block)
25
+ # self.fetch(block)
26
+ # end
27
+ # end
28
+ # end
@@ -6,6 +6,16 @@ module Parsistence
6
6
 
7
7
  RESERVED_KEYS = [:objectId, :username, :password, :email]
8
8
 
9
+ def initialize(pf=nil)
10
+ if pf
11
+ self.PFObject = pf
12
+ else
13
+ self.PFObject = PFObject.objectWithClassName(self.class.to_s)
14
+ end
15
+
16
+ self
17
+ end
18
+
9
19
  def PFObject=(value)
10
20
  @PFObject = value
11
21
  @PFUser = @PFObject
@@ -21,7 +31,7 @@ module Parsistence
21
31
  users = query.findObjects
22
32
  users
23
33
  end
24
-
34
+
25
35
  def currentUser
26
36
  PFUser.currentUser
27
37
  end
@@ -1,3 +1,3 @@
1
1
  module Parsistence
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Parsistence
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-09-05 00:00:00.000000000 Z
14
+ date: 2012-09-12 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: Your models on RubyMotion and Parse in a persistence.js style pattern.
17
17
  email:
@@ -30,6 +30,7 @@ files:
30
30
  - lib/Parsistence.rb
31
31
  - lib/Parsistence/Model.rb
32
32
  - lib/Parsistence/Query.rb
33
+ - lib/Parsistence/Relation.rb
33
34
  - lib/Parsistence/User.rb
34
35
  - lib/Parsistence/version.rb
35
36
  homepage: https://github.com/clearsightstudio/Parsistence