fire-model 0.0.2 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +111 -0
- data/VERSION +1 -1
- data/fire-model.gemspec +11 -7
- data/lib/fire-model.rb +6 -2
- data/lib/{model.rb → model/model.rb} +26 -39
- data/lib/model/nested/nested_model.rb +71 -0
- data/lib/model/nested/parent.rb +38 -0
- data/lib/model/querying/querying.rb +54 -0
- data/spec/models/{fire_model_spec.rb → main_spec.rb} +25 -4
- data/spec/models/nested_models_spec.rb +162 -0
- metadata +10 -6
- data/README.rdoc +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6c2fd8a5b0c94437795c9fb89ba94b2cfcc5b5c
|
4
|
+
data.tar.gz: ad45e8dbfeebfe2a2f526b1776683520db018781
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d20eea46eda6c341c1704ffe7bbbeefc946d2fee0cc8546c194db45c122bb75bb6b119a052d31c69942a757278a054ecc74ed63d8edde2c30c5a9beeec1e4e46
|
7
|
+
data.tar.gz: 40c84c04420569fd75259637863d6972673a6274f9599cbe24483cd6e3972e61d53e9ab4499e0c5fe538c30699f7b822dc107a16d1d59b183f3834377d5c29ec
|
data/README.md
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
**fire-model** -
|
2
|
+
REST wrapper for **Firebase**.
|
3
|
+
|
4
|
+
Setup Firebase
|
5
|
+
```ruby
|
6
|
+
Fire.setup(firebase_path: 'https://some-test-777.firebaseio.com')
|
7
|
+
```
|
8
|
+
|
9
|
+
Declare your Model
|
10
|
+
```ruby
|
11
|
+
class LibraryBook < Fire::Model
|
12
|
+
has_path_keys(:library, :floor, :row_number, :shelf)
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
Use query syntax
|
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')
|
23
|
+
|
24
|
+
LibraryBook.all.map(&:name)
|
25
|
+
=> [ 'Kobzar', 'Eneida', 'Lord Of The Rings', 'Harry Potter', 'Hobbit' ]
|
26
|
+
|
27
|
+
# Query by library
|
28
|
+
LibraryBook.query(library: 'Shevchenko').map(&:name)
|
29
|
+
=> [ 'Kobzar', 'Eneida', 'Lord Of The Rings' ]
|
30
|
+
LibraryBook.query(library: 'Skovoroda').map(&:name)
|
31
|
+
=> [ 'Harry Potter', 'Hobbit' ]
|
32
|
+
|
33
|
+
# Query by library, floor
|
34
|
+
LibraryBook.query(library: 'Shevchenko', floor: 1).map(&:name)
|
35
|
+
=> [ 'Kobzar', 'Eneida' ]
|
36
|
+
|
37
|
+
# Query by library, floor, row
|
38
|
+
LibraryBook.query(library: 'Shevchenko', floor: 1, row_number: 1).map(&:name)
|
39
|
+
=> [ 'Kobzar', 'Eneida' ]
|
40
|
+
|
41
|
+
# Query by shelf
|
42
|
+
LibraryBook.query(shelf: 15).map(&:name)
|
43
|
+
=> [ 'Eneida', 'Hobbit' ]
|
44
|
+
|
45
|
+
# Query by author
|
46
|
+
LibraryBook.query(author: ' J.R.R. Tolkien').map(&:name)
|
47
|
+
=> [ 'Lord Of The Rings', 'Hobbit' ]
|
48
|
+
|
49
|
+
# Query by math condition
|
50
|
+
LibraryBook.query{|m| m.row_number % 5 == 0 }.map(&:name)
|
51
|
+
=> [ 'Lord Of The Rings', 'Harry Potter' ]
|
52
|
+
```
|
53
|
+
Play with CRUD
|
54
|
+
```ruby
|
55
|
+
class Point < Fire::Model
|
56
|
+
has_path_keys(:x, :y)
|
57
|
+
end
|
58
|
+
|
59
|
+
p1 = Point.create(x: 1, y: 1, value: 1)
|
60
|
+
p2 = Point.create(x: 1, y: 2, value: 2)
|
61
|
+
p3 = Point.create(x: 2, y: 1, value: 3)
|
62
|
+
p4 = Point.create(x: 1, y: 1, value: 4)
|
63
|
+
|
64
|
+
Point.all.map(&:value)
|
65
|
+
=> [ 1, 2, 3, 4 ]
|
66
|
+
|
67
|
+
p1.value = 5
|
68
|
+
p1.path_changed?
|
69
|
+
=> false
|
70
|
+
|
71
|
+
p1.save
|
72
|
+
|
73
|
+
reloaded_point = Point.take(x: p2.x, y: p2.y, id: p2.id)
|
74
|
+
reloaded_point.value = 6
|
75
|
+
|
76
|
+
reloaded_point.path_changed?
|
77
|
+
=> false
|
78
|
+
|
79
|
+
reloaded_point.save
|
80
|
+
|
81
|
+
p1.delete
|
82
|
+
|
83
|
+
Point.all.map(&:value)
|
84
|
+
=> [ 6, 3, 4]
|
85
|
+
|
86
|
+
p3.x = 4
|
87
|
+
p3.path_changed?
|
88
|
+
=> true
|
89
|
+
|
90
|
+
p3.save
|
91
|
+
|
92
|
+
Point.all.map(&:value)
|
93
|
+
=> [ 6, 3, 4]
|
94
|
+
```
|
95
|
+
|
96
|
+
|
97
|
+
**Contributing to fire-model**
|
98
|
+
|
99
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
100
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
101
|
+
* Fork the project.
|
102
|
+
* Start a feature/bugfix branch.
|
103
|
+
* Commit and push until you are happy with your contribution.
|
104
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
105
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
106
|
+
|
107
|
+
**Copyright**
|
108
|
+
|
109
|
+
Copyright (c) 2015 Vitaly Tarasenko. See LICENSE.txt for
|
110
|
+
further details.
|
111
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/fire-model.gemspec
CHANGED
@@ -2,35 +2,39 @@
|
|
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.
|
5
|
+
# stub: fire-model 0.0.6 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "fire-model"
|
9
|
-
s.version = "0.0.
|
9
|
+
s.version = "0.0.6"
|
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-
|
14
|
+
s.date = "2015-06-19"
|
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 = [
|
18
18
|
"LICENSE.txt",
|
19
|
-
"README.
|
19
|
+
"README.md"
|
20
20
|
]
|
21
21
|
s.files = [
|
22
22
|
".document",
|
23
23
|
"Gemfile",
|
24
24
|
"LICENSE.txt",
|
25
|
-
"README.
|
25
|
+
"README.md",
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"fire-model.gemspec",
|
29
29
|
"lib/connection/request.rb",
|
30
30
|
"lib/connection/response.rb",
|
31
31
|
"lib/fire-model.rb",
|
32
|
-
"lib/model.rb",
|
33
|
-
"
|
32
|
+
"lib/model/model.rb",
|
33
|
+
"lib/model/nested/nested_model.rb",
|
34
|
+
"lib/model/nested/parent.rb",
|
35
|
+
"lib/model/querying/querying.rb",
|
36
|
+
"spec/models/main_spec.rb",
|
37
|
+
"spec/models/nested_models_spec.rb",
|
34
38
|
"spec/spec_helper.rb"
|
35
39
|
]
|
36
40
|
s.homepage = "http://github.com/tarvit/fire-model"
|
data/lib/fire-model.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Fire
|
2
2
|
require 'connection/response'
|
3
3
|
require 'connection/request'
|
4
|
-
require 'model'
|
4
|
+
require 'model/model'
|
5
5
|
|
6
6
|
require 'ostruct'
|
7
7
|
|
@@ -17,7 +17,11 @@ module Fire
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.drop!
|
20
|
-
|
20
|
+
connection.delete(?/)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.connection
|
24
|
+
Fire::Connection::Request.new
|
21
25
|
end
|
22
26
|
|
23
27
|
private
|
@@ -7,7 +7,7 @@ module Fire
|
|
7
7
|
include TarvitHelpers::NonSharedAccessors
|
8
8
|
LEVEL_SEPARATOR = ?/
|
9
9
|
|
10
|
-
non_shared_cattr_accessor :fire_collection, :path_keys
|
10
|
+
non_shared_cattr_accessor :fire_collection, :path_keys, :id_key_name
|
11
11
|
|
12
12
|
def initialize(attrs={})
|
13
13
|
data = self.class.prepare_hash(attrs)
|
@@ -27,13 +27,17 @@ module Fire
|
|
27
27
|
self.class.id_key
|
28
28
|
end
|
29
29
|
|
30
|
+
def id_value
|
31
|
+
send(id_key)
|
32
|
+
end
|
33
|
+
|
30
34
|
def collection_name
|
31
35
|
self.class.collection_name
|
32
36
|
end
|
33
37
|
|
34
38
|
def save
|
35
39
|
self.class.new(@original_data).delete if path_changed?
|
36
|
-
self.class.connection.set(path, self.
|
40
|
+
self.class.connection.set(path, self.saving_data)
|
37
41
|
@persisted = true
|
38
42
|
end
|
39
43
|
|
@@ -94,6 +98,10 @@ module Fire
|
|
94
98
|
self.to_h
|
95
99
|
end
|
96
100
|
|
101
|
+
def saving_data
|
102
|
+
data
|
103
|
+
end
|
104
|
+
|
97
105
|
class << self
|
98
106
|
|
99
107
|
# Klass Setters
|
@@ -106,6 +114,10 @@ module Fire
|
|
106
114
|
self.path_keys = keys
|
107
115
|
end
|
108
116
|
|
117
|
+
def set_id_key(value)
|
118
|
+
self.id_key_name = value
|
119
|
+
end
|
120
|
+
|
109
121
|
# Klass Accessors
|
110
122
|
|
111
123
|
def collection_name
|
@@ -126,42 +138,6 @@ module Fire
|
|
126
138
|
|
127
139
|
# Record Methods
|
128
140
|
|
129
|
-
def query(params={}, &filter_condition)
|
130
|
-
path_values, selected_keys = [], []
|
131
|
-
|
132
|
-
own_path_keys.each do |key|
|
133
|
-
if params[key]
|
134
|
-
path_values << path_value_param(params[key])
|
135
|
-
selected_keys << key
|
136
|
-
else
|
137
|
-
break
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
full_path = ([ collection_name ] + path_values) * LEVEL_SEPARATOR
|
142
|
-
response = connection.get(full_path).body
|
143
|
-
|
144
|
-
return [] if response.nil?
|
145
|
-
result = response.values
|
146
|
-
|
147
|
-
(own_path_keys - selected_keys).count.times do
|
148
|
-
result = result.map(&:values).flatten.compact
|
149
|
-
end
|
150
|
-
|
151
|
-
filter = params.clone
|
152
|
-
selected_keys.each do |sk|
|
153
|
-
filter.delete(sk)
|
154
|
-
end
|
155
|
-
|
156
|
-
result.map{|data| new(data) }.select do |model_object|
|
157
|
-
not_filtered_by_attributes = model_object.has_data?(filter)
|
158
|
-
not_filtered_by_block = block_given? ? filter_condition.(model_object) : true
|
159
|
-
not_filtered_by_attributes && not_filtered_by_block
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
alias_method :all, :query
|
164
|
-
|
165
141
|
def take(path_data)
|
166
142
|
path_object = new(path_data)
|
167
143
|
loaded_data = connection.get(path_object.path).body
|
@@ -190,7 +166,7 @@ module Fire
|
|
190
166
|
end
|
191
167
|
|
192
168
|
def id_key
|
193
|
-
:id
|
169
|
+
self.id_key_name || :id
|
194
170
|
end
|
195
171
|
|
196
172
|
protected
|
@@ -213,5 +189,16 @@ module Fire
|
|
213
189
|
end
|
214
190
|
end
|
215
191
|
|
192
|
+
class InvalidPathKeyError < FireModelError
|
193
|
+
def initialize(key, message=nil)
|
194
|
+
super (message || "Path key '#{ key }' is invalid")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
require_relative './querying/querying'
|
199
|
+
require_relative './nested/parent'
|
200
|
+
require_relative './nested/nested_model'
|
201
|
+
include Querying
|
202
|
+
include Parent
|
216
203
|
end
|
217
204
|
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Fire
|
2
|
+
|
3
|
+
class NestedModel < Model
|
4
|
+
non_shared_cattr_accessor :parent, :nested_options
|
5
|
+
|
6
|
+
def saving_data
|
7
|
+
res = data.clone
|
8
|
+
self.class.parent.all_path_keys.each do |k|
|
9
|
+
res.delete(k)
|
10
|
+
end
|
11
|
+
res
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def in_collection(name)
|
16
|
+
raise CollectionIsSetError.new(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_path_keys(*keys)
|
20
|
+
raise ParentModelNotSetError.new(self) unless self.parent
|
21
|
+
super(*keys)
|
22
|
+
keys.each do |key|
|
23
|
+
raise DuplicatedParentPathKeyError.new(key, self.parent) if self.parent.all_path_keys.include?(key)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def nested_in(parent, options)
|
28
|
+
self.parent = parent
|
29
|
+
self.nested_options = OpenStruct.new(options)
|
30
|
+
self.parent.has_nested(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def own_path_keys
|
34
|
+
parent.all_path_keys + [ nested_options.folder ] + super()
|
35
|
+
end
|
36
|
+
|
37
|
+
def collection_name
|
38
|
+
parent.collection_name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def method_missing(*args)
|
43
|
+
if args.first.to_s == self.class.nested_options.folder
|
44
|
+
self.class.nested_options.folder
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class DuplicatedParentPathKeyError < InvalidPathKeyError
|
51
|
+
def initialize(key, parent)
|
52
|
+
message = "Key '#{key}' is duplicated in a Parent Model '#{parent}'"
|
53
|
+
super(key, message)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class ParentModelNotSetError < FireModelError
|
58
|
+
def initialize(nested_model)
|
59
|
+
super("Nested Model '#{nested_model}' has no Parent Model set. Call `nested_in` to set a Parent.")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class CollectionIsSetError < FireModelError
|
64
|
+
def initialize(nested_model)
|
65
|
+
super("Nested Model '#{nested_model}' can not have own Collection. It is extended from Parent Model '#{nested_model.parent}'")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Fire
|
2
|
+
class Model
|
3
|
+
module Parent
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
non_shared_cattr_accessor :assigned_nested_models
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def has_nested(nested_model)
|
13
|
+
self.assigned_nested_models ||= []
|
14
|
+
self.assigned_nested_models << nested_model
|
15
|
+
|
16
|
+
folder = nested_model.nested_options.folder
|
17
|
+
define_method "nested_#{folder}" do
|
18
|
+
objects = self.class.down_levels(send(folder), nested_model.path_keys.count)
|
19
|
+
objects.map{|x|
|
20
|
+
full_data = x.merge(self.path_data)
|
21
|
+
nested_model.new(full_data)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method "add_to_#{folder}" do |object|
|
26
|
+
nested_model.create(object.merge(self.path_data))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def nested_models
|
31
|
+
self.assigned_nested_models || []
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Fire
|
2
|
+
class Model
|
3
|
+
module Querying
|
4
|
+
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def query(params={}, &filter_condition)
|
9
|
+
path_values, selected_keys = [], []
|
10
|
+
|
11
|
+
own_path_keys.each do |key|
|
12
|
+
if params[key]
|
13
|
+
path_values << path_value_param(params[key])
|
14
|
+
selected_keys << key
|
15
|
+
else
|
16
|
+
break
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
full_path = ([ collection_name ] + path_values) * LEVEL_SEPARATOR
|
21
|
+
response = connection.get(full_path).body
|
22
|
+
|
23
|
+
return [] if response.nil?
|
24
|
+
|
25
|
+
result = down_levels(response, (own_path_keys - selected_keys).count)
|
26
|
+
|
27
|
+
filter = params.clone
|
28
|
+
selected_keys.each do |sk|
|
29
|
+
filter.delete(sk)
|
30
|
+
end
|
31
|
+
|
32
|
+
result.map{|data| new(data) }.select do |model_object|
|
33
|
+
not_filtered_by_attributes = model_object.has_data?(filter)
|
34
|
+
not_filtered_by_block = block_given? ? filter_condition.(model_object) : true
|
35
|
+
not_filtered_by_attributes && not_filtered_by_block
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :all, :query
|
40
|
+
|
41
|
+
def down_levels(root, levels_count)
|
42
|
+
result = root.values
|
43
|
+
|
44
|
+
levels_count.times do
|
45
|
+
result = result.map(&:values).flatten.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
result
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -178,11 +178,12 @@ describe 'Fire Models' do
|
|
178
178
|
|
179
179
|
context 'Updating' do
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
|
181
|
+
it 'should update data (default ID key)' do
|
182
|
+
|
183
|
+
class Point < Fire::Model
|
184
|
+
has_path_keys(:x, :y)
|
185
|
+
end
|
184
186
|
|
185
|
-
it 'should update data' do
|
186
187
|
p1 = Point.create(x: 1, y: 1, value: 1)
|
187
188
|
p2 = Point.create(x: 1, y: 2, value: 2)
|
188
189
|
p3 = Point.create(x: 2, y: 1, value: 3)
|
@@ -190,6 +191,8 @@ describe 'Fire Models' do
|
|
190
191
|
|
191
192
|
expect(Point.all.map(&:value).sort).to eq([ 1, 2, 3, 4 ].sort)
|
192
193
|
|
194
|
+
expect(p1.id).to be
|
195
|
+
|
193
196
|
p1.value = 5
|
194
197
|
expect(p1.path_changed?).to be_falsey
|
195
198
|
p1.save
|
@@ -216,6 +219,24 @@ describe 'Fire Models' do
|
|
216
219
|
expect(Point.all.map(&:value).sort).to eq([ 6, 3, 4].sort)
|
217
220
|
end
|
218
221
|
|
222
|
+
it 'should update data (custom ID key)' do
|
223
|
+
class Point < Fire::Model
|
224
|
+
has_path_keys(:x, :y)
|
225
|
+
set_id_key(:z)
|
226
|
+
end
|
227
|
+
|
228
|
+
p1 = Point.create(x: 1, y: 1, value: 1)
|
229
|
+
expect(p1.z).to be
|
230
|
+
expect(p1.id).to be_nil
|
231
|
+
|
232
|
+
p1.z = 10
|
233
|
+
p1.save
|
234
|
+
|
235
|
+
reloaded_point = Point.take(x: 1, y: 1, z: 10)
|
236
|
+
|
237
|
+
expect(reloaded_point).to eq(p1)
|
238
|
+
end
|
239
|
+
|
219
240
|
end
|
220
241
|
|
221
242
|
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Nested Models' do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
Fire.drop!
|
7
|
+
end
|
8
|
+
|
9
|
+
after :each do
|
10
|
+
Fire.drop!
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should declare nested models' do
|
14
|
+
|
15
|
+
class Organization < Fire::Model
|
16
|
+
has_path_keys :country, :state
|
17
|
+
set_id_key(:name)
|
18
|
+
end
|
19
|
+
|
20
|
+
expect(Organization.nested_models).to be_empty
|
21
|
+
|
22
|
+
class Employee < Fire::NestedModel
|
23
|
+
nested_in Organization, folder: 'employees'
|
24
|
+
has_path_keys :department
|
25
|
+
end
|
26
|
+
|
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
|
116
|
+
|
117
|
+
context 'Restrictions' do
|
118
|
+
before :all do
|
119
|
+
|
120
|
+
class Hotel < Fire::Model
|
121
|
+
has_path_keys :location, :class
|
122
|
+
set_id_key(:name)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should not allow to set path keys if parent model is not set' do
|
128
|
+
expect(->{
|
129
|
+
class Room < Fire::NestedModel
|
130
|
+
has_path_keys :number
|
131
|
+
end
|
132
|
+
}).to raise_error(Fire::NestedModel::ParentModelNotSetError)
|
133
|
+
|
134
|
+
expect(->{
|
135
|
+
class Room < Fire::NestedModel
|
136
|
+
nested_in Hotel, folder: 'rooms'
|
137
|
+
has_path_keys :number
|
138
|
+
end
|
139
|
+
}).to be
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should not allow to declare duplicated path keys in nested models' do
|
143
|
+
expect(->{
|
144
|
+
class Room < Fire::NestedModel
|
145
|
+
nested_in Hotel, folder: 'rooms'
|
146
|
+
has_path_keys :number, :class
|
147
|
+
end
|
148
|
+
}).to raise_error(Fire::NestedModel::DuplicatedParentPathKeyError)
|
149
|
+
|
150
|
+
expect(->{
|
151
|
+
class Room < Fire::NestedModel
|
152
|
+
has_path_keys :number, :room_class
|
153
|
+
end
|
154
|
+
}).to be
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def current_data
|
159
|
+
Fire.connection.get(?/).body
|
160
|
+
end
|
161
|
+
|
162
|
+
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.
|
4
|
+
version: 0.0.6
|
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-
|
11
|
+
date: 2015-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tarvit-helpers
|
@@ -143,20 +143,24 @@ executables: []
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files:
|
145
145
|
- LICENSE.txt
|
146
|
-
- README.
|
146
|
+
- README.md
|
147
147
|
files:
|
148
148
|
- .document
|
149
149
|
- Gemfile
|
150
150
|
- LICENSE.txt
|
151
|
-
- README.
|
151
|
+
- README.md
|
152
152
|
- Rakefile
|
153
153
|
- VERSION
|
154
154
|
- fire-model.gemspec
|
155
155
|
- lib/connection/request.rb
|
156
156
|
- lib/connection/response.rb
|
157
157
|
- lib/fire-model.rb
|
158
|
-
- lib/model.rb
|
159
|
-
-
|
158
|
+
- lib/model/model.rb
|
159
|
+
- lib/model/nested/nested_model.rb
|
160
|
+
- lib/model/nested/parent.rb
|
161
|
+
- lib/model/querying/querying.rb
|
162
|
+
- spec/models/main_spec.rb
|
163
|
+
- spec/models/nested_models_spec.rb
|
160
164
|
- spec/spec_helper.rb
|
161
165
|
homepage: http://github.com/tarvit/fire-model
|
162
166
|
licenses:
|
data/README.rdoc
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
= fire-model
|
2
|
-
|
3
|
-
Description goes here.
|
4
|
-
|
5
|
-
== Contributing to fire-model
|
6
|
-
|
7
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
8
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
9
|
-
* Fork the project.
|
10
|
-
* Start a feature/bugfix branch.
|
11
|
-
* Commit and push until you are happy with your contribution.
|
12
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
-
|
15
|
-
== Copyright
|
16
|
-
|
17
|
-
Copyright (c) 2015 Vitaly Tarasenko. See LICENSE.txt for
|
18
|
-
further details.
|
19
|
-
|