datasource 0.0.2 → 0.0.3
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 +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
|