sunstone 1.1.0 → 1.2.0
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/active_record/connection_adapters/sunstone/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +3 -3
- data/lib/arel/collectors/sunstone.rb +18 -13
- data/lib/arel/visitors/sunstone.rb +22 -17
- data/lib/ext/active_record/finder_methods.rb +96 -0
- data/lib/ext/arel/nodes/eager_load.rb +7 -0
- data/lib/ext/arel/nodes/select_statement.rb +28 -0
- data/lib/ext/arel/select_manager.rb +18 -0
- data/lib/sunstone.rb +6 -1
- data/lib/sunstone/connection.rb +10 -12
- data/sunstone.gemspec +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25d9399ddb2d453dfd16181b8207792c1de527a6
|
4
|
+
data.tar.gz: e675ed6285907dfa641237e6d0e86df12c59ce29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de118716de30e72b4fce3b85c7267883b6daaa3a747a076d9049e64e49ca964edf105347652ecbe0830f96bd915447023cadc67799cc9b1be132215d9a24b37e
|
7
|
+
data.tar.gz: 54cef9aad93186f4e121331fedff26e2bb6226e25770a372343db86074ae05cf6d5ffda127d71ab637292b096466eaf60dde6827f60ac1842fc56ceb65fa6eef
|
@@ -2,7 +2,7 @@ module ActiveRecord
|
|
2
2
|
module ConnectionAdapters
|
3
3
|
module Sunstone
|
4
4
|
module DatabaseStatements
|
5
|
-
|
5
|
+
|
6
6
|
# Converts an arel AST to a Sunstone API Request
|
7
7
|
def to_sar(arel, bvs)
|
8
8
|
if arel.respond_to?(:ast)
|
@@ -12,12 +12,12 @@ module ActiveRecord
|
|
12
12
|
arel
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# Returns an ActiveRecord::Result instance.
|
17
17
|
def select_all(arel, name = nil, binds = [], &block)
|
18
18
|
exec_query(arel, name, binds)
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def exec_query(arel, name = 'SAR', binds = [])
|
22
22
|
result = exec(to_sar(arel, binds), name)
|
23
23
|
|
@@ -135,11 +135,11 @@ module ActiveRecord
|
|
135
135
|
def update_table_definition(table_name, base) #:nodoc:
|
136
136
|
SunstoneAPI::Table.new(table_name, base)
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
def collector
|
140
140
|
Arel::Collectors::Sunstone.new
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
def server_config
|
144
144
|
Wankel.parse(@connection.get("/configuration").body)
|
145
145
|
end
|
@@ -174,4 +174,4 @@ module ActiveRecord
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
end
|
177
|
-
end
|
177
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Arel
|
2
2
|
module Collectors
|
3
3
|
class Sunstone < Arel::Collectors::Bind
|
4
|
-
|
5
|
-
attr_accessor :request_type, :table, :where, :limit, :offset, :order, :operation, :columns, :updates
|
6
|
-
|
4
|
+
|
5
|
+
attr_accessor :request_type, :table, :where, :limit, :offset, :order, :operation, :columns, :updates, :eager_loads
|
6
|
+
|
7
7
|
def substitute_binds hash, bvs
|
8
8
|
if hash.is_a?(Array)
|
9
9
|
hash.map { |w| substitute_binds(w, bvs) }
|
@@ -21,11 +21,11 @@ module Arel
|
|
21
21
|
newhash
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def value
|
26
26
|
flatten_nested(where).flatten
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def flatten_nested(obj)
|
30
30
|
if obj.is_a?(Array)
|
31
31
|
obj.map { |w| flatten_nested(w) }
|
@@ -35,17 +35,17 @@ module Arel
|
|
35
35
|
obj
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def compile bvs, conn = nil
|
40
40
|
path = "/#{table}"
|
41
|
-
|
41
|
+
|
42
42
|
case operation
|
43
43
|
when :count, :average, :min, :max
|
44
44
|
path += "/#{operation}"
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
get_params = {}
|
48
|
-
|
48
|
+
|
49
49
|
if where
|
50
50
|
get_params[:where] = substitute_binds(where.clone, bvs)
|
51
51
|
if get_params[:where].size == 1
|
@@ -53,23 +53,28 @@ module Arel
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
if eager_loads
|
57
|
+
get_params[:include] = eager_loads.clone
|
58
|
+
end
|
59
|
+
|
56
60
|
get_params[:limit] = limit if limit
|
57
61
|
get_params[:offset] = offset if offset
|
58
62
|
get_params[:order] = order if order
|
59
63
|
get_params[:columns] = columns if columns
|
60
|
-
|
64
|
+
|
61
65
|
if get_params.size > 0
|
62
66
|
path += '?' + get_params.to_param
|
63
67
|
end
|
64
|
-
|
68
|
+
|
65
69
|
request = request_type.new(path)
|
70
|
+
|
66
71
|
if updates
|
67
72
|
request.body = {table.singularize => substitute_binds(updates.clone, bvs)}.to_json
|
68
73
|
end
|
69
|
-
|
74
|
+
|
70
75
|
request
|
71
76
|
end
|
72
|
-
|
77
|
+
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
@@ -24,34 +24,40 @@ module Arel
|
|
24
24
|
def compile node, &block
|
25
25
|
accept(node, Arel::Collectors::SQLString.new, &block).value
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
private
|
29
|
-
|
29
|
+
|
30
30
|
def visit_Arel_Nodes_SelectStatement o, collector
|
31
31
|
collector = o.cores.inject(collector) { |c,x|
|
32
32
|
visit_Arel_Nodes_SelectCore(x, c)
|
33
33
|
}
|
34
|
-
|
34
|
+
|
35
35
|
if !o.orders.empty?
|
36
36
|
collector.order = o.orders.map { |x| visit(x, collector) }
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
collector = maybe_visit o.limit, collector
|
40
40
|
collector = maybe_visit o.offset, collector
|
41
|
+
collector = maybe_visit o.eager_load, collector
|
41
42
|
# collector = maybe_visit o.lock, collector
|
42
43
|
|
43
44
|
collector
|
44
45
|
end
|
45
|
-
|
46
|
+
|
47
|
+
def visit_Arel_Nodes_EagerLoad o, collector
|
48
|
+
collector.eager_loads = o.expr
|
49
|
+
collector
|
50
|
+
end
|
51
|
+
|
46
52
|
def visit_Arel_Nodes_SelectCore o, collector
|
47
53
|
collector.request_type = Net::HTTP::Get
|
48
|
-
|
54
|
+
|
49
55
|
unless o.projections.empty?
|
50
56
|
visit(o.projections.first, collector)
|
51
57
|
else
|
52
58
|
collector.operation = :select
|
53
59
|
end
|
54
|
-
|
60
|
+
|
55
61
|
if o.source && !o.source.empty?
|
56
62
|
collector.table = o.source.left.name
|
57
63
|
end
|
@@ -78,8 +84,6 @@ module Arel
|
|
78
84
|
end
|
79
85
|
|
80
86
|
|
81
|
-
|
82
|
-
#
|
83
87
|
# private
|
84
88
|
#
|
85
89
|
# def visit_Arel_Nodes_DeleteStatement o, collector
|
@@ -625,13 +629,14 @@ module Arel
|
|
625
629
|
# visit right, collector
|
626
630
|
# end
|
627
631
|
# end
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
632
|
+
|
633
|
+
def visit_Arel_Nodes_As o, collector
|
634
|
+
# collector = visit o.left, collector
|
635
|
+
# collector << " AS "
|
636
|
+
# visit o.right, collector
|
637
|
+
collector
|
638
|
+
end
|
639
|
+
|
635
640
|
# def visit_Arel_Nodes_UnqualifiedColumn o, collector
|
636
641
|
# collector << "#{quote_column_name o.name}"
|
637
642
|
# collector
|
@@ -756,4 +761,4 @@ module Arel
|
|
756
761
|
end
|
757
762
|
end
|
758
763
|
end
|
759
|
-
end
|
764
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module FinderMethods
|
3
|
+
|
4
|
+
def find_with_associations
|
5
|
+
arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
|
6
|
+
|
7
|
+
if block_given?
|
8
|
+
yield self
|
9
|
+
else
|
10
|
+
if ActiveRecord::NullRelation === self
|
11
|
+
[]
|
12
|
+
else
|
13
|
+
rows = connection.select_all(arel, 'SQL', arel.bind_values + bind_values)
|
14
|
+
instantiate_with_associations(rows, self)
|
15
|
+
# join_dependency.instantiate(rows, aliases)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def instantiate_with_associations(result_set, klass)
|
21
|
+
seen = Hash.new { |h, parent_klass|
|
22
|
+
h[parent_klass] = Hash.new { |i, parent_id|
|
23
|
+
i[parent_id] = Hash.new { |j, child_klass| j[child_klass] = {} }
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
model_cache = Hash.new { |h,klass| h[klass] = {} }
|
28
|
+
parents = model_cache[self.base_class]
|
29
|
+
|
30
|
+
result_set.each { |row_hash|
|
31
|
+
parent = parents[row_hash[primary_key]] ||= instantiate(row_hash.select{|k,v| column_names.include?(k.to_s) })
|
32
|
+
construct(parent, row_hash.select{|k,v| !column_names.include?(k.to_s) }, seen, model_cache)
|
33
|
+
}
|
34
|
+
|
35
|
+
parents.values
|
36
|
+
end
|
37
|
+
|
38
|
+
def construct(parent, relations, seen, model_cache)
|
39
|
+
relations.each do |key, attributes|
|
40
|
+
reflection = parent.class.reflect_on_association(key)
|
41
|
+
next unless reflection
|
42
|
+
|
43
|
+
if reflection.collection?
|
44
|
+
other = parent.association(reflection.name)
|
45
|
+
other.loaded!
|
46
|
+
else
|
47
|
+
if parent.association_cache.key?(reflection.name)
|
48
|
+
model = parent.association(reflection.name).target
|
49
|
+
construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if !reflection.collection?
|
54
|
+
construct_association(parent, reflection, attributes, seen, model_cache)
|
55
|
+
else
|
56
|
+
attributes.each do |row|
|
57
|
+
construct_association(parent, reflection, row, seen, model_cache)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def construct_association(parent, reflection, attributes, seen, model_cache)
|
65
|
+
return if attributes.nil?
|
66
|
+
id = attributes[reflection.klass.primary_key]
|
67
|
+
|
68
|
+
model = seen[parent.class.base_class][parent.id][reflection.klass][id]
|
69
|
+
|
70
|
+
if model
|
71
|
+
construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
72
|
+
else
|
73
|
+
model = construct_model(parent, reflection, id, attributes.select{|k,v| reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
74
|
+
seen[parent.class.base_class][parent.id][model.class.base_class][id] = model
|
75
|
+
construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def construct_model(record, reflection, id, attributes, seen, model_cache)
|
81
|
+
model = model_cache[reflection.klass][id] ||= reflection.klass.instantiate(attributes)
|
82
|
+
other = record.association(reflection.name)
|
83
|
+
|
84
|
+
if reflection.collection?
|
85
|
+
other.target.push(model)
|
86
|
+
else
|
87
|
+
other.target = model
|
88
|
+
end
|
89
|
+
|
90
|
+
other.set_inverse_instance(model)
|
91
|
+
model
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Arel
|
2
|
+
module Nodes
|
3
|
+
class SelectStatement < Arel::Nodes::Node
|
4
|
+
|
5
|
+
attr_accessor :eager_load
|
6
|
+
|
7
|
+
def initialize_with_eager_load cores = [SelectCore.new]
|
8
|
+
initialize_without_eager_load
|
9
|
+
@eager_load = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :initialize_without_eager_load, :initialize
|
13
|
+
alias_method :initialize, :initialize_with_eager_load
|
14
|
+
|
15
|
+
def hash
|
16
|
+
[@cores, @orders, @limit, @lock, @offset, @with, @eager_load].hash
|
17
|
+
end
|
18
|
+
|
19
|
+
def eql_with_eager_load? other
|
20
|
+
eql_without_eager_load?(other) && self.eager_load == other.eager_load
|
21
|
+
end
|
22
|
+
alias_method :eql_without_eager_load?, :eql?
|
23
|
+
alias_method :eql?, :eql_with_eager_load?
|
24
|
+
alias_method :==, :eql?
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Arel
|
2
|
+
class SelectManager < Arel::TreeManager
|
3
|
+
|
4
|
+
def eager_load
|
5
|
+
@ast.eager_load
|
6
|
+
end
|
7
|
+
|
8
|
+
def eager_load=(eager_load)
|
9
|
+
if eager_load.nil? || eager_load.expr.empty?
|
10
|
+
@ast.eager_load = nil
|
11
|
+
else
|
12
|
+
@ast.eager_load = eager_load
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/sunstone.rb
CHANGED
@@ -14,6 +14,11 @@ require 'ext/active_record/statement_cache'
|
|
14
14
|
require 'ext/active_record/relation'
|
15
15
|
require 'ext/active_record/associations/builder/has_and_belongs_to_many'
|
16
16
|
|
17
|
+
require 'ext/arel/select_manager'
|
18
|
+
require 'ext/arel/nodes/eager_load'
|
19
|
+
require 'ext/arel/nodes/select_statement'
|
20
|
+
require 'ext/active_record/finder_methods'
|
21
|
+
|
17
22
|
# require 'sunstone/parser'
|
18
23
|
|
19
24
|
module Sunstone
|
@@ -48,4 +53,4 @@ module Sunstone
|
|
48
53
|
# headers
|
49
54
|
# end
|
50
55
|
#
|
51
|
-
end
|
56
|
+
end
|
data/lib/sunstone/connection.rb
CHANGED
@@ -2,9 +2,9 @@ require 'uri'
|
|
2
2
|
require 'net/http'
|
3
3
|
require 'net/https'
|
4
4
|
|
5
|
-
#
|
6
|
-
# #
|
7
|
-
#
|
5
|
+
# _Sunstone_ is a low-level API. It provides basic HTTP #get, #post, #put, and
|
6
|
+
# #delete calls to the Sunstone Server. It can also provides basic error
|
7
|
+
# checking of responses.
|
8
8
|
module Sunstone
|
9
9
|
class Connection
|
10
10
|
|
@@ -99,7 +99,7 @@ module Sunstone
|
|
99
99
|
# end
|
100
100
|
def send_request(request, body=nil, &block)
|
101
101
|
request_headers.each { |k, v| request[k] = v }
|
102
|
-
|
102
|
+
|
103
103
|
if body.is_a?(IO)
|
104
104
|
request['Transfer-Encoding'] = 'chunked'
|
105
105
|
request.body_stream = body
|
@@ -108,23 +108,23 @@ module Sunstone
|
|
108
108
|
elsif body
|
109
109
|
request.body = Wankel.encode(body)
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
return_value = nil
|
113
113
|
@connection.request(request) do |response|
|
114
|
-
|
114
|
+
|
115
115
|
if response['X-42Floors-API-Version-Deprecated']
|
116
116
|
logger.warn("DEPRECATION WARNING: API v#{API_VERSION} is being phased out")
|
117
117
|
end
|
118
118
|
|
119
119
|
validate_response_code(response)
|
120
|
-
|
120
|
+
|
121
121
|
# Get the cookies
|
122
122
|
response.each_header do |key, value|
|
123
123
|
if key.downcase == 'set-cookie' && Thread.current[:sunstone_cookie_store]
|
124
124
|
Thread.current[:sunstone_cookie_store].set_cookie("#{site}#{request.path}", value)
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
if block_given?
|
129
129
|
return_value =yield(response)
|
130
130
|
else
|
@@ -132,11 +132,9 @@ module Sunstone
|
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
135
|
-
|
136
|
-
|
137
135
|
return_value
|
138
136
|
end
|
139
|
-
|
137
|
+
|
140
138
|
# Send a GET request to +path+ on the Sunstone Server via +Sunstone#send_request+.
|
141
139
|
# See +Sunstone#send_request+ for more details on how the response is handled.
|
142
140
|
#
|
@@ -335,4 +333,4 @@ module Sunstone
|
|
335
333
|
end
|
336
334
|
|
337
335
|
end
|
338
|
-
end
|
336
|
+
end
|
data/sunstone.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sunstone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -269,8 +269,12 @@ files:
|
|
269
269
|
- lib/arel/collectors/sunstone.rb
|
270
270
|
- lib/arel/visitors/sunstone.rb
|
271
271
|
- lib/ext/active_record/associations/builder/has_and_belongs_to_many.rb
|
272
|
+
- lib/ext/active_record/finder_methods.rb
|
272
273
|
- lib/ext/active_record/relation.rb
|
273
274
|
- lib/ext/active_record/statement_cache.rb
|
275
|
+
- lib/ext/arel/nodes/eager_load.rb
|
276
|
+
- lib/ext/arel/nodes/select_statement.rb
|
277
|
+
- lib/ext/arel/select_manager.rb
|
274
278
|
- lib/sunstone.rb
|
275
279
|
- lib/sunstone/connection.rb
|
276
280
|
- lib/sunstone/exception.rb
|