datasource 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/datasource/adapters/active_record.rb +34 -23
- data/lib/datasource/adapters/sequel.rb +42 -33
- data/lib/datasource/base.rb +10 -8
- data/lib/datasource/consumer_adapters/active_model_serializers.rb +24 -15
- data/lib/datasource.rb +29 -8
- data/lib/generators/datasource/templates/initializer.rb +1 -11
- metadata +60 -17
- data/test/active_record_helper.rb +0 -23
- data/test/schema.rb +0 -19
- data/test/test_helper.rb +0 -14
- data/test/test_loader.rb +0 -79
- data/test/test_scope.rb +0 -50
- data/test/test_serializer.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a9fb1c2535e9067063259742826afd3e588a6ed
|
4
|
+
data.tar.gz: a99f6cf865ea1075a2e26165c58c03483e45e93c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b5a9a5c5a9b4af51e1115a152a58b1b2187ffcf4adaa912e9921824d3fbbf96c12b21df77461347ca0569eb6943542bea1dc50b7bbfa0cc57f583a5017c431d
|
7
|
+
data.tar.gz: 5742b0fe11b8bd4a61accb93ca762b4c42cdd4a95cc7044d76b1d7ee124ccc9df9ed3911b36ac8861ac57343c1757557eaa7ddc3ce03af036287e3c578ce58f8
|
@@ -20,18 +20,20 @@ module Datasource
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
private
|
24
|
+
def exec_queries
|
24
25
|
if @datasource
|
25
26
|
datasource = @datasource.new(self)
|
26
27
|
datasource.select(*Array(@datasource_select))
|
27
28
|
if @datasource_serializer
|
28
29
|
select = []
|
29
|
-
Datasource::Base.consumer_adapter.to_datasource_select(select, @datasource.orm_klass, @datasource_serializer)
|
30
|
+
Datasource::Base.consumer_adapter.to_datasource_select(select, @datasource.orm_klass, @datasource_serializer, nil, datasource.adapter)
|
30
31
|
|
31
32
|
datasource.select(*select)
|
32
33
|
end
|
33
34
|
|
34
|
-
|
35
|
+
@loaded = true
|
36
|
+
@records = datasource.results
|
35
37
|
else
|
36
38
|
super
|
37
39
|
end
|
@@ -74,7 +76,8 @@ module Datasource
|
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
77
|
-
|
79
|
+
module_function
|
80
|
+
def association_reflection(klass, name)
|
78
81
|
if reflection = klass.reflections[name]
|
79
82
|
{
|
80
83
|
klass: reflection.klass,
|
@@ -84,19 +87,23 @@ module Datasource
|
|
84
87
|
end
|
85
88
|
end
|
86
89
|
|
87
|
-
def
|
90
|
+
def get_table_name(klass)
|
88
91
|
klass.table_name.to_sym
|
89
92
|
end
|
90
93
|
|
91
|
-
def
|
94
|
+
def is_scope?(obj)
|
92
95
|
obj.kind_of?(::ActiveRecord::Relation)
|
93
96
|
end
|
94
97
|
|
95
|
-
def
|
98
|
+
def scope_to_class(scope)
|
96
99
|
scope.klass
|
97
100
|
end
|
98
101
|
|
99
|
-
def
|
102
|
+
def scope_loaded?(scope)
|
103
|
+
scope.loaded?
|
104
|
+
end
|
105
|
+
|
106
|
+
def association_klass(reflection)
|
100
107
|
if reflection.macro == :belongs_to && reflection.options[:polymorphic]
|
101
108
|
fail Datasource::Error, "polymorphic belongs_to not supported, write custom loader"
|
102
109
|
else
|
@@ -104,7 +111,7 @@ module Datasource
|
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
107
|
-
def
|
114
|
+
def preload_association(records, name)
|
108
115
|
return if records.empty?
|
109
116
|
return if records.first.association(name.to_sym).loaded?
|
110
117
|
klass = records.first.class
|
@@ -144,43 +151,43 @@ module Datasource
|
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
|
-
def to_query
|
154
|
+
def to_query(ds)
|
148
155
|
::ActiveRecord::Base.uncached do
|
149
|
-
|
156
|
+
ds.scope.select(*ds.get_select_values).to_sql
|
150
157
|
end
|
151
158
|
end
|
152
159
|
|
153
|
-
def select_scope
|
154
|
-
|
160
|
+
def select_scope(ds)
|
161
|
+
ds.scope.select(*ds.get_select_values)
|
155
162
|
end
|
156
163
|
|
157
|
-
def get_rows
|
164
|
+
def get_rows(ds)
|
158
165
|
append_select = []
|
159
|
-
|
160
|
-
if reflection = Adapters::ActiveRecord.association_reflection(
|
166
|
+
ds.expose_associations.each_pair do |assoc_name, assoc_select|
|
167
|
+
if reflection = Adapters::ActiveRecord.association_reflection(ds.class.orm_klass, assoc_name.to_sym)
|
161
168
|
Datasource::Base.reflection_select(reflection, append_select, [])
|
162
169
|
end
|
163
170
|
end
|
164
|
-
select(*append_select)
|
171
|
+
ds.select(*append_select)
|
165
172
|
|
166
|
-
scope = select_scope
|
173
|
+
scope = select_scope(ds)
|
167
174
|
if scope.respond_to?(:use_datasource)
|
168
175
|
scope = scope.spawn.use_datasource(nil)
|
169
176
|
end
|
170
177
|
scope.includes_values = []
|
171
178
|
scope.to_a.tap do |records|
|
172
|
-
|
179
|
+
ds.expose_associations.each_pair do |assoc_name, assoc_select|
|
173
180
|
Adapters::ActiveRecord.preload_association(records, assoc_name)
|
174
181
|
end
|
175
182
|
end
|
176
183
|
end
|
177
184
|
|
178
|
-
def primary_scope_table(
|
179
|
-
scope.klass.table_name
|
185
|
+
def primary_scope_table(ds)
|
186
|
+
ds.scope.klass.table_name
|
180
187
|
end
|
181
188
|
|
182
|
-
def ensure_table_join!(name, att)
|
183
|
-
join_value =
|
189
|
+
def ensure_table_join!(ds, name, att)
|
190
|
+
join_value = ds.scope.joins_values.find do |value|
|
184
191
|
if value.is_a?(Symbol)
|
185
192
|
value.to_s == att[:name]
|
186
193
|
elsif value.is_a?(String)
|
@@ -203,6 +210,10 @@ module Datasource
|
|
203
210
|
klass
|
204
211
|
end
|
205
212
|
|
213
|
+
define_singleton_method(:default_adapter) do
|
214
|
+
Datasource::Adapters::ActiveRecord
|
215
|
+
end
|
216
|
+
|
206
217
|
define_method(:primary_key) do
|
207
218
|
klass.primary_key.to_sym
|
208
219
|
end
|
@@ -25,7 +25,7 @@ module Datasource
|
|
25
25
|
datasource.select(*Array(@datasource_select))
|
26
26
|
if @datasource_serializer
|
27
27
|
select = []
|
28
|
-
Datasource::Base.consumer_adapter.to_datasource_select(select, @datasource.orm_klass, @datasource_serializer)
|
28
|
+
Datasource::Base.consumer_adapter.to_datasource_select(select, @datasource.orm_klass, @datasource_serializer, nil, datasource.adapter)
|
29
29
|
|
30
30
|
datasource.select(*select)
|
31
31
|
end
|
@@ -75,7 +75,8 @@ module Datasource
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
|
78
|
+
module_function
|
79
|
+
def association_reflection(klass, name)
|
79
80
|
reflection = klass.association_reflections[name]
|
80
81
|
|
81
82
|
macro = case reflection[:type]
|
@@ -92,15 +93,15 @@ module Datasource
|
|
92
93
|
}
|
93
94
|
end
|
94
95
|
|
95
|
-
def
|
96
|
+
def get_table_name(klass)
|
96
97
|
klass.table_name
|
97
98
|
end
|
98
99
|
|
99
|
-
def
|
100
|
+
def is_scope?(obj)
|
100
101
|
obj.kind_of?(::Sequel::Dataset)
|
101
102
|
end
|
102
103
|
|
103
|
-
def
|
104
|
+
def scope_to_class(scope)
|
104
105
|
if scope.row_proc && scope.row_proc.ancestors.include?(::Sequel::Model)
|
105
106
|
scope.row_proc
|
106
107
|
else
|
@@ -108,29 +109,8 @@ module Datasource
|
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
|
-
def
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
def select_scope
|
116
|
-
@scope.select(*get_sequel_select_values)
|
117
|
-
end
|
118
|
-
|
119
|
-
def get_rows
|
120
|
-
eager = {}
|
121
|
-
append_select = []
|
122
|
-
@expose_associations.each_pair do |assoc_name, assoc_select|
|
123
|
-
eager.merge!(
|
124
|
-
get_assoc_eager_options(self.class.orm_klass, assoc_name.to_sym, assoc_select, append_select))
|
125
|
-
end
|
126
|
-
# TODO: remove/disable datasource on scope if present
|
127
|
-
scope = select_scope
|
128
|
-
if scope.respond_to?(:use_datasource)
|
129
|
-
scope = scope.clone.use_datasource(nil)
|
130
|
-
end
|
131
|
-
scope
|
132
|
-
.select_append(*get_sequel_select_values(append_select.map { |v| primary_scope_table(@scope) + ".#{v}" }))
|
133
|
-
.eager(eager).all
|
112
|
+
def scope_loaded?(scope)
|
113
|
+
false
|
134
114
|
end
|
135
115
|
|
136
116
|
def get_assoc_eager_options(klass, name, assoc_select, append_select)
|
@@ -153,15 +133,40 @@ module Datasource
|
|
153
133
|
end
|
154
134
|
|
155
135
|
def get_sequel_select_values(values = nil)
|
156
|
-
|
136
|
+
values.map { |str| ::Sequel.lit(str) }
|
137
|
+
end
|
138
|
+
|
139
|
+
def to_query(ds)
|
140
|
+
ds.scope.sql
|
157
141
|
end
|
158
142
|
|
159
|
-
def
|
160
|
-
scope.
|
143
|
+
def select_scope(ds)
|
144
|
+
ds.scope.select(*get_sequel_select_values(ds.get_select_values))
|
161
145
|
end
|
162
146
|
|
163
|
-
def
|
164
|
-
|
147
|
+
def get_rows(ds)
|
148
|
+
eager = {}
|
149
|
+
append_select = []
|
150
|
+
ds.expose_associations.each_pair do |assoc_name, assoc_select|
|
151
|
+
eager.merge!(
|
152
|
+
get_assoc_eager_options(ds.class.orm_klass, assoc_name.to_sym, assoc_select, append_select))
|
153
|
+
end
|
154
|
+
# TODO: remove/disable datasource on scope if present
|
155
|
+
scope = select_scope(ds)
|
156
|
+
if scope.respond_to?(:use_datasource)
|
157
|
+
scope = scope.clone.use_datasource(nil)
|
158
|
+
end
|
159
|
+
scope
|
160
|
+
.select_append(*get_sequel_select_values(append_select.map { |v| primary_scope_table(ds) + ".#{v}" }))
|
161
|
+
.eager(eager).all
|
162
|
+
end
|
163
|
+
|
164
|
+
def primary_scope_table(ds)
|
165
|
+
ds.scope.first_source_alias.to_s
|
166
|
+
end
|
167
|
+
|
168
|
+
def ensure_table_join!(ds, name, att)
|
169
|
+
join_value = Hash(ds.scope.opts[:join]).find do |value|
|
165
170
|
(value.table_alias || value.table).to_s == att[:name]
|
166
171
|
end
|
167
172
|
fail Datasource::Error, "given scope does not join on #{name}, but it is required by #{att[:name]}" unless join_value
|
@@ -178,6 +183,10 @@ module Datasource
|
|
178
183
|
klass
|
179
184
|
end
|
180
185
|
|
186
|
+
define_singleton_method(:default_adapter) do
|
187
|
+
Datasource::Adapters::Sequel
|
188
|
+
end
|
189
|
+
|
181
190
|
define_method(:primary_key) do
|
182
191
|
klass.primary_key
|
183
192
|
end
|
data/lib/datasource/base.rb
CHANGED
@@ -8,10 +8,9 @@ module Datasource
|
|
8
8
|
base._attributes = (_attributes || {}).dup
|
9
9
|
base._associations = (_associations || {}).dup
|
10
10
|
base._loaders = (_loaders || {}).dup
|
11
|
-
self.send :include, adapter
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
13
|
+
def default_adapter
|
15
14
|
@adapter ||= begin
|
16
15
|
Datasource::Adapters.const_get(Datasource::Adapters.constants.first)
|
17
16
|
end
|
@@ -68,7 +67,10 @@ module Datasource
|
|
68
67
|
end
|
69
68
|
end
|
70
69
|
|
71
|
-
|
70
|
+
attr_reader :scope, :expose_attributes, :expose_associations, :adapter
|
71
|
+
|
72
|
+
def initialize(scope, adapter = nil)
|
73
|
+
@adapter = adapter || self.class.default_adapter
|
72
74
|
@scope =
|
73
75
|
if self.class._update_scope
|
74
76
|
self.class._update_scope.call(scope)
|
@@ -115,7 +117,7 @@ module Datasource
|
|
115
117
|
end
|
116
118
|
|
117
119
|
def get_select_values
|
118
|
-
scope_table = primary_scope_table(
|
120
|
+
scope_table = adapter.primary_scope_table(self)
|
119
121
|
select_values = Set.new
|
120
122
|
select_values.add("#{scope_table}.#{primary_key}")
|
121
123
|
|
@@ -127,7 +129,7 @@ module Datasource
|
|
127
129
|
att[:klass]._depends.keys.map(&:to_s).each do |name|
|
128
130
|
next if name == scope_table
|
129
131
|
next if name == "loaders"
|
130
|
-
ensure_table_join!(name, att)
|
132
|
+
adapter.ensure_table_join!(self, name, att)
|
131
133
|
end
|
132
134
|
att[:klass]._depends.each_pair do |table, names|
|
133
135
|
next if table.to_sym == :loaders
|
@@ -140,7 +142,7 @@ module Datasource
|
|
140
142
|
select_values.add("(#{att[:klass].select_value}) as #{att[:name]}")
|
141
143
|
att[:klass]._depends.each do |name|
|
142
144
|
next if name == scope_table
|
143
|
-
ensure_table_join!(name, att)
|
145
|
+
adapter.ensure_table_join!(self, name, att)
|
144
146
|
end
|
145
147
|
end
|
146
148
|
end
|
@@ -153,11 +155,11 @@ module Datasource
|
|
153
155
|
end
|
154
156
|
|
155
157
|
def results(rows = nil)
|
156
|
-
rows ||= get_rows
|
158
|
+
rows ||= adapter.get_rows(self)
|
157
159
|
|
158
160
|
@expose_attributes.each do |name|
|
159
161
|
att = self.class._attributes[name]
|
160
|
-
fail Datasource::Error, "attribute #{name} doesn't exist for #{self.class.orm_klass.name}, did you forget to call \"computed :#{name},
|
162
|
+
fail Datasource::Error, "attribute #{name} doesn't exist for #{self.class.orm_klass.name}, did you forget to call \"computed :#{name}, :db_column_dependency\" in your datasource_module? See https://github.com/mrbrdo/datasource#model-methods--virtual-attributes" unless att
|
161
163
|
klass = att[:klass]
|
162
164
|
next unless klass
|
163
165
|
|
@@ -3,25 +3,20 @@ require "active_model/serializer"
|
|
3
3
|
module Datasource
|
4
4
|
module ConsumerAdapters
|
5
5
|
module ActiveModelSerializers
|
6
|
-
|
7
|
-
|
8
|
-
else
|
9
|
-
ActiveModel::ArraySerializer
|
10
|
-
end
|
11
|
-
class ArraySerializer < superclass
|
12
|
-
def initialize(objects, options = {})
|
6
|
+
module ArraySerializer
|
7
|
+
def initialize_with_datasource(objects, options = {})
|
13
8
|
datasource_class = options.delete(:datasource)
|
14
|
-
adapter = Datasource
|
15
|
-
if adapter.
|
9
|
+
adapter = Datasource.orm_adapters.find { |a| a.is_scope?(objects) }
|
10
|
+
if adapter && !adapter.scope_loaded?(objects)
|
16
11
|
datasource_class ||= adapter.scope_to_class(objects).default_datasource
|
17
12
|
|
18
13
|
records = objects
|
19
14
|
.with_datasource(datasource_class)
|
20
15
|
.for_serializer(options[:serializer]).all.to_a # all needed for Sequel eager loading
|
21
16
|
|
22
|
-
|
17
|
+
initialize_without_datasource(records, options)
|
23
18
|
else
|
24
|
-
|
19
|
+
initialize_without_datasource(objects, options)
|
25
20
|
end
|
26
21
|
end
|
27
22
|
end
|
@@ -38,7 +33,8 @@ module Datasource
|
|
38
33
|
serializer || "#{klass.name}Serializer".constantize
|
39
34
|
end
|
40
35
|
|
41
|
-
def to_datasource_select(result, klass, serializer = nil, serializer_assoc = nil)
|
36
|
+
def to_datasource_select(result, klass, serializer = nil, serializer_assoc = nil, adapter = nil)
|
37
|
+
adapter ||= Datasource::Base.default_adapter
|
42
38
|
serializer ||= get_serializer_for(klass, serializer_assoc)
|
43
39
|
result.concat(serializer._attributes)
|
44
40
|
result_assocs = {}
|
@@ -46,12 +42,12 @@ module Datasource
|
|
46
42
|
|
47
43
|
serializer._associations.each_pair do |name, serializer_assoc|
|
48
44
|
# TODO: what if assoc is renamed in serializer?
|
49
|
-
reflection =
|
45
|
+
reflection = adapter.association_reflection(klass, name.to_sym)
|
50
46
|
assoc_class = reflection[:klass]
|
51
47
|
|
52
48
|
name = name.to_s
|
53
49
|
result_assocs[name] = []
|
54
|
-
to_datasource_select(result_assocs[name], assoc_class, nil, serializer_assoc)
|
50
|
+
to_datasource_select(result_assocs[name], assoc_class, nil, serializer_assoc, adapter)
|
55
51
|
end
|
56
52
|
rescue Exception => ex
|
57
53
|
if ex.is_a?(SystemStackError) || ex.is_a?(Datasource::RecursionError)
|
@@ -62,5 +58,18 @@ module Datasource
|
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
65
|
-
|
61
|
+
end
|
62
|
+
|
63
|
+
array_serializer_class = if defined?(ActiveModel::Serializer::ArraySerializer)
|
64
|
+
ActiveModel::Serializer::ArraySerializer
|
65
|
+
else
|
66
|
+
ActiveModel::ArraySerializer
|
67
|
+
end
|
68
|
+
|
69
|
+
array_serializer_class.class_exec do
|
70
|
+
alias_method :initialize_without_datasource, :initialize
|
71
|
+
include Datasource::ConsumerAdapters::ActiveModelSerializers::ArraySerializer
|
72
|
+
def initialize(*args)
|
73
|
+
initialize_with_datasource(*args)
|
74
|
+
end
|
66
75
|
end
|
data/lib/datasource.rb
CHANGED
@@ -2,18 +2,39 @@ module Datasource
|
|
2
2
|
Error = Class.new(StandardError)
|
3
3
|
RecursionError = Class.new(StandardError)
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
AdapterPaths = {
|
6
|
+
activerecord: 'datasource/adapters/active_record',
|
7
|
+
active_record: :activerecord,
|
8
|
+
sequel: 'datasource/adapters/sequel',
|
9
|
+
ams: 'datasource/consumer_adapters/active_model_serializers',
|
10
|
+
active_model_serializers: :ams
|
11
|
+
}
|
12
|
+
|
13
|
+
module_function
|
14
|
+
def load(*adapters)
|
15
|
+
if adapters.empty?
|
16
|
+
adapters = []
|
17
|
+
if defined? ActiveRecord
|
18
|
+
adapters.push(:activerecord)
|
9
19
|
elsif defined? Sequel
|
10
|
-
:sequel
|
20
|
+
adapters.push(:sequel)
|
21
|
+
end
|
22
|
+
if defined? ActiveModel::Serializer
|
23
|
+
adapters.push(:ams)
|
11
24
|
end
|
12
25
|
end
|
13
26
|
|
14
|
-
|
15
|
-
|
16
|
-
|
27
|
+
adapters.each do |adapter|
|
28
|
+
adapter = AdapterPaths[adapter]
|
29
|
+
adapter = AdapterPaths[adapter] if adapter.is_a?(Symbol)
|
30
|
+
require adapter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def orm_adapters
|
35
|
+
@orm_adapters ||= begin
|
36
|
+
Datasource::Adapters.constants.map { |name| Datasource::Adapters.const_get(name) }
|
37
|
+
end
|
17
38
|
end
|
18
39
|
end
|
19
40
|
|
@@ -1,11 +1 @@
|
|
1
|
-
Datasource.load(:activerecord)
|
2
|
-
|
3
|
-
if defined? ActiveModel::Serializer
|
4
|
-
if ActiveModel::Serializer.respond_to?(:config)
|
5
|
-
ActiveModel::Serializer.config.array_serializer = Datasource::ArrayAMS
|
6
|
-
else
|
7
|
-
ActiveModel::Serializer.setup do |config|
|
8
|
-
config.array_serializer = Datasource::ArrayAMS
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
1
|
+
Datasource.load(:activerecord, :active_model_serializers)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datasource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Berdajs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_model_serializers
|
@@ -24,6 +24,34 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.9'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: activerecord
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +94,34 @@ dependencies:
|
|
66
94
|
- - "~>"
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sequel
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '4.17'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '4.17'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: database_cleaner
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.3'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.3'
|
69
125
|
description:
|
70
126
|
email:
|
71
127
|
- mrbrdo@gmail.com
|
@@ -87,12 +143,6 @@ files:
|
|
87
143
|
- lib/datasource/serializer.rb
|
88
144
|
- lib/generators/datasource/install_generator.rb
|
89
145
|
- lib/generators/datasource/templates/initializer.rb
|
90
|
-
- test/active_record_helper.rb
|
91
|
-
- test/schema.rb
|
92
|
-
- test/test_helper.rb
|
93
|
-
- test/test_loader.rb
|
94
|
-
- test/test_scope.rb
|
95
|
-
- test/test_serializer.rb
|
96
146
|
homepage: https://github.com/mrbrdo/datasource
|
97
147
|
licenses:
|
98
148
|
- MIT
|
@@ -116,12 +166,5 @@ rubyforge_project:
|
|
116
166
|
rubygems_version: 2.2.2
|
117
167
|
signing_key:
|
118
168
|
specification_version: 4
|
119
|
-
summary: Ruby library
|
120
|
-
test_files:
|
121
|
-
- test/active_record_helper.rb
|
122
|
-
- test/schema.rb
|
123
|
-
- test/test_helper.rb
|
124
|
-
- test/test_loader.rb
|
125
|
-
- test/test_scope.rb
|
126
|
-
- test/test_serializer.rb
|
127
|
-
has_rdoc:
|
169
|
+
summary: Ruby library to automatically preload records for your serializers
|
170
|
+
test_files: []
|
@@ -1,23 +0,0 @@
|
|
1
|
-
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
2
|
-
ActiveRecord::Migration.verbose = false
|
3
|
-
load "schema.rb"
|
4
|
-
|
5
|
-
def clean_db
|
6
|
-
ActiveRecord::Base.connection.execute("DELETE FROM comments")
|
7
|
-
ActiveRecord::Base.connection.execute("DELETE FROM posts")
|
8
|
-
ActiveRecord::Base.connection.execute("DELETE FROM blogs")
|
9
|
-
ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence")
|
10
|
-
end
|
11
|
-
|
12
|
-
def assert_query_count(count)
|
13
|
-
old_logger = ActiveRecord::Base.logger
|
14
|
-
logger = StringIO.new
|
15
|
-
ActiveRecord::Base.logger = Logger.new(logger)
|
16
|
-
begin
|
17
|
-
yield
|
18
|
-
ensure
|
19
|
-
ActiveRecord::Base.logger = old_logger
|
20
|
-
# puts logger.string
|
21
|
-
end
|
22
|
-
assert_equal count, logger.string.lines.count
|
23
|
-
end
|
data/test/schema.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
ActiveRecord::Schema.define(:version => 0) do
|
2
|
-
create_table :blogs, :force => true do |t|
|
3
|
-
t.string :title
|
4
|
-
end
|
5
|
-
|
6
|
-
create_table :posts, :force => true do |t|
|
7
|
-
t.integer :blog_id
|
8
|
-
t.string :title
|
9
|
-
t.string :author_first_name
|
10
|
-
t.string :author_last_name
|
11
|
-
end
|
12
|
-
|
13
|
-
create_table :comments, :force => true do |t|
|
14
|
-
t.integer :post_id
|
15
|
-
t.text :comment
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
ActiveRecord::Base.send :include, Datasource::Adapters::ActiveRecord::Model
|
data/test/test_helper.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# Configure Rails Environment
|
2
|
-
ENV["RAILS_ENV"] = "test"
|
3
|
-
|
4
|
-
require 'minitest/autorun'
|
5
|
-
require 'active_support/all'
|
6
|
-
require 'active_record'
|
7
|
-
require 'datasource'
|
8
|
-
require 'active_model_serializers'
|
9
|
-
require 'pry'
|
10
|
-
|
11
|
-
Datasource.load(:activerecord)
|
12
|
-
|
13
|
-
# Load support files
|
14
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
data/test/test_loader.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'active_record_helper'
|
3
|
-
|
4
|
-
class LoaderTest < ActiveSupport::TestCase
|
5
|
-
class Comment < ActiveRecord::Base
|
6
|
-
self.table_name = "comments"
|
7
|
-
belongs_to :post
|
8
|
-
end
|
9
|
-
|
10
|
-
class Post < ActiveRecord::Base
|
11
|
-
self.table_name = "posts"
|
12
|
-
has_many :comments
|
13
|
-
|
14
|
-
datasource_module do
|
15
|
-
loader :newest_comment, group_by: :post_id, one: true do |post_ids|
|
16
|
-
Comment.for_serializer.where(post_id: post_ids)
|
17
|
-
.group("post_id")
|
18
|
-
.having("id = MAX(id)")
|
19
|
-
.datasource_select(:post_id)
|
20
|
-
end
|
21
|
-
|
22
|
-
loader :newest_comment_text, array_to_hash: true do |post_ids|
|
23
|
-
Comment.where(post_id: post_ids)
|
24
|
-
.group("post_id")
|
25
|
-
.having("id = MAX(id)")
|
26
|
-
.pluck("post_id, comment")
|
27
|
-
end
|
28
|
-
|
29
|
-
loader :ordered_comments, group_by: :post_id do |post_ids|
|
30
|
-
Comment.for_serializer(CommentSerializer).where(post_id: post_ids)
|
31
|
-
.order("post_id, id desc")
|
32
|
-
.datasource_select(:post_id)
|
33
|
-
end
|
34
|
-
|
35
|
-
computed :newest_comment, loaders: :newest_comment
|
36
|
-
computed :newest_comment_text, loaders: :newest_comment_text
|
37
|
-
computed :ordered_comments, loaders: :ordered_comments
|
38
|
-
end
|
39
|
-
|
40
|
-
def name_initials
|
41
|
-
return unless author_first_name && author_last_name
|
42
|
-
author_first_name[0].upcase + author_last_name[0].upcase
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class CommentSerializer < ActiveModel::Serializer
|
47
|
-
attributes :id, :comment
|
48
|
-
end
|
49
|
-
|
50
|
-
class PostSerializer < ActiveModel::Serializer
|
51
|
-
attributes :id, :title, :newest_comment, :newest_comment_text, :ordered_comments
|
52
|
-
|
53
|
-
def newest_comment
|
54
|
-
CommentSerializer.new(object.loaded_values[:newest_comment]).as_json
|
55
|
-
end
|
56
|
-
|
57
|
-
def newest_comment_text
|
58
|
-
object.loaded_values[:newest_comment_text]
|
59
|
-
end
|
60
|
-
|
61
|
-
def ordered_comments
|
62
|
-
Datasource::ArrayAMS.new(object.loaded_values[:ordered_comments]).as_json
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def test_loader
|
67
|
-
post = Post.create! title: "First Post"
|
68
|
-
2.times { |i| post.comments.create! comment: "Comment #{i+1}" }
|
69
|
-
|
70
|
-
assert_query_count(4) do
|
71
|
-
assert_equal Datasource::ArrayAMS.new(Post.all).as_json,
|
72
|
-
[{:id=>1, :title=>"First Post", :newest_comment=>{"comment"=>{:id=>2, :comment=>"Comment 2"}}, :newest_comment_text=>"Comment 2", :ordered_comments=>[{:id=>2, :comment=>"Comment 2"}, {:id=>1, :comment=>"Comment 1"}]}]
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def teardown
|
77
|
-
clean_db
|
78
|
-
end
|
79
|
-
end
|
data/test/test_scope.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'active_record_helper'
|
3
|
-
|
4
|
-
class ScopeTest < ActiveSupport::TestCase
|
5
|
-
class Post < ActiveRecord::Base
|
6
|
-
belongs_to :blog
|
7
|
-
|
8
|
-
datasource_module do
|
9
|
-
query :author_name do
|
10
|
-
"posts.author_first_name || ' ' || posts.author_last_name"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class PostSerializer < ActiveModel::Serializer
|
16
|
-
attributes :id, :title, :author_name
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_first
|
20
|
-
Post.create! title: "The Post", author_first_name: "John", author_last_name: "Doe", blog_id: 10
|
21
|
-
post = Post.for_serializer.first
|
22
|
-
|
23
|
-
assert_equal("The Post", post.title)
|
24
|
-
assert_equal("John Doe", post.author_name)
|
25
|
-
assert_raises(ActiveModel::MissingAttributeError) { post.blog_id }
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_find
|
29
|
-
post = Post.create! title: "The Post", author_first_name: "John", author_last_name: "Doe", blog_id: 10
|
30
|
-
post = Post.for_serializer.find(post.id)
|
31
|
-
|
32
|
-
assert_equal("The Post", post.title)
|
33
|
-
assert_equal("John Doe", post.author_name)
|
34
|
-
assert_raises(ActiveModel::MissingAttributeError) { post.blog_id }
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_each
|
38
|
-
post = Post.create! title: "The Post", author_first_name: "John", author_last_name: "Doe", blog_id: 10
|
39
|
-
|
40
|
-
Post.for_serializer.each do |post|
|
41
|
-
assert_equal("The Post", post.title)
|
42
|
-
assert_equal("John Doe", post.author_name)
|
43
|
-
assert_raises(ActiveModel::MissingAttributeError) { post.blog_id }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def teardown
|
48
|
-
clean_db
|
49
|
-
end
|
50
|
-
end
|
data/test/test_serializer.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'active_record_helper'
|
3
|
-
|
4
|
-
class SerializerTest < ActiveSupport::TestCase
|
5
|
-
class Post < ActiveRecord::Base
|
6
|
-
belongs_to :blog
|
7
|
-
|
8
|
-
datasource_module do
|
9
|
-
query :author_name do
|
10
|
-
"posts.author_first_name || ' ' || posts.author_last_name"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class Blog < ActiveRecord::Base
|
16
|
-
has_many :posts
|
17
|
-
end
|
18
|
-
|
19
|
-
class BlogSerializer < ActiveModel::Serializer
|
20
|
-
attributes :id, :title
|
21
|
-
|
22
|
-
has_many :posts
|
23
|
-
end
|
24
|
-
|
25
|
-
class PostSerializer < ActiveModel::Serializer
|
26
|
-
attributes :id, :title, :author_name
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_blogs_and_posts_serializer
|
30
|
-
blog = Blog.create! title: "Blog 1"
|
31
|
-
blog.posts.create! title: "Post 1", author_first_name: "John", author_last_name: "Doe"
|
32
|
-
blog.posts.create! title: "Post 2", author_first_name: "Maria", author_last_name: "Doe"
|
33
|
-
blog = Blog.create! title: "Blog 2"
|
34
|
-
|
35
|
-
expected_result = [
|
36
|
-
{:id =>1, :title =>"Blog 1", :posts =>[
|
37
|
-
{:id =>1, :title =>"Post 1", :author_name =>"John Doe"},
|
38
|
-
{:id =>2, :title =>"Post 2", :author_name =>"Maria Doe"}
|
39
|
-
]},
|
40
|
-
{:id =>2, :title =>"Blog 2", :posts =>[]}
|
41
|
-
]
|
42
|
-
|
43
|
-
assert_query_count(2) do
|
44
|
-
serializer = Datasource::ArrayAMS.new(Blog.all)
|
45
|
-
assert_equal(expected_result, serializer.as_json)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def teardown
|
50
|
-
clean_db
|
51
|
-
end
|
52
|
-
end
|