sequel_mapper 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +43 -0
- data/LICENSE.txt +22 -0
- data/README.md +112 -0
- data/Rakefile +2 -0
- data/TODO.md +33 -0
- data/lib/sequel_mapper.rb +4 -0
- data/lib/sequel_mapper/association_proxy.rb +54 -0
- data/lib/sequel_mapper/belongs_to_association_proxy.rb +27 -0
- data/lib/sequel_mapper/graph.rb +174 -0
- data/lib/sequel_mapper/queryable_association_proxy.rb +23 -0
- data/lib/sequel_mapper/struct_factory.rb +17 -0
- data/lib/sequel_mapper/version.rb +3 -0
- data/sequel_mapper.gemspec +28 -0
- data/spec/graph_persistence_spec.rb +287 -0
- data/spec/graph_traversal_spec.rb +85 -0
- data/spec/ordered_association_spec.rb +29 -0
- data/spec/proxying_spec.rb +82 -0
- data/spec/querying_spec.rb +51 -0
- data/spec/sequel_mapper/association_proxy_spec.rb +95 -0
- data/spec/sequel_mapper/belongs_to_association_proxy_spec.rb +65 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/graph_fixture.rb +331 -0
- data/spec/support/mock_sequel.rb +194 -0
- data/spec/support/query_counter.rb +29 -0
- metadata +167 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sequel_mapper"
|
4
|
+
require "support/graph_fixture"
|
5
|
+
|
6
|
+
RSpec.describe "Ordered associations" do
|
7
|
+
include SequelMapper::GraphFixture
|
8
|
+
|
9
|
+
context "of type `has_many`" do
|
10
|
+
subject(:graph) {
|
11
|
+
SequelMapper::Graph.new(
|
12
|
+
top_level_namespace: :users,
|
13
|
+
datastore: datastore,
|
14
|
+
relation_mappings: relation_mappings,
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:user) {
|
19
|
+
graph.where(id: "user/1").first
|
20
|
+
}
|
21
|
+
|
22
|
+
it "enumerates the objects in order specified in the config" do
|
23
|
+
user.toots.to_a
|
24
|
+
|
25
|
+
expect(user.toots.map(&:id).to_a)
|
26
|
+
.to eq(user.toots.to_a.sort_by { |t| t.tooted_at }.map(&:id).reverse)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sequel_mapper"
|
4
|
+
require "support/graph_fixture"
|
5
|
+
|
6
|
+
RSpec.describe "Proxying associations" do
|
7
|
+
include SequelMapper::GraphFixture
|
8
|
+
|
9
|
+
context "of type `has_many`" do
|
10
|
+
subject(:graph) {
|
11
|
+
SequelMapper::Graph.new(
|
12
|
+
top_level_namespace: :users,
|
13
|
+
datastore: datastore,
|
14
|
+
relation_mappings: relation_mappings,
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:user) {
|
19
|
+
graph.where(id: "user/1").first
|
20
|
+
}
|
21
|
+
|
22
|
+
let(:posts) { user.posts }
|
23
|
+
|
24
|
+
def identity
|
25
|
+
->(x){x}
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "limiting datastore reads" do
|
29
|
+
context "when loading the root node" do
|
30
|
+
it "only performs one read" do
|
31
|
+
user
|
32
|
+
|
33
|
+
expect(query_counter.read_count).to eq(1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when getting a reference to an association proxy" do
|
38
|
+
before { user }
|
39
|
+
|
40
|
+
it "does no additional reads" do
|
41
|
+
expect{
|
42
|
+
user.posts
|
43
|
+
}.to change { query_counter.read_count }.by(0)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when iteratiing over a has many association" do
|
48
|
+
before { posts }
|
49
|
+
|
50
|
+
it "does a single additional read for the assocation collection" do
|
51
|
+
expect {
|
52
|
+
user.posts.map(&identity)
|
53
|
+
}.to change { query_counter.read_count }.by(1)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when getting a reference to a many to many assocation" do
|
58
|
+
before { post }
|
59
|
+
|
60
|
+
let(:post) { user.posts.first }
|
61
|
+
|
62
|
+
it "does no additional reads" do
|
63
|
+
expect {
|
64
|
+
post.categories
|
65
|
+
}.to change { query_counter.read_count }.by(0)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when iterating over a many to many assocation" do
|
70
|
+
let(:category_count) { 3 }
|
71
|
+
|
72
|
+
it "does 1 read" do
|
73
|
+
post = user.posts.first
|
74
|
+
|
75
|
+
expect {
|
76
|
+
post.categories.map(&:name).to_a
|
77
|
+
}.to change { query_counter.read_count }.by(1)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sequel_mapper"
|
4
|
+
require "support/graph_fixture"
|
5
|
+
|
6
|
+
RSpec.describe "Querying" do
|
7
|
+
include SequelMapper::GraphFixture
|
8
|
+
|
9
|
+
subject(:graph) {
|
10
|
+
SequelMapper::Graph.new(
|
11
|
+
top_level_namespace: :users,
|
12
|
+
datastore: datastore,
|
13
|
+
relation_mappings: relation_mappings,
|
14
|
+
)
|
15
|
+
}
|
16
|
+
|
17
|
+
let(:user) {
|
18
|
+
graph.where(id: "user/1").first
|
19
|
+
}
|
20
|
+
|
21
|
+
let(:query_criteria) {
|
22
|
+
{
|
23
|
+
body: "Lazy load all the things!",
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
describe "arbitrary where query" do
|
28
|
+
it "returns a filtered version of the association" do
|
29
|
+
expect(
|
30
|
+
user.posts
|
31
|
+
.where(query_criteria)
|
32
|
+
.map(&:id)
|
33
|
+
).to eq(["post/2"])
|
34
|
+
end
|
35
|
+
|
36
|
+
it "sends the query directly to the datastore" do
|
37
|
+
expect {
|
38
|
+
user.posts
|
39
|
+
.where(query_criteria)
|
40
|
+
.map(&:id)
|
41
|
+
}.to change { query_counter.read_count }.by(2)
|
42
|
+
|
43
|
+
# TODO: this is a quick hack to assert that no superfluous records where
|
44
|
+
# loaded. Figure out a better way to check efficiency
|
45
|
+
expect(graph.send(:identity_map).values.map(&:id)).to match_array([
|
46
|
+
"user/1",
|
47
|
+
"post/2",
|
48
|
+
])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sequel_mapper/association_proxy"
|
4
|
+
|
5
|
+
RSpec.describe SequelMapper::AssociationProxy do
|
6
|
+
let(:proxy) {
|
7
|
+
SequelMapper::AssociationProxy.new(lazy_enum)
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:lazy_enum) { data_set.each.lazy }
|
11
|
+
let(:data_set) { (0..9) }
|
12
|
+
|
13
|
+
def id
|
14
|
+
->(x) { x }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "is Enumerable" do
|
18
|
+
expect(proxy).to be_a(Enumerable)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#to_a" do
|
22
|
+
it "is equivalent to the original enumeration" do
|
23
|
+
expect(proxy.map(&id)).to eq(data_set.to_a)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#each" do
|
28
|
+
context "when called with a block" do
|
29
|
+
it "returns self" do
|
30
|
+
expect(proxy.each(&id)).to eq(proxy)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "yields each element to the block" do
|
34
|
+
yielded = []
|
35
|
+
|
36
|
+
proxy.each do |element|
|
37
|
+
yielded.push(element)
|
38
|
+
end
|
39
|
+
|
40
|
+
expect(yielded).to eq(data_set.to_a)
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when calling each more than once" do
|
44
|
+
before do
|
45
|
+
proxy.each { |x| nil }
|
46
|
+
proxy.each { |x| nil }
|
47
|
+
end
|
48
|
+
|
49
|
+
it "rewinds the enumeration on each call" do
|
50
|
+
expect(proxy.map(&id)).to eq(data_set.to_a)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when called without a block" do
|
56
|
+
it "returns an enumerator" do
|
57
|
+
expect(proxy.each).to be_a(Enumerator)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#remove" do
|
63
|
+
it "returns self" do
|
64
|
+
expect(proxy.remove(3)).to be(proxy)
|
65
|
+
end
|
66
|
+
|
67
|
+
context "after removing a element from the enumeration" do
|
68
|
+
before do
|
69
|
+
proxy.remove(3)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "skips that element in the enumeration" do
|
73
|
+
expect(proxy.map(&id)).to eq([0,1,2,4,5,6,7,8,9])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#push" do
|
79
|
+
context "after pushing another element into the enumeration" do
|
80
|
+
before do
|
81
|
+
proxy.push(new_value)
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:new_value) { double(:new_value) }
|
85
|
+
|
86
|
+
it "does not alter the other elements" do
|
87
|
+
expect(proxy.map(&id)[0..-2]).to eq([0,1,2,3,4,5,6,7,8,9])
|
88
|
+
end
|
89
|
+
|
90
|
+
it "appends the element to the enumeration" do
|
91
|
+
expect(proxy.map(&id).last).to eq(new_value)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "sequel_mapper/belongs_to_association_proxy"
|
4
|
+
|
5
|
+
RSpec.describe BelongsToAssociationProxy do
|
6
|
+
subject(:proxy) { BelongsToAssociationProxy.new(object_loader) }
|
7
|
+
|
8
|
+
let(:object_loader) { double(:object_loader, call: proxied_object) }
|
9
|
+
let(:proxied_object) { double(:proxied_object, name: name) }
|
10
|
+
let(:name) { double(:name) }
|
11
|
+
|
12
|
+
describe "#__getobj__" do
|
13
|
+
it "loads the object" do
|
14
|
+
proxy.__getobj__
|
15
|
+
|
16
|
+
expect(object_loader).to have_received(:call)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns the proxied object" do
|
20
|
+
expect(proxy.__getobj__).to be(proxied_object)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when no method is called on it" do
|
25
|
+
it "does not call the loader" do
|
26
|
+
proxy
|
27
|
+
|
28
|
+
expect(object_loader).not_to have_received(:call)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when a missing method is called on the proxy" do
|
33
|
+
it "is a true decorator" do
|
34
|
+
expect(proxied_object).to receive(:arbitrary_message)
|
35
|
+
|
36
|
+
proxy.arbitrary_message
|
37
|
+
end
|
38
|
+
|
39
|
+
it "loads the object" do
|
40
|
+
proxy.name
|
41
|
+
|
42
|
+
expect(object_loader).to have_received(:call)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns delegates the message to the object" do
|
46
|
+
args = [ double, double ]
|
47
|
+
proxy.name(*args)
|
48
|
+
|
49
|
+
expect(proxied_object).to have_received(:name).with(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "returns the objects return value" do
|
53
|
+
expect(proxy.name).to eq(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when calling a method twice" do
|
57
|
+
it "loads the object once" do
|
58
|
+
proxy.name
|
59
|
+
proxy.name
|
60
|
+
|
61
|
+
expect(object_loader).to have_received(:call)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "sequel"
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
`psql postgres --command "CREATE DATABASE $PGDATABASE;"`
|
6
|
+
|
7
|
+
DB = Sequel.postgres(
|
8
|
+
host: ENV.fetch("PGHOST"),
|
9
|
+
user: ENV.fetch("PGUSER"),
|
10
|
+
database: ENV.fetch("PGDATABASE"),
|
11
|
+
)
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.expect_with :rspec do |expectations|
|
15
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
16
|
+
end
|
17
|
+
|
18
|
+
config.mock_with :rspec do |mocks|
|
19
|
+
mocks.verify_partial_doubles = true
|
20
|
+
end
|
21
|
+
|
22
|
+
config.filter_run :focus
|
23
|
+
config.run_all_when_everything_filtered = true
|
24
|
+
|
25
|
+
config.disable_monkey_patching!
|
26
|
+
|
27
|
+
# TODO: get everything running without warnings
|
28
|
+
config.warnings = false
|
29
|
+
|
30
|
+
if config.files_to_run.one?
|
31
|
+
config.default_formatter = 'doc'
|
32
|
+
end
|
33
|
+
|
34
|
+
# config.profile_examples = 10
|
35
|
+
|
36
|
+
# config.order = :random
|
37
|
+
|
38
|
+
# Kernel.srand config.seed
|
39
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
require "support/mock_sequel"
|
2
|
+
require "sequel_mapper/struct_factory"
|
3
|
+
require "support/query_counter"
|
4
|
+
|
5
|
+
module SequelMapper
|
6
|
+
module GraphFixture
|
7
|
+
|
8
|
+
# A little hack so these let blocks from an RSpec example don't have
|
9
|
+
# to change
|
10
|
+
def self.let(name, &block)
|
11
|
+
define_method(name) {
|
12
|
+
instance_variable_get("@#{name}") or
|
13
|
+
instance_variable_set("@#{name}", instance_eval(&block))
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
User = Struct.new(:id, :first_name, :last_name, :email, :posts, :toots)
|
18
|
+
Post = Struct.new(:id, :author, :subject, :body, :comments, :categories)
|
19
|
+
Comment = Struct.new(:id, :post, :commenter, :body)
|
20
|
+
Category = Struct.new(:id, :name, :posts)
|
21
|
+
Toot = Struct.new(:id, :tooter, :body, :tooted_at)
|
22
|
+
|
23
|
+
let(:query_counter) {
|
24
|
+
QueryCounter.new
|
25
|
+
}
|
26
|
+
|
27
|
+
let(:datastore) {
|
28
|
+
DB.tap { |db|
|
29
|
+
load_fixture_data(db)
|
30
|
+
db.loggers << query_counter
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
def load_fixture_data(datastore)
|
35
|
+
tables.each do |table, rows|
|
36
|
+
|
37
|
+
datastore.drop_table?(table)
|
38
|
+
|
39
|
+
datastore.create_table(table) do
|
40
|
+
rows.first.keys.each do |column|
|
41
|
+
String column
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
rows.each do |row|
|
46
|
+
datastore[table].insert(row)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:tables) {
|
52
|
+
{
|
53
|
+
users: [
|
54
|
+
user_1_data,
|
55
|
+
user_2_data,
|
56
|
+
user_3_data,
|
57
|
+
],
|
58
|
+
posts: [
|
59
|
+
post_1_data,
|
60
|
+
post_2_data,
|
61
|
+
],
|
62
|
+
comments: [
|
63
|
+
comment_1_data,
|
64
|
+
comment_2_data,
|
65
|
+
],
|
66
|
+
categories: [
|
67
|
+
category_1_data,
|
68
|
+
category_2_data,
|
69
|
+
],
|
70
|
+
categories_to_posts: [
|
71
|
+
{
|
72
|
+
post_id: post_1_data.fetch(:id),
|
73
|
+
category_id: category_1_data.fetch(:id),
|
74
|
+
},
|
75
|
+
{
|
76
|
+
post_id: post_1_data.fetch(:id),
|
77
|
+
category_id: category_2_data.fetch(:id),
|
78
|
+
},
|
79
|
+
{
|
80
|
+
post_id: post_2_data.fetch(:id),
|
81
|
+
category_id: category_2_data.fetch(:id),
|
82
|
+
},
|
83
|
+
],
|
84
|
+
toots: [
|
85
|
+
# Toot ordering is inconsistent for scope testing.
|
86
|
+
toot_2_data,
|
87
|
+
toot_1_data,
|
88
|
+
toot_3_data,
|
89
|
+
],
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
let(:relation_mappings) {
|
94
|
+
{
|
95
|
+
users: {
|
96
|
+
columns: [
|
97
|
+
:id,
|
98
|
+
:first_name,
|
99
|
+
:last_name,
|
100
|
+
:email,
|
101
|
+
],
|
102
|
+
factory: user_factory,
|
103
|
+
has_many: {
|
104
|
+
posts: {
|
105
|
+
relation_name: :posts,
|
106
|
+
foreign_key: :author_id,
|
107
|
+
},
|
108
|
+
toots: {
|
109
|
+
relation_name: :toots,
|
110
|
+
foreign_key: :tooter_id,
|
111
|
+
order_by: {
|
112
|
+
columns: [:tooted_at],
|
113
|
+
direction: :desc,
|
114
|
+
},
|
115
|
+
},
|
116
|
+
},
|
117
|
+
# TODO: maybe combine associations like this
|
118
|
+
# has_many_through: {
|
119
|
+
# categories_posted_in: {
|
120
|
+
# through_association: [ :posts, :categories ]
|
121
|
+
# }
|
122
|
+
# }
|
123
|
+
},
|
124
|
+
posts: {
|
125
|
+
columns: [
|
126
|
+
:id,
|
127
|
+
:author_id,
|
128
|
+
:subject,
|
129
|
+
:body,
|
130
|
+
],
|
131
|
+
factory: post_factory,
|
132
|
+
has_many: {
|
133
|
+
comments: {
|
134
|
+
relation_name: :comments,
|
135
|
+
foreign_key: :post_id,
|
136
|
+
},
|
137
|
+
},
|
138
|
+
has_many_through: {
|
139
|
+
categories: {
|
140
|
+
through_relation_name: :categories_to_posts,
|
141
|
+
relation_name: :categories,
|
142
|
+
foreign_key: :post_id,
|
143
|
+
association_foreign_key: :category_id,
|
144
|
+
}
|
145
|
+
},
|
146
|
+
belongs_to: {
|
147
|
+
author: {
|
148
|
+
relation_name: :users,
|
149
|
+
foreign_key: :author_id,
|
150
|
+
},
|
151
|
+
},
|
152
|
+
},
|
153
|
+
comments: {
|
154
|
+
columns: [
|
155
|
+
:id,
|
156
|
+
:post_id,
|
157
|
+
:commenter_id,
|
158
|
+
:body,
|
159
|
+
],
|
160
|
+
factory: comment_factory,
|
161
|
+
belongs_to: {
|
162
|
+
commenter: {
|
163
|
+
relation_name: :users,
|
164
|
+
foreign_key: :commenter_id,
|
165
|
+
},
|
166
|
+
},
|
167
|
+
},
|
168
|
+
categories: {
|
169
|
+
columns: [
|
170
|
+
:id,
|
171
|
+
:name,
|
172
|
+
],
|
173
|
+
factory: category_factory,
|
174
|
+
has_many_through: {
|
175
|
+
posts: {
|
176
|
+
through_relation_name: :categories_to_posts,
|
177
|
+
relation_name: :posts,
|
178
|
+
foreign_key: :category_id,
|
179
|
+
association_foreign_key: :post_id,
|
180
|
+
}
|
181
|
+
},
|
182
|
+
},
|
183
|
+
toots: {
|
184
|
+
columns: [
|
185
|
+
:id,
|
186
|
+
:tooter_id,
|
187
|
+
:body,
|
188
|
+
:tooted_at,
|
189
|
+
],
|
190
|
+
factory: toot_factory,
|
191
|
+
belongs_to: {
|
192
|
+
tooter: {
|
193
|
+
relation_name: :users,
|
194
|
+
foreign_key: :tooter_id,
|
195
|
+
},
|
196
|
+
},
|
197
|
+
},
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
let(:user_factory){
|
202
|
+
SequelMapper::StructFactory.new(User)
|
203
|
+
}
|
204
|
+
|
205
|
+
let(:post_factory){
|
206
|
+
SequelMapper::StructFactory.new(Post)
|
207
|
+
}
|
208
|
+
|
209
|
+
let(:comment_factory){
|
210
|
+
SequelMapper::StructFactory.new(Comment)
|
211
|
+
}
|
212
|
+
|
213
|
+
let(:category_factory){
|
214
|
+
SequelMapper::StructFactory.new(Category)
|
215
|
+
}
|
216
|
+
|
217
|
+
let(:toot_factory){
|
218
|
+
SequelMapper::StructFactory.new(Toot)
|
219
|
+
}
|
220
|
+
|
221
|
+
let(:user_1_data) {
|
222
|
+
{
|
223
|
+
id: "user/1",
|
224
|
+
first_name: "Stephen",
|
225
|
+
last_name: "Best",
|
226
|
+
email: "bestie@gmail.com",
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
let(:user_2_data) {
|
231
|
+
{
|
232
|
+
id: "user/2",
|
233
|
+
first_name: "Hansel",
|
234
|
+
last_name: "Trickett",
|
235
|
+
email: "hansel@gmail.com",
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
let(:user_3_data) {
|
240
|
+
{
|
241
|
+
id: "user/3",
|
242
|
+
first_name: "Jasper",
|
243
|
+
last_name: "Trickett",
|
244
|
+
email: "jasper@gmail.com",
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
let(:post_1_data) {
|
249
|
+
{
|
250
|
+
id: "post/1",
|
251
|
+
author_id: "user/1",
|
252
|
+
subject: "Object mapping",
|
253
|
+
body: "It is often tricky",
|
254
|
+
}
|
255
|
+
}
|
256
|
+
|
257
|
+
let(:post_2_data) {
|
258
|
+
{
|
259
|
+
id: "post/2",
|
260
|
+
author_id: "user/1",
|
261
|
+
subject: "Object mapping part 2",
|
262
|
+
body: "Lazy load all the things!",
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
let(:comment_1_data) {
|
267
|
+
{
|
268
|
+
id: "comment/1",
|
269
|
+
post_id: "post/1",
|
270
|
+
commenter_id: "user/2",
|
271
|
+
body: "Trololol",
|
272
|
+
}
|
273
|
+
}
|
274
|
+
|
275
|
+
let(:comment_2_data) {
|
276
|
+
{
|
277
|
+
id: "comment/2",
|
278
|
+
post_id: "post/1",
|
279
|
+
commenter_id: "user/1",
|
280
|
+
body: "You are so LOL",
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
let(:category_1_data) {
|
285
|
+
{
|
286
|
+
id: "category/1",
|
287
|
+
name: "good",
|
288
|
+
}
|
289
|
+
}
|
290
|
+
|
291
|
+
let(:category_2_data) {
|
292
|
+
{
|
293
|
+
id: "category/2",
|
294
|
+
name: "bad",
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
let(:category_3_data) {
|
299
|
+
{
|
300
|
+
id: "category/3",
|
301
|
+
name: "ugly",
|
302
|
+
}
|
303
|
+
}
|
304
|
+
|
305
|
+
let(:toot_1_data) {
|
306
|
+
{
|
307
|
+
id: "toot/1",
|
308
|
+
tooter_id: "user/1",
|
309
|
+
body: "Armistice toots",
|
310
|
+
tooted_at: Time.parse("2014-11-11 11:11:00 UTC").iso8601,
|
311
|
+
}
|
312
|
+
}
|
313
|
+
let(:toot_2_data) {
|
314
|
+
{
|
315
|
+
id: "toot/2",
|
316
|
+
tooter_id: "user/1",
|
317
|
+
body: "Tooting every second",
|
318
|
+
tooted_at: Time.parse("2014-11-11 11:11:01 UTC").iso8601,
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
let(:toot_3_data) {
|
323
|
+
{
|
324
|
+
id: "toot/3",
|
325
|
+
tooter_id: "user/1",
|
326
|
+
body: "Join me in a minutes' toots",
|
327
|
+
tooted_at: Time.parse("2014-11-11 11:11:02 UTC").iso8601,
|
328
|
+
}
|
329
|
+
}
|
330
|
+
end
|
331
|
+
end
|