sunstone 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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