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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 567a0950650c172c56b5c8d23061ff04efe5ecc2
4
- data.tar.gz: 95cd7fcc96e4aaefb0ce439548fb2e5eb9d2aff1
3
+ metadata.gz: 25d9399ddb2d453dfd16181b8207792c1de527a6
4
+ data.tar.gz: e675ed6285907dfa641237e6d0e86df12c59ce29
5
5
  SHA512:
6
- metadata.gz: 82626c3c9861b180c9021eb845d2988e467a7564e0f9f5c040e202eb6ff996670d777f7f636924b8f2dc1d4738600b03381d2495c769e8a8288db534a8feccd8
7
- data.tar.gz: fd7e2ec407a4f2ae055a710613c3e1ae35d486679d2299bfe29f3a661e13396f687d597e8eecec056a42b418bf8138a02f0454a7a97f0f6c7b9e93b9c8a99ad4
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
- # def visit_Arel_Nodes_As o, collector
630
- # collector = visit o.left, collector
631
- # collector << " AS "
632
- # visit o.right, collector
633
- # end
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,7 @@
1
+ module Arel
2
+ module Nodes
3
+ class EagerLoad < Arel::Nodes::Unary
4
+
5
+ end
6
+ end
7
+ 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
@@ -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
@@ -2,9 +2,9 @@ require 'uri'
2
2
  require 'net/http'
3
3
  require 'net/https'
4
4
 
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.
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
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "sunstone"
3
- s.version = '1.1.0'
3
+ s.version = '1.2.0'
4
4
  s.authors = ["Jon Bracy"]
5
5
  s.email = ["jonbracy@gmail.com"]
6
6
  s.homepage = "http://sunstonerb.com"
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.1.0
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 00:00:00.000000000 Z
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