sunstone 2.0.0 → 2.0.1

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: 5971616d7a67d451d0d618ed1aaa6f9de9b3daa0
4
- data.tar.gz: df3a218c951f5070e2cfccdc91cfa88c0c6a895c
3
+ metadata.gz: e7571ad32bf7197a480c1f59c5a5158ce0f1d492
4
+ data.tar.gz: d10ec4207fc78c2e6ec8d3dee815469a7b4b868a
5
5
  SHA512:
6
- metadata.gz: 6c2eed7323ae88fe0200bfbe83dff412602174d0f3559d94c8bce01117768b1f11b70b95f3b016f75de4751f051db8eb5dbee9ea9efa94743d0e5f9fc49ccfa0
7
- data.tar.gz: 87f7fe2cf78a6d7b0e8a4d0c10b00f606b31d4058c4a8b0fe1ed5f70ab16d39414da4d8d350e778dc389fa19408fd3c980dd9cf03fc9cf7ec8acc94c6beb91fc
6
+ metadata.gz: 121532495ba520b5e66de7cc054e9fc1958076c6953c2dc10e710816d9944fc76e940a4dd6018cea3a5599aa43faecdee9c81259fd7d569ea659abcbc6ccb4d9
7
+ data.tar.gz: 815d5f4f6a5c89a1552b8dc8cde45ac8cf508608b5403c75f4516569fd834f2f3becf1fa3af3cf25c622cba2d3ade471dca215029d4aa2230a9b46fc916e730b
data/README.md CHANGED
@@ -1,4 +1,11 @@
1
- sunstone
1
+ Sunstone
2
2
  ========
3
3
 
4
- A library for interacting with REST APIs
4
+ An [ActiveRecord](https://rubygems.org/gems/activerecord) adapter for quering
5
+ APIs over Standard API (https://github.com/waratuman/standardapi).
6
+
7
+
8
+ TODO:
9
+ =====
10
+ Make `cookie_store` and optional
11
+ stream building model instances with wankel
@@ -1,48 +1,52 @@
1
- module ActiveRecord::Associations::Builder
2
- class HasAndBelongsToMany # :nodoc:
3
-
4
- def through_model
5
- habtm = JoinTableResolver.build lhs_model, association_name, options
6
-
7
- join_model = Class.new(lhs_model.base_class.superclass) {
8
- class << self;
9
- attr_accessor :class_resolver
10
- attr_accessor :name
11
- attr_accessor :table_name_resolver
12
- attr_accessor :left_reflection
13
- attr_accessor :right_reflection
14
- end
15
-
16
- def self.table_name
17
- table_name_resolver.join_table
18
- end
19
-
20
- def self.compute_type(class_name)
21
- class_resolver.compute_type class_name
22
- end
23
-
24
- def self.add_left_association(name, options)
25
- belongs_to name, options
26
- self.left_reflection = _reflect_on_association(name)
27
- end
28
-
29
- def self.add_right_association(name, options)
30
- rhs_name = name.to_s.singularize.to_sym
31
- belongs_to rhs_name, options
32
- self.right_reflection = _reflect_on_association(rhs_name)
33
- end
34
-
35
- }
36
-
37
- join_model.name = "HABTM_#{association_name.to_s.camelize}"
38
- join_model.table_name_resolver = habtm
39
- join_model.class_resolver = lhs_model
40
- join_model.primary_key = nil
41
-
42
- join_model.add_left_association :left_side, anonymous_class: lhs_model
43
- join_model.add_right_association association_name, belongs_to_options(options)
44
- join_model
45
- end
46
-
47
- end
48
- end
1
+ # module ActiveRecord::Associations::Builder
2
+ # class HasAndBelongsToMany # :nodoc:
3
+ #
4
+ # def through_model
5
+ # habtm = JoinTableResolver.build lhs_model, association_name, options
6
+ #
7
+ # join_model = Class.new(lhs_model.base_class.superclass) { # Don't use ActiveRecord::Base here because that might not be the abstract class that we need and the connection may be different
8
+ # class << self;
9
+ # attr_accessor :left_model
10
+ # attr_accessor :name
11
+ # attr_accessor :table_name_resolver
12
+ # attr_accessor :left_reflection
13
+ # attr_accessor :right_reflection
14
+ # end
15
+ #
16
+ # def self.table_name
17
+ # table_name_resolver.join_table
18
+ # end
19
+ #
20
+ # def self.compute_type(class_name)
21
+ # left_model.compute_type class_name
22
+ # end
23
+ #
24
+ # def self.add_left_association(name, options)
25
+ # belongs_to name, options
26
+ # self.left_reflection = _reflect_on_association(name)
27
+ # end
28
+ #
29
+ # def self.add_right_association(name, options)
30
+ # rhs_name = name.to_s.singularize.to_sym
31
+ # belongs_to rhs_name, options
32
+ # self.right_reflection = _reflect_on_association(rhs_name)
33
+ # end
34
+ #
35
+ # def self.retrieve_connection
36
+ # left_model.retrieve_connection
37
+ # end
38
+ #
39
+ # }
40
+ #
41
+ # join_model.name = "HABTM_#{association_name.to_s.camelize}"
42
+ # join_model.table_name_resolver = habtm
43
+ # join_model.class_resolver = lhs_model
44
+ # join_model.primary_key = nil
45
+ #
46
+ # join_model.add_left_association :left_side, anonymous_class: lhs_model
47
+ # join_model.add_right_association association_name, belongs_to_options(options)
48
+ # join_model
49
+ # end
50
+ #
51
+ # end
52
+ # end
@@ -3,9 +3,9 @@ module ActiveRecord
3
3
 
4
4
  private
5
5
 
6
- # "#{quoted_table_name}.#{quoted_primary_key} ASC"
6
+ # Arrrr Rails hard coding SQL
7
7
  def batch_order
8
- {:id => :asc}
8
+ primary_key ? {primary_key => :asc} : {}
9
9
  end
10
10
 
11
11
  end
@@ -1,28 +1,28 @@
1
- module ActiveRecord
2
- module Calculations
3
- def pluck(*column_names)
4
-
5
- # column_names.map! do |column_name|
6
- # if column_name.is_a?(Symbol) && attribute_alias?(column_name)
7
- # attribute_alias(column_name)
8
- # else
9
- # column_name.to_s
10
- # end
11
- # end
12
-
13
- if has_include?(column_names.first)
14
- construct_relation_for_association_calculations.pluck(*column_names)
15
- else
16
- relation = spawn
17
- relation.select_values = column_names.map { |cn|
18
- columns_hash.key?(cn) ? arel_table[cn] : cn
19
- }
20
-
21
- result = klass.connection.exec_query(relation.arel, nil, relation.arel.bind_values + bind_values)
22
- result.cast_values(klass.column_types)
23
- end
24
- end
25
-
26
- end
27
- end
28
-
1
+ # module ActiveRecord
2
+ # module Calculations
3
+ # def pluck(*column_names)
4
+ #
5
+ # # column_names.map! do |column_name|
6
+ # # if column_name.is_a?(Symbol) && attribute_alias?(column_name)
7
+ # # attribute_alias(column_name)
8
+ # # else
9
+ # # column_name.to_s
10
+ # # end
11
+ # # end
12
+ #
13
+ # if has_include?(column_names.first)
14
+ # construct_relation_for_association_calculations.pluck(*column_names)
15
+ # else
16
+ # relation = spawn
17
+ # relation.select_values = column_names.map { |cn|
18
+ # columns_hash.key?(cn) ? arel_table[cn] : cn
19
+ # }
20
+ #
21
+ # result = klass.connection.exec_query(relation.arel, nil, relation.arel.bind_values + bind_values)
22
+ # result.cast_values(klass.column_types)
23
+ # end
24
+ # end
25
+ #
26
+ # end
27
+ # end
28
+ #
@@ -1,22 +1,36 @@
1
1
  module ActiveRecord
2
2
  module FinderMethods
3
-
4
- def find_with_associations
5
- arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
6
3
 
4
+ def find_with_associations
5
+ join_dependency = nil
6
+ aliases = nil
7
+ relation = if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
8
+ arel.eager_load = Arel::Nodes::EagerLoad.new(eager_load_values)
9
+ self
10
+ else
11
+ join_dependency = construct_join_dependency(joins_values)
12
+ aliases = join_dependency.aliases
13
+ apply_join_dependency(select(aliases.columns), join_dependency)
14
+ end
15
+
7
16
  if block_given?
8
- yield self
17
+ yield relation
9
18
  else
10
- if ActiveRecord::NullRelation === self
19
+ if ActiveRecord::NullRelation === relation
11
20
  []
12
21
  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)
22
+ arel = relation.arel
23
+ rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
24
+ if join_dependency
25
+ join_dependency.instantiate(rows, aliases)
26
+ else
27
+ instantiate_with_associations(rows, relation)
28
+ end
29
+
16
30
  end
17
31
  end
18
32
  end
19
-
33
+
20
34
  def instantiate_with_associations(result_set, klass)
21
35
  seen = Hash.new { |h, parent_klass|
22
36
  h[parent_klass] = Hash.new { |i, parent_id|
@@ -26,20 +40,20 @@ module ActiveRecord
26
40
 
27
41
  model_cache = Hash.new { |h,klass| h[klass] = {} }
28
42
  parents = model_cache[self.base_class]
29
-
43
+
30
44
  result_set.each { |row_hash|
31
45
  parent = parents[row_hash[primary_key]] ||= instantiate(row_hash.select{|k,v| column_names.include?(k.to_s) })
32
46
  construct(parent, row_hash.select{|k,v| !column_names.include?(k.to_s) }, seen, model_cache)
33
47
  }
34
-
48
+
35
49
  parents.values
36
50
  end
37
-
51
+
38
52
  def construct(parent, relations, seen, model_cache)
39
53
  relations.each do |key, attributes|
40
54
  reflection = parent.class.reflect_on_association(key)
41
55
  next unless reflection
42
-
56
+
43
57
  if reflection.collection?
44
58
  other = parent.association(reflection.name)
45
59
  other.loaded!
@@ -49,7 +63,7 @@ module ActiveRecord
49
63
  construct(model, attributes.select{|k,v| !reflection.klass.column_names.include?(k.to_s) }, seen, model_cache)
50
64
  end
51
65
  end
52
-
66
+
53
67
  if !reflection.collection?
54
68
  construct_association(parent, reflection, attributes, seen, model_cache)
55
69
  else
@@ -57,13 +71,13 @@ module ActiveRecord
57
71
  construct_association(parent, reflection, row, seen, model_cache)
58
72
  end
59
73
  end
60
-
74
+
61
75
  end
62
76
  end
63
-
77
+
64
78
  def construct_association(parent, reflection, attributes, seen, model_cache)
65
79
  return if attributes.nil?
66
-
80
+
67
81
  klass = if reflection.polymorphic?
68
82
  parent.send(reflection.foreign_type).constantize.base_class
69
83
  else
@@ -71,12 +85,12 @@ module ActiveRecord
71
85
  end
72
86
  id = attributes[klass.primary_key]
73
87
  model = seen[parent.class.base_class][parent.id][klass][id]
74
-
88
+
75
89
  if model
76
90
  construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
77
91
 
78
92
  other = parent.association(reflection.name)
79
-
93
+
80
94
  if reflection.collection?
81
95
  other.target.push(model)
82
96
  else
@@ -90,7 +104,7 @@ module ActiveRecord
90
104
  construct(model, attributes.select{|k,v| !klass.column_names.include?(k.to_s) }, seen, model_cache)
91
105
  end
92
106
  end
93
-
107
+
94
108
 
95
109
  def construct_model(record, reflection, id, attributes, seen, model_cache)
96
110
  klass = if reflection.polymorphic?
@@ -98,7 +112,7 @@ module ActiveRecord
98
112
  else
99
113
  reflection.klass
100
114
  end
101
-
115
+
102
116
  model = model_cache[klass][id] ||= klass.instantiate(attributes)
103
117
  other = record.association(reflection.name)
104
118
 
@@ -111,7 +125,7 @@ module ActiveRecord
111
125
  other.set_inverse_instance(model)
112
126
  model
113
127
  end
114
-
128
+
115
129
  end
116
130
 
117
131
  end
@@ -0,0 +1,23 @@
1
+ module ActiveRecord
2
+ module QueryMethods
3
+
4
+ def reverse_sql_order(order_query)
5
+ order_query = [arel_table[primary_key].asc] if order_query.empty?
6
+
7
+ order_query.flat_map do |o|
8
+ case o
9
+ when Arel::Nodes::Ordering
10
+ o.reverse
11
+ when String
12
+ o.to_s.split(',').map! do |s|
13
+ s.strip!
14
+ s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC')
15
+ end
16
+ else
17
+ o
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -1,11 +1,11 @@
1
1
  module ActiveRecord
2
2
  class Relation
3
+
3
4
  def to_sql
4
5
  @to_sql ||= begin
5
6
  relation = self
6
7
  connection = klass.connection
7
- visitor = connection.visitor
8
- collector = connection.collector
8
+ visitor = connection.visitor.is_a?(Arel::Visitors::Sunstone) ? Arel::Visitors::ToSql.new(connection) : connection.visitor
9
9
 
10
10
  if eager_loading?
11
11
  find_with_associations { |rel| relation = rel }
@@ -14,13 +14,11 @@ module ActiveRecord
14
14
  arel = relation.arel
15
15
  binds = (arel.bind_values + relation.bind_values).dup
16
16
  binds.map! { |bv| connection.quote(*bv.reverse) }
17
- collect = visitor.accept(arel.ast, collector)
18
- if collector.is_a?(Arel::Collectors::Sunstone)
19
- collect.compile(binds)
20
- else
21
- collect.substitute_binds(binds).join
22
- end
17
+ collect = visitor.accept(arel.ast, Arel::Collectors::Bind.new)
18
+ collect.substitute_binds(binds).join
23
19
  end
24
20
  end
21
+
22
+
25
23
  end
26
24
  end
@@ -1,23 +1,29 @@
1
- module ActiveRecord
2
- class PredicateBuilder # :nodoc:
3
-
4
- def self.expand(klass, table, column, value)
5
- queries = []
6
-
7
- # In standard Rails where takes :table => { columns }, but in sunstone we
8
- # can can do nested tables eg: where(:properties => { :regions => {:id => 1}})
9
- if klass && reflection = klass._reflect_on_association(column)
10
- if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value)
11
- queries << build(table[reflection.foreign_type], base_class)
12
- end
13
-
14
- # column = reflection.foreign_key
15
- column # Don't need Rails to assume we are referencing a table
16
- end
17
-
18
- queries << build(table[column], value)
19
- queries
20
- end
21
-
22
- end
23
- end
1
+ # module ActiveRecord
2
+ # class PredicateBuilder # :nodoc:
3
+ #
4
+ # def self.expand(klass, table, column, value)
5
+ # queries = []
6
+ #
7
+ # # In standard Rails where takes :table => { columns }, but in sunstone we
8
+ # # can can do nested tables eg: where(:properties => { :regions => {:id => 1}})
9
+ # if klass && reflection = klass._reflect_on_association(column)
10
+ # base_class = polymorphic_base_class_from_value(value)
11
+ #
12
+ # if reflection.polymorphic? && base_class
13
+ # queries << build(table[reflection.foreign_type], base_class)
14
+ # end
15
+ #
16
+ # column = reflection.foreign_key
17
+ #
18
+ # if base_class
19
+ # primary_key = reflection.association_primary_key(base_class)
20
+ # value = convert_value_to_association_ids(value, primary_key)
21
+ # end
22
+ # end
23
+ #
24
+ # queries << build(table[column], value)
25
+ # queries
26
+ # end
27
+ #
28
+ # end
29
+ # end
@@ -1,23 +1,36 @@
1
1
  module ActiveRecord
2
2
  class StatementCache
3
3
  class PartialQuery
4
-
5
- def initialize collector
6
- @collector = collector
7
- @indexes = collector.value.find_all { |thing|
8
- Arel::Nodes::BindParam === thing
9
- }
4
+
5
+ def initialize(values, sunstone=false)
6
+ @values = values
7
+ if sunstone
8
+ @indexes = values.value.find_all { |thing|
9
+ Arel::Nodes::BindParam === thing
10
+ }
11
+ else
12
+ @indexes = values.each_with_index.find_all { |thing,i|
13
+ Arel::Nodes::BindParam === thing
14
+ }.map(&:last)
15
+ end
10
16
  end
11
17
 
12
18
  def sql_for(binds, connection)
13
19
  binds = binds.dup
14
- @collector.compile(binds)
20
+
21
+ if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
22
+ @values.compile(binds)
23
+ else
24
+ val = @values.dup
25
+ @indexes.each { |i| val[i] = connection.quote(*binds.shift.reverse) }
26
+ val.join
27
+ end
15
28
  end
16
29
  end
17
30
 
18
31
  def self.partial_query(visitor, ast, collector)
19
32
  collected = visitor.accept(ast, collector)
20
- PartialQuery.new collected
33
+ PartialQuery.new(visitor.is_a?(Arel::Visitors::Sunstone) ? collected : collected.value, visitor.is_a?(Arel::Visitors::Sunstone))
21
34
  end
22
35
 
23
36
  end