fire-model 0.0.10 → 0.0.11

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: de9855aaa62f8486c88fd342c4e2fda217d042f0
4
- data.tar.gz: b1d04688dc786d1ffefb03d22a5e7ecd63a0082e
3
+ metadata.gz: 2f20e6ee2e52181a1490b86b89ac6fd856ef625d
4
+ data.tar.gz: 47ed6a3f6a15e509dcd8a0be087b45fd2b0d10a0
5
5
  SHA512:
6
- metadata.gz: dd9605004b7ee87c441f509f69ae328c6b2fd36ef9d9ddd50ef8096dfa2f7ef920da12a92fc227762f86a7f23bea977dbd4e987cf68d1e7dc52b6baa76e4157d
7
- data.tar.gz: cef9a05347474fd52edcd5844b92d7560a963698aa7d918e76b56dd54d38cf77aab5b6d4e8c94aa96bf100f5e6b148141f802689e8abdfcbb59a550c10dbf660
6
+ metadata.gz: b39771a4764b4ac5c23bf893092a1504c4db6813b119bb6868af7e4a25aa02abe276a89fec772157b787778a601e61391db08c61b425f1db9728c1d05cfb2507
7
+ data.tar.gz: dee861d2c31ed08b12b4ce2bc0a31bd37678c8e644e1be37c90c7b322cfd1a2564c88aecf7292852dc4bcbd752311cb01cecc5687ac0a6514889c94cc9b6de1f
data/README.md CHANGED
@@ -15,11 +15,16 @@ end
15
15
 
16
16
  Use query syntax
17
17
  ```ruby
18
- LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10, name: 'Kobzar', author: 'T.G. Shevchenko')
19
- LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 15, name: 'Eneida', author: 'I. Kotlyrevskiy')
20
- LibraryBook.create(library: 'Shevchenko', floor: 2, row_number: 15, shelf: 115, name: 'Lord Of The Rings', author: ' J.R.R. Tolkien')
21
- LibraryBook.create(library: 'Skovoroda', floor: 1, row_number: 25, shelf: 34, name: 'Harry Potter', author: 'J.K. Rowling')
22
- LibraryBook.create(library: 'Skovoroda', floor: 2, row_number: 12, shelf: 15, name: 'Hobbit', author: ' J.R.R. Tolkien')
18
+ LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10,
19
+ name: 'Kobzar', author: 'T.G. Shevchenko')
20
+ LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 15,
21
+ name: 'Eneida', author: 'I. Kotlyrevskiy')
22
+ LibraryBook.create(library: 'Shevchenko', floor: 2, row_number: 15, shelf: 115,
23
+ name: 'Lord Of The Rings', author: ' J.R.R. Tolkien')
24
+ LibraryBook.create(library: 'Skovoroda', floor: 1, row_number: 25, shelf: 34,
25
+ name: 'Harry Potter', author: 'J.K. Rowling')
26
+ LibraryBook.create(library: 'Skovoroda', floor: 2, row_number: 12, shelf: 15,
27
+ name: 'Hobbit', author: ' J.R.R. Tolkien')
23
28
 
24
29
  LibraryBook.all.map(&:name)
25
30
  => [ 'Kobzar', 'Eneida', 'Lord Of The Rings', 'Harry Potter', 'Hobbit' ]
@@ -118,6 +123,8 @@ larry == employee
118
123
  employee.department = 'Research'
119
124
  employee.save
120
125
  => true
126
+
127
+ google.reload
121
128
 
122
129
  tim = apple.add_to_employees(
123
130
  full_name: 'Tim Cook',
@@ -125,34 +132,130 @@ tim = apple.add_to_employees(
125
132
  department: 'HQ'
126
133
  )
127
134
 
128
- Fire.connection.get(?/).body
135
+ Fire.tree
129
136
  => {'Organization'=>
130
- {'usa'=>
131
- {'ca'=>
132
- {'apple'=>
133
- {'country'=>'USA',
134
- 'employees'=>
135
- {'hq'=>
136
- {'h543ka'=>
137
- {'department'=>'HQ',
138
- 'full_name'=>'Tim Cook',
139
- 'id'=>'h543ka',
140
- 'position'=>'CEO'}}},
141
- 'name'=>'Apple',
142
- 'state'=>'CA'},
143
- 'google'=>
144
- {'country'=>'USA',
145
- 'employees'=>
146
- {'research'=>
147
- {'d23h1a'=>
148
- {'department'=>'Research',
149
- 'full_name'=>'Larry Page',
150
- 'id'=>'d23h1a',
151
- 'position'=>'CEO'}}},
152
- 'name'=>'Google',
153
- 'state'=>'CA'}}}}}
137
+ {'usa'=>
138
+ {'ca'=>
139
+ {'apple'=>
140
+ {'country'=>'USA',
141
+ 'employees'=>
142
+ {'hq'=>
143
+ {'h543ka'=>
144
+ {'department'=>'HQ',
145
+ 'full_name'=>'Tim Cook',
146
+ 'id'=>'h543ka',
147
+ 'position'=>'CEO'}}},
148
+ 'name'=>'Apple',
149
+ 'state'=>'CA'},
150
+ 'google'=>
151
+ {'country'=>'USA',
152
+ 'employees'=>
153
+ {'research'=>
154
+ {'d23h1a'=>
155
+ {'department'=>'Research',
156
+ 'full_name'=>'Larry Page',
157
+ 'id'=>'d23h1a',
158
+ 'position'=>'CEO'}}},
159
+ 'name'=>'Google',
160
+ 'state'=>'CA'}}}}}
161
+ ```
162
+ Single Nested Models
163
+ ```ruby
164
+ class Car < Fire::Model
165
+ has_path_keys :manufacturer, :model, :car_class
166
+ end
154
167
 
168
+ class Engine < Fire::SingleNestedModel
169
+ nested_in Car
170
+ end
171
+
172
+ scirocco = Car.create(manufacturer: 'Volkswagen', model: 'Scirocco', car_class: 'Sport compact')
173
+ scirocco.add_to_engine(code: 'I4 turbo', power: '122 PS')
174
+
175
+ car = Car.create(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini',
176
+ engine: { code: 'MeMZ-966' })
177
+
178
+ zaporozhets = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
179
+ expect(zaporozhets.nested_engine.code).to eq('MeMZ-966')
180
+
181
+ Fire.tree
182
+ => {
183
+ 'Car'=>
184
+ {'volkswagen'=>
185
+ {'scirocco'=>
186
+ {'sport-compact'=>
187
+ {'adqa21'=>
188
+ {'car_class'=>'Sport compact',
189
+ 'engine'=>{'code'=>'I4 turbo', 'power'=>'122 PS'},
190
+ 'id'=>'adqa21',
191
+ 'manufacturer'=>'Volkswagen',
192
+ 'model'=>'Scirocco'}}}},
193
+ 'zaporozhets'=>
194
+ {'zaz-965'=>
195
+ {'mini'=>
196
+ {'23rtfw'=>
197
+ {'car_class'=>'Mini',
198
+ 'engine'=>{'code'=>'MeMZ-966'},
199
+ 'id'=>'23rtfw',
200
+ 'manufacturer'=>'Zaporozhets',
201
+ 'model'=>'ZAZ-965'}}}}}})
202
+
203
+ zap2 = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
204
+ zap2.nested_engine.update(code: 'MeMZ-555')
205
+ zaporozhets.nested_engine.reload.code
206
+ => 'MeMZ-555'
207
+ ```
155
208
 
209
+ Nested Models with Parent`s values
210
+ ```ruby
211
+ class House < Fire::Model
212
+ has_path_keys :country, :city, :street
213
+ set_id_key(:house_number)
214
+ end
215
+
216
+ class Room < Fire::NestedModel
217
+ nested_in House, parent_values: true
218
+ set_id_key(:number)
219
+ has_path_keys :floor
220
+ end
221
+
222
+ house = House.create(country: 'Ukraine', city: 'Kyiv',
223
+ street: 'Shevchenko Ave.', house_number: '53101')
224
+
225
+ house.add_to_rooms(floor: 200, number: '1A')
226
+ house.add_to_rooms(floor: 150, number: '2A')
227
+
228
+
229
+ rooms = house.reload.nested_rooms
230
+ expect(rooms.map(&:number).sort).to eq(%w{ 1A 2A }.sort)
231
+
232
+ Fire.tree
233
+ => {'House'=>
234
+ {'ukraine'=>
235
+ {'kyiv'=>
236
+ {'shevchenko-ave'=>
237
+ {'53101'=>
238
+ {'city'=>'Kyiv',
239
+ 'country'=>'Ukraine',
240
+ 'house_number'=>'53101',
241
+ 'rooms'=>
242
+ {'150_'=>
243
+ {'2a'=>
244
+ {'city'=>'Kyiv',
245
+ 'country'=>'Ukraine',
246
+ 'floor'=>150,
247
+ 'number'=>'2A',
248
+ 'house_number'=>'53101',
249
+ 'street'=>'Shevchenko Ave.'}},
250
+ '200_'=>
251
+ {'1a'=>
252
+ {'city'=>'Kyiv',
253
+ 'country'=>'Ukraine',
254
+ 'floor'=>200,
255
+ 'number'=>'1A',
256
+ 'house_number'=>'53101',
257
+ 'street'=>'Shevchenko Ave.'}}},
258
+ 'street'=>'Shevchenko Ave.'}}}}}})
156
259
  ```
157
260
 
158
261
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.10
1
+ 0.0.11
data/fire-model.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: fire-model 0.0.10 ruby lib
5
+ # stub: fire-model 0.0.11 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "fire-model"
9
- s.version = "0.0.10"
9
+ s.version = "0.0.11"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Vitaly Tarasenko"]
14
- s.date = "2015-06-20"
14
+ s.date = "2015-06-21"
15
15
  s.description = "You can define your Firebase models, set collection names, CRUD your data. "
16
16
  s.email = "vetal.tarasenko@gmail.com"
17
17
  s.extra_rdoc_files = [
data/lib/fire-model.rb CHANGED
@@ -20,6 +20,10 @@ module Fire
20
20
  connection.delete(?/)
21
21
  end
22
22
 
23
+ def self.tree
24
+ connection.get(?/).body
25
+ end
26
+
23
27
  def self.connection
24
28
  Fire::Connection::Request.new
25
29
  end
data/lib/model/base.rb CHANGED
@@ -54,6 +54,18 @@ module Fire
54
54
  ([ collection_name ] + path_values) * LEVEL_SEPARATOR
55
55
  end
56
56
 
57
+ def reload
58
+ loaded_data = self.class.take(path_data).data
59
+ @table = loaded_data
60
+ @cache = {}
61
+ self
62
+ end
63
+
64
+ def update(attrs)
65
+ @table.merge!(attrs)
66
+ save
67
+ end
68
+
57
69
  # Data Methods
58
70
 
59
71
  def path_values
@@ -102,6 +114,11 @@ module Fire
102
114
  data
103
115
  end
104
116
 
117
+ def cache(key, &value)
118
+ @cache ||= {}
119
+ @cache[key] ||= value.call
120
+ end
121
+
105
122
  class << self
106
123
 
107
124
  # Klass Setters
@@ -196,10 +213,12 @@ module Fire
196
213
  end
197
214
 
198
215
  require_relative './querying/querying'
216
+ include Querying
217
+
199
218
  require_relative './nested/base'
200
219
  require_relative './nested/single'
201
220
  require_relative './nested/parent'
202
- include Querying
221
+
203
222
  include NestedModel::Parent
204
223
  end
205
224
  end
@@ -55,6 +55,14 @@ module Fire
55
55
  }
56
56
  end
57
57
 
58
+ def query(params={}, &filter_condition)
59
+ raise QueryingNotSupportedError.new
60
+ end
61
+
62
+ def all
63
+ query
64
+ end
65
+
58
66
  protected
59
67
 
60
68
  def default_folder_name
@@ -89,6 +97,12 @@ module Fire
89
97
  end
90
98
  end
91
99
 
100
+ class QueryingNotSupportedError < FireModelError
101
+ def initialize
102
+ super("Nested Models do not support querying")
103
+ end
104
+ end
105
+
92
106
  end
93
107
 
94
108
  end
@@ -15,7 +15,9 @@ module Fire
15
15
 
16
16
  folder = nested_model.folder
17
17
  define_method "nested_#{folder}" do
18
- nested_model.folder_content(self)
18
+ self.cache(folder) do
19
+ nested_model.folder_content(self)
20
+ end
19
21
  end
20
22
 
21
23
  define_method "add_to_#{folder}" do |object|
@@ -9,7 +9,8 @@ module Fire
9
9
  end
10
10
 
11
11
  def folder_content(parent)
12
- new(parent.send(folder).merge(parent.path_data))
12
+ object = parent.send(folder) || {}
13
+ new(object.merge(parent.path_data))
13
14
  end
14
15
 
15
16
  protected
@@ -12,7 +12,8 @@ module Fire
12
12
  response = connection.get(full_path).body
13
13
  return [] if response.nil?
14
14
 
15
- rows = down_levels(response, (own_path_keys - direct_keys).count)
15
+ needed_levels = (all_path_keys - direct_keys - default_path_keys).count
16
+ rows = down_levels(response, needed_levels)
16
17
 
17
18
  filter_result(rows, filter_opts(params, direct_keys), filter_condition)
18
19
  end
@@ -146,7 +146,7 @@ describe 'Fire Models' do
146
146
  has_path_keys(:library, :floor, :row_number, :shelf)
147
147
  end
148
148
 
149
- LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10, name: 'Kobzar', author: 'T.G. Shevchenko')
149
+ book = LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10, name: 'Kobzar', author: 'T.G. Shevchenko')
150
150
  LibraryBook.create(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 15, name: 'Eneida', author: 'I. Kotlyrevskiy')
151
151
  LibraryBook.create(library: 'Shevchenko', floor: 2, row_number: 15, shelf: 115, name: 'Lord Of The Rings', author: ' J.R.R. Tolkien')
152
152
  LibraryBook.create(library: 'Skovoroda', floor: 1, row_number: 25, shelf: 34, name: 'Harry Potter', author: 'J.K. Rowling')
@@ -172,6 +172,12 @@ describe 'Fire Models' do
172
172
 
173
173
  # Query by math condition
174
174
  expect(LibraryBook.query{|m| m.row_number % 5 == 0 }.map(&:name)).to eq([ 'Lord Of The Rings', 'Harry Potter' ])
175
+
176
+ # Query by full path
177
+ expect(LibraryBook.query(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10).map(&:name)).to eq([ 'Kobzar' ])
178
+
179
+ # Take by full path + ID
180
+ expect(LibraryBook.take(library: 'Shevchenko', floor: 1, row_number: 1, shelf: 10, id: book.id).name).to eq('Kobzar')
175
181
  end
176
182
 
177
183
  end
@@ -184,6 +190,7 @@ describe 'Fire Models' do
184
190
  has_path_keys(:x, :y)
185
191
  end
186
192
 
193
+ # Creating
187
194
  p1 = Point.create(x: 1, y: 1, value: 1)
188
195
  p2 = Point.create(x: 1, y: 2, value: 2)
189
196
  p3 = Point.create(x: 2, y: 1, value: 3)
@@ -191,23 +198,31 @@ describe 'Fire Models' do
191
198
 
192
199
  expect(Point.all.map(&:value).sort).to eq([ 1, 2, 3, 4 ].sort)
193
200
 
201
+ # ID generation
194
202
  expect(p1.id).to be
195
203
 
204
+ # Updating
196
205
  p1.value = 5
197
206
  expect(p1.path_changed?).to be_falsey
198
207
  p1.save
199
208
 
209
+
200
210
  expect(Point.all.map(&:value).sort).to eq([ 5, 2, 3, 4 ].sort)
201
211
 
202
212
  reloaded_point = Point.take(x: p2.x, y: p2.y, id: p2.id)
203
- reloaded_point.value = 6
213
+ reloaded_point.update(value: 6)
204
214
 
205
215
  expect(reloaded_point.path_changed?).to be_falsey
206
216
 
207
217
  reloaded_point.save
208
-
209
218
  expect(Point.all.map(&:value).sort).to eq([ 5, 6, 3, 4 ].sort)
210
219
 
220
+ # Reloading
221
+ expect(p2.value).to eq(2)
222
+ p2.reload
223
+ expect(p2.value).to eq(6)
224
+
225
+ # Deletion
211
226
  p1.delete
212
227
 
213
228
  expect(Point.all.map(&:value).sort).to eq([ 6, 3, 4].sort)
@@ -2,210 +2,223 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Nested Models' do
4
4
 
5
- before :each do
6
- Fire.drop!
7
- end
8
-
9
- after :each do
10
- Fire.drop!
11
- end
5
+ context 'With Firebase Connection' do
12
6
 
13
- it 'should declare nested models' do
14
-
15
- class Organization < Fire::Model
16
- has_path_keys :country, :state
17
- set_id_key(:name)
7
+ before :each do
8
+ Fire.drop!
18
9
  end
19
10
 
20
- expect(Organization.nested_models).to be_empty
11
+ after :each do
12
+ Fire.drop!
13
+ end
21
14
 
22
- class Employee < Fire::NestedModel
23
- nested_in Organization
24
- has_path_keys :department
15
+ def current_data
16
+ Fire.tree
25
17
  end
26
18
 
27
- expect(Organization.nested_models).to eq([ Employee ])
28
-
29
- google = Organization.create(name: 'Google', country: 'USA', state: 'CA')
30
- apple = Organization.create(name: 'Apple', country: 'USA', state: 'CA')
31
-
32
- expect(current_data).to eq(
33
- {'Organization'=>
34
- {'usa'=>
35
- {'ca'=>
36
- {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
37
- 'google'=>{'country'=>'USA', 'name'=>'Google', 'state'=>'CA'}}}}})
38
-
39
- larry = Employee.create(name: 'Google', country: 'USA', state: 'CA',
40
- department: 'HQ', full_name: 'Larry Page', position: 'CEO')
41
-
42
- expect(current_data).to eq(
43
- {'Organization'=>
44
- {'usa'=>
45
- {'ca'=>
46
- {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
47
- 'google'=>{
48
- 'country'=>'USA', 'name'=>'Google', 'state'=>'CA', 'employees' => {
49
- 'hq' => {
50
- larry.id => {
51
- 'id' => larry.id,
52
- 'full_name' => 'Larry Page',
53
- 'position' => 'CEO',
54
- 'department' => 'HQ',
55
- }}}}}}}})
56
-
57
- google = Organization.query(name: 'Google').first
58
- google.nested_employees
59
-
60
- employee = google.nested_employees.first
61
- expect(larry).to eq(employee)
62
-
63
- employee.department = 'Research'
64
- employee.save
65
-
66
- expect(current_data).to eq(
67
- {'Organization'=>
68
- {'usa'=>
69
- {'ca'=>
70
- {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
71
- 'google'=>{
72
- 'country'=>'USA', 'name'=>'Google', 'state'=>'CA', 'employees' => {
73
- 'research' => {
74
- larry.id => {
75
- 'id' => larry.id,
76
- 'full_name' => 'Larry Page',
77
- 'position' => 'CEO',
78
- 'department' => 'Research',
79
- }}}}}}}})
80
-
81
- apple = Organization.query(name: 'Apple').first
82
- tim = apple.add_to_employees(
83
- full_name: 'Tim Cook',
84
- position: 'CEO',
85
- department: 'HQ'
86
- )
87
-
88
- expect(current_data).to eq(
89
- {'Organization'=>
90
- {'usa'=>
91
- {'ca'=>
92
- {'apple'=>
93
- {'country'=>'USA',
94
- 'employees'=>
95
- {'hq'=>
96
- {tim.id=>
97
- {'department'=>'HQ',
98
- 'full_name'=>'Tim Cook',
99
- 'id'=>tim.id,
100
- 'position'=>'CEO'}}},
101
- 'name'=>'Apple',
102
- 'state'=>'CA'},
103
- 'google'=>
104
- {'country'=>'USA',
105
- 'employees'=>
106
- {'research'=>
107
- {larry.id=>
108
- {'department'=>'Research',
109
- 'full_name'=>'Larry Page',
110
- 'id'=>larry.id,
111
- 'position'=>'CEO'}}},
112
- 'name'=>'Google',
113
- 'state'=>'CA'}}}}}
114
- )
115
- end
19
+ it 'should declare nested models' do
116
20
 
117
- context 'Nested Models Types' do
21
+ class Organization < Fire::Model
22
+ has_path_keys :country, :state
23
+ set_id_key(:name)
24
+ end
118
25
 
119
- it 'should declare single nested models' do
26
+ expect(Organization.nested_models).to be_empty
120
27
 
121
- class Car < Fire::Model
122
- has_path_keys :manufacturer, :model, :car_class
28
+ class Employee < Fire::NestedModel
29
+ nested_in Organization
30
+ has_path_keys :department
123
31
  end
124
32
 
125
- class Engine < Fire::SingleNestedModel
126
- nested_in Car
127
- end
33
+ expect(Organization.nested_models).to eq([ Employee ])
34
+
35
+ google = Organization.create(name: 'Google', country: 'USA', state: 'CA')
36
+ apple = Organization.create(name: 'Apple', country: 'USA', state: 'CA')
128
37
 
129
- scirocco = Car.create(manufacturer: 'Volkswagen', model: 'Scirocco', car_class: 'Sport compact')
130
- scirocco.add_to_engine(code: 'I4 turbo', power: '122 PS')
131
-
132
- car = Car.create(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', engine: { code: 'MeMZ-966' })
133
-
134
- zaporozhets = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
135
- expect(zaporozhets.nested_engine.code).to eq('MeMZ-966')
136
-
137
- expect(current_data).to eq({
138
- 'Car'=>
139
- {'volkswagen'=>
140
- {'scirocco'=>
141
- {'sport-compact'=>
142
- {scirocco.id=>
143
- {'''car_class'=>'Sport compact',
144
- 'engine'=>{'code'=>'I4 turbo', 'power'=>'122 PS'},
145
- 'id'=>scirocco.id,
146
- 'manufacturer'=>'Volkswagen',
147
- 'model'=>'Scirocco'}}}},
148
- 'zaporozhets'=>
149
- {'zaz-965'=>
150
- {'mini'=>
151
- {zaporozhets.id=>
152
- {'car_class'=>'Mini',
153
- 'engine'=>{'code'=>'MeMZ-966'},
154
- 'id'=>zaporozhets.id,
155
- 'manufacturer'=>'Zaporozhets',
156
- 'model'=>'ZAZ-965'}}}}}})
38
+ expect(current_data).to eq(
39
+ {'Organization'=>
40
+ {'usa'=>
41
+ {'ca'=>
42
+ {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
43
+ 'google'=>{'country'=>'USA', 'name'=>'Google', 'state'=>'CA'}}}}})
44
+
45
+ larry = Employee.create(name: 'Google', country: 'USA', state: 'CA',
46
+ department: 'HQ', full_name: 'Larry Page', position: 'CEO')
47
+
48
+ expect(current_data).to eq(
49
+ {'Organization'=>
50
+ {'usa'=>
51
+ {'ca'=>
52
+ {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
53
+ 'google'=>{
54
+ 'country'=>'USA', 'name'=>'Google', 'state'=>'CA', 'employees' => {
55
+ 'hq' => {
56
+ larry.id => {
57
+ 'id' => larry.id,
58
+ 'full_name' => 'Larry Page',
59
+ 'position' => 'CEO',
60
+ 'department' => 'HQ',
61
+ }}}}}}}})
62
+
63
+
64
+ employee = google.reload.nested_employees.first
65
+ expect(larry).to eq(employee)
66
+
67
+ employee.update(department: 'Research')
68
+
69
+ expect(current_data).to eq(
70
+ {'Organization'=>
71
+ {'usa'=>
72
+ {'ca'=>
73
+ {'apple'=>{'country'=>'USA', 'name'=>'Apple', 'state'=>'CA'},
74
+ 'google'=>{
75
+ 'country'=>'USA', 'name'=>'Google', 'state'=>'CA', 'employees' => {
76
+ 'research' => {
77
+ larry.id => {
78
+ 'id' => larry.id,
79
+ 'full_name' => 'Larry Page',
80
+ 'position' => 'CEO',
81
+ 'department' => 'Research',
82
+ }}}}}}}})
83
+
84
+ tim = apple.add_to_employees(
85
+ full_name: 'Tim Cook',
86
+ position: 'CEO',
87
+ department: 'HQ'
88
+ )
89
+
90
+ expect(current_data).to eq(
91
+ {'Organization'=>
92
+ {'usa'=>
93
+ {'ca'=>
94
+ {'apple'=>
95
+ {'country'=>'USA',
96
+ 'employees'=>
97
+ {'hq'=>
98
+ {tim.id=>
99
+ {'department'=>'HQ',
100
+ 'full_name'=>'Tim Cook',
101
+ 'id'=>tim.id,
102
+ 'position'=>'CEO'}}},
103
+ 'name'=>'Apple',
104
+ 'state'=>'CA'},
105
+ 'google'=>
106
+ {'country'=>'USA',
107
+ 'employees'=>
108
+ {'research'=>
109
+ {larry.id=>
110
+ {'department'=>'Research',
111
+ 'full_name'=>'Larry Page',
112
+ 'id'=>larry.id,
113
+ 'position'=>'CEO'}}},
114
+ 'name'=>'Google',
115
+ 'state'=>'CA'}}}}}
116
+ )
157
117
  end
158
118
 
159
- it 'should allow to declare nested models with all *parent values* duplicated' do
160
- class House < Fire::Model
161
- has_path_keys :country, :city, :street
162
- set_id_key(:house_number)
163
- end
119
+ context 'Nested Models Types' do
120
+
121
+ it 'should declare single nested models' do
164
122
 
165
- class Room < Fire::NestedModel
166
- nested_in House, parent_values: true
167
- set_id_key(:number)
168
- has_path_keys :floor
123
+ class Car < Fire::Model
124
+ has_path_keys :manufacturer, :model, :car_class
125
+ end
126
+
127
+ class Engine < Fire::SingleNestedModel
128
+ nested_in Car
129
+ end
130
+
131
+ scirocco = Car.create(manufacturer: 'Volkswagen', model: 'Scirocco', car_class: 'Sport compact')
132
+ scirocco.add_to_engine(code: 'I4 turbo', power: '122 PS')
133
+
134
+ car = Car.create(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', engine: { code: 'MeMZ-966' })
135
+
136
+ zaporozhets = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
137
+ expect(zaporozhets.nested_engine.code).to eq('MeMZ-966')
138
+
139
+ expect(current_data).to eq({
140
+ 'Car'=>
141
+ {'volkswagen'=>
142
+ {'scirocco'=>
143
+ {'sport-compact'=>
144
+ {scirocco.id=>
145
+ {'car_class'=>'Sport compact',
146
+ 'engine'=>{'code'=>'I4 turbo', 'power'=>'122 PS'},
147
+ 'id'=>scirocco.id,
148
+ 'manufacturer'=>'Volkswagen',
149
+ 'model'=>'Scirocco'}}}},
150
+ 'zaporozhets'=>
151
+ {'zaz-965'=>
152
+ {'mini'=>
153
+ {zaporozhets.id=>
154
+ {'car_class'=>'Mini',
155
+ 'engine'=>{'code'=>'MeMZ-966'},
156
+ 'id'=>zaporozhets.id,
157
+ 'manufacturer'=>'Zaporozhets',
158
+ 'model'=>'ZAZ-965'}}}}}})
159
+
160
+ # nested association caching
161
+ zaporozhets.nested_engine.code = 'MeMZ-777'
162
+ expect(zaporozhets.nested_engine.code).to eq('MeMZ-777')
163
+ expect(zaporozhets.reload.nested_engine.code).to eq('MeMZ-966')
164
+
165
+ # nested association saving
166
+ zap2 = Car.take(manufacturer: 'Zaporozhets', model: 'ZAZ-965', car_class: 'Mini', id: car.id)
167
+ zap2.nested_engine.update(code: 'MeMZ-555')
168
+ expect(zaporozhets.nested_engine.reload.code).to eq('MeMZ-555')
169
169
  end
170
170
 
171
- house = House.create(country: 'Ukraine', city: 'Kyiv', street: 'Shevchenko Ave.', house_number: '53101')
172
- house.add_to_rooms(floor: 200, number: '1A')
173
- house.add_to_rooms(floor: 150, number: '2A')
171
+ it 'should allow to declare nested models with all *parent values* duplicated' do
172
+ class House < Fire::Model
173
+ has_path_keys :country, :city, :street
174
+ set_id_key(:house_number)
175
+ end
176
+
177
+ class Room < Fire::NestedModel
178
+ nested_in House, parent_values: true
179
+ set_id_key(:number)
180
+ has_path_keys :floor
181
+ end
174
182
 
175
- house = House.query(house_number: '53101').first
176
- rooms = house.nested_rooms
177
- expect(rooms.map(&:number).sort).to eq(%w{ 1A 2A }.sort)
183
+ house = House.create(country: 'Ukraine', city: 'Kyiv', street: 'Shevchenko Ave.', house_number: '53101')
184
+ house.add_to_rooms(floor: 200, number: '1A')
185
+ house.add_to_rooms(floor: 150, number: '2A')
186
+
187
+
188
+ rooms = house.reload.nested_rooms
189
+ expect(rooms.map(&:number).sort).to eq(%w{ 1A 2A }.sort)
190
+
191
+ expect(current_data).to eq(
192
+ {'House'=>
193
+ {'ukraine'=>
194
+ {'kyiv'=>
195
+ {'shevchenko-ave'=>
196
+ {'53101'=>
197
+ {'city'=>'Kyiv',
198
+ 'country'=>'Ukraine',
199
+ 'house_number'=>'53101',
200
+ 'rooms'=>
201
+ {'150_'=>
202
+ {'2a'=>
203
+ {'city'=>'Kyiv',
204
+ 'country'=>'Ukraine',
205
+ 'floor'=>150,
206
+ 'number'=>'2A',
207
+ 'house_number'=>'53101',
208
+ 'street'=>'Shevchenko Ave.'}},
209
+ '200_'=>
210
+ {'1a'=>
211
+ {'city'=>'Kyiv',
212
+ 'country'=>'Ukraine',
213
+ 'floor'=>200,
214
+ 'number'=>'1A',
215
+ 'house_number'=>'53101',
216
+ 'street'=>'Shevchenko Ave.'}}},
217
+ 'street'=>'Shevchenko Ave.'}}}}}})
178
218
 
179
- expect(current_data).to eq(
180
- {'House'=>
181
- {'ukraine'=>
182
- {'kyiv'=>
183
- {'shevchenko-ave'=>
184
- {'53101'=>
185
- {'city'=>'Kyiv',
186
- 'country'=>'Ukraine',
187
- 'house_number'=>'53101',
188
- 'rooms'=>
189
- {'150_'=>
190
- {'2a'=>
191
- {'city'=>'Kyiv',
192
- 'country'=>'Ukraine',
193
- 'floor'=>150,
194
- 'number'=>'2A',
195
- 'house_number'=>'53101',
196
- 'street'=>'Shevchenko Ave.'}},
197
- '200_'=>
198
- {'1a'=>
199
- {'city'=>'Kyiv',
200
- 'country'=>'Ukraine',
201
- 'floor'=>200,
202
- 'number'=>'1A',
203
- 'house_number'=>'53101',
204
- 'street'=>'Shevchenko Ave.'}}},
205
- 'street'=>'Shevchenko Ave.'}}}}}})
219
+ end
206
220
 
207
221
  end
208
-
209
222
  end
210
223
 
211
224
  context 'Restrictions' do
@@ -262,10 +275,22 @@ describe 'Nested Models' do
262
275
  end
263
276
  }).to raise_error(Fire::SingleNestedModel::PathKeysNotSupported)
264
277
  end
265
- end
266
278
 
267
- def current_data
268
- Fire.connection.get(?/).body
279
+ it 'should now allow to query by Nested Models' do
280
+ class Earth < Fire::Model
281
+
282
+ end
283
+
284
+ class Moon < Fire::SingleNestedModel
285
+ nested_in Earth
286
+ end
287
+
288
+ expect(->{
289
+ Moon.query
290
+ }).to raise_error(Fire::NestedModel::QueryingNotSupportedError)
291
+ end
292
+
293
+
269
294
  end
270
295
 
271
296
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fire-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vitaly Tarasenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-20 00:00:00.000000000 Z
11
+ date: 2015-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tarvit-helpers