sunstone 0.1.0 → 1.0.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/active_record/connection_adapters/sunstone/column.rb +19 -0
  3. data/lib/active_record/connection_adapters/sunstone/database_statements.rb +40 -0
  4. data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +95 -0
  5. data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +22 -0
  6. data/lib/active_record/connection_adapters/sunstone_adapter.rb +177 -0
  7. data/lib/arel/collectors/sunstone.rb +75 -0
  8. data/lib/arel/visitors/sunstone.rb +769 -0
  9. data/lib/ext/active_record/associations/builder/has_and_belongs_to_many.rb +48 -0
  10. data/lib/ext/active_record/relation.rb +26 -0
  11. data/lib/ext/active_record/statement_cache.rb +24 -0
  12. data/lib/sunstone.rb +37 -347
  13. data/lib/sunstone/connection.rb +337 -0
  14. data/sunstone.gemspec +3 -2
  15. data/test/sunstone/connection_test.rb +319 -0
  16. data/test/sunstone/parser_test.rb +21 -21
  17. metadata +30 -36
  18. data/lib/sunstone/model.rb +0 -23
  19. data/lib/sunstone/model/attributes.rb +0 -99
  20. data/lib/sunstone/model/persistence.rb +0 -168
  21. data/lib/sunstone/schema.rb +0 -38
  22. data/lib/sunstone/type/boolean.rb +0 -19
  23. data/lib/sunstone/type/date_time.rb +0 -20
  24. data/lib/sunstone/type/decimal.rb +0 -19
  25. data/lib/sunstone/type/integer.rb +0 -17
  26. data/lib/sunstone/type/mutable.rb +0 -16
  27. data/lib/sunstone/type/string.rb +0 -18
  28. data/lib/sunstone/type/value.rb +0 -97
  29. data/test/sunstone/model/associations_test.rb +0 -55
  30. data/test/sunstone/model/attributes_test.rb +0 -60
  31. data/test/sunstone/model/persistence_test.rb +0 -173
  32. data/test/sunstone/model_test.rb +0 -11
  33. data/test/sunstone/schema_test.rb +0 -25
  34. data/test/sunstone/type/boolean_test.rb +0 -24
  35. data/test/sunstone/type/date_time_test.rb +0 -31
  36. data/test/sunstone/type/decimal_test.rb +0 -27
  37. data/test/sunstone/type/integer_test.rb +0 -29
  38. data/test/sunstone/type/string_test.rb +0 -54
  39. data/test/sunstone/type/value_test.rb +0 -27
@@ -1,38 +0,0 @@
1
- require 'sunstone/type/value'
2
- require 'sunstone/type/mutable'
3
- require 'sunstone/type/boolean'
4
- require 'sunstone/type/date_time'
5
- require 'sunstone/type/decimal'
6
- require 'sunstone/type/integer'
7
- require 'sunstone/type/string'
8
-
9
- module Sunstone
10
- class Schema
11
-
12
- attr_accessor :attributes
13
-
14
- def initialize
15
- @attributes = {}
16
- end
17
-
18
- def attribute(name, type, options = {})
19
- types = Sunstone::Type::Value.subclasses
20
- type = types.find {|sc| sc.name.demodulize.downcase == type.to_s}
21
-
22
- @attributes[name.to_s] = type.new(options)
23
- end
24
-
25
- def [](name)
26
- @attributes[name.to_s]
27
- end
28
-
29
- Sunstone::Type::Value.subclasses.each do |type|
30
- class_eval <<-EOV, __FILE__, __LINE__ + 1
31
- def #{type.name.demodulize.downcase}(name, options = {})
32
- attribute(name, "#{type.name.demodulize.downcase}", options)
33
- end
34
- EOV
35
- end
36
-
37
- end
38
- end
@@ -1,19 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class Boolean < Value
4
-
5
- TRUE_VALUES = [true, 'true', 'TRUE'].to_set
6
-
7
- private
8
-
9
- def _cast_value(value)
10
- if value == ''
11
- nil
12
- else
13
- TRUE_VALUES.include?(value)
14
- end
15
- end
16
-
17
- end
18
- end
19
- end
@@ -1,20 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class DateTime < Value
4
-
5
- private
6
-
7
- def _type_cast_for_json(value)
8
- value.iso8601(3) if value
9
- end
10
-
11
- def _cast_value(string)
12
- return string unless string.is_a?(::String)
13
- return if string.empty?
14
-
15
- ::DateTime.iso8601(string) || ::DateTime.parse(string)
16
- end
17
-
18
- end
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class Decimal < Value
4
-
5
- private
6
-
7
- def _cast_value(value)
8
- if value == ''
9
- nil
10
- elsif value.is_a?(BigDecimal)
11
- value
12
- else
13
- BigDecimal.new(value.to_s)
14
- end
15
- end
16
-
17
- end
18
- end
19
- end
@@ -1,17 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class Integer < Value
4
-
5
- private
6
-
7
- def _cast_value(value)
8
- case value
9
- when true then 1
10
- when false then 0
11
- else value.to_i
12
- end
13
- end
14
-
15
- end
16
- end
17
- end
@@ -1,16 +0,0 @@
1
- module Sunstone
2
- module Type
3
- module Mutable # :nodoc:
4
- def type_cast_from_user(value)
5
- type_cast_from_json(type_cast_for_json(value))
6
- end
7
-
8
- # +raw_old_value+ will be the `_before_type_cast` version of the
9
- # value (likely a string). +new_value+ will be the current, type
10
- # cast value.
11
- def changed_in_place?(raw_old_value, new_value)
12
- raw_old_value != type_cast_for_json(new_value)
13
- end
14
- end
15
- end
16
- end
@@ -1,18 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class String < Value
4
-
5
- private
6
-
7
- def _cast_value(value)
8
- case value
9
- when true then "1"
10
- when false then "0"
11
- # Dup the string
12
- else ::String.new(value.to_s)
13
- end
14
- end
15
-
16
- end
17
- end
18
- end
@@ -1,97 +0,0 @@
1
- module Sunstone
2
- module Type
3
- class Value
4
-
5
- attr_accessor :options
6
-
7
- def initialize(options={})
8
- @options = options
9
- end
10
-
11
- def type_cast_from_json(value)
12
- if @options[:array]
13
- value.nil? ? nil : value.map{ |v| _type_cast_from_json(v) }
14
- else
15
- _type_cast_from_json(value)
16
- end
17
- end
18
-
19
- def type_cast_from_user(value)
20
- if @options[:array]
21
- value.nil? ? nil : value.map{ |v| _type_cast_from_user(v) }
22
- else
23
- _type_cast_from_user(value)
24
- end
25
- end
26
-
27
- def type_cast_for_json(value)
28
- if @options[:array]
29
- value.nil? ? nil : value.map{ |v| _type_cast_for_json(v) }
30
- else
31
- _type_cast_for_json(value)
32
- end
33
- end
34
-
35
- # Determines whether a value has changed for dirty checking. +old_value+
36
- # and +new_value+ will always be type-cast. Types should not need to
37
- # override this method.
38
- def changed?(old_value, new_value, _new_value_before_type_cast)
39
- old_value != new_value
40
- end
41
-
42
- # Determines whether the mutable value has been modified since it was
43
- # read. Returns +false+ by default. This method should not need to be
44
- # overriden directly. Types which return a mutable value should include
45
- # +Type::Mutable+, which will define this method.
46
- def changed_in_place?(*)
47
- false
48
- end
49
-
50
- def readonly?
51
- @options[:readonly]
52
- end
53
-
54
- private
55
-
56
- # Type casts a value from json into the appropriate ruby type. Classes
57
- # which do not need separate type casting behavior for json and user
58
- # provided values should override +_cast_value+ instead.
59
- def _type_cast_from_json(value)
60
- _type_cast(value)
61
- end
62
-
63
- # Type casts a value from user input (e.g. from a setter). This value may
64
- # be a string from the form builder, or an already type cast value
65
- # provided manually to a setter.
66
- #
67
- # Classes which do not need separate type casting behavior for json
68
- # and user provided values should override +_type_cast+ or +_cast_value+
69
- # instead.
70
- def _type_cast_from_user(value)
71
- _type_cast(value)
72
- end
73
-
74
- # Cast a value from the ruby type to a type that the json knows how
75
- # to understand. The returned value from this method should be a
76
- # +String+, +Numeric+, +Symbol+, +true+, +false+, or +nil+
77
- def _type_cast_for_json(value)
78
- value
79
- end
80
-
81
- def _type_cast(value)
82
- _cast_value(value) unless value.nil?
83
- end
84
-
85
- # Convenience method for types which do not need separate type casting
86
- # behavior for user and database inputs. Called by
87
- # `_type_cast_from_json` and `_type_cast_from_user` for all values except
88
- # `nil`.
89
- #
90
- # If you wish to catch the nil case use the `_type_cast` function
91
- def _cast_value(value) # :doc:
92
- value
93
- end
94
-
95
- end
96
- end
97
- end
@@ -1,55 +0,0 @@
1
- require 'test_helper'
2
-
3
- class BelongsToModel < Sunstone::Model
4
- end
5
-
6
-
7
- class Sunstone::Model::AssociationsTest < Minitest::Test
8
-
9
- def setup
10
- @klass = Class.new(Sunstone::Model)
11
- end
12
-
13
- test "inherited models get a schema setup with id" do
14
- assert_equal({}, @klass.reflect_on_associations)
15
- end
16
-
17
- test "::belongs_to adds association" do
18
- @klass.belongs_to :belongs_to_model
19
-
20
- assert_equal({
21
- :name=>:belongs_to_model,
22
- :macro=>:belongs_to,
23
- :klass=>BelongsToModel,
24
- :foreign_key=>:belongs_to_model_id
25
- }, @klass.reflect_on_associations[:belongs_to_model])
26
- end
27
-
28
- test "::belongs_to addes foreign_key attribute to class" do
29
- @klass.belongs_to :belongs_to_model
30
-
31
- assert_kind_of Sunstone::Type::Integer, @klass.schema[:belongs_to_model_id]
32
- end
33
-
34
- test "::belongs_to setter and getter" do
35
- @klass.belongs_to :belongs_to_model
36
-
37
- model = @klass.new
38
- omodel = BelongsToModel.new(:id => 10)
39
- assert_nil model.belongs_to_model
40
- model.belongs_to_model = omodel
41
- assert_equal omodel, model.belongs_to_model
42
- assert_equal 10, model.belongs_to_model_id
43
- end
44
-
45
- test "::has_many adds association" do
46
- @klass.has_many :belongs_to_models
47
-
48
- assert_equal({
49
- :name => :belongs_to_models,
50
- :macro => :has_many,
51
- :klass => BelongsToModel
52
- }, @klass.reflect_on_associations[:belongs_to_models])
53
- end
54
-
55
- end
@@ -1,60 +0,0 @@
1
- require 'test_helper'
2
-
3
- class Sunstone::Model::AttributesTest < Minitest::Test
4
-
5
- def setup
6
- @klass = Class.new(Sunstone::Model)
7
- end
8
-
9
- test "inherited models get a schema setup with id" do
10
- assert_kind_of Sunstone::Schema, @klass.schema
11
- assert_kind_of Sunstone::Type::Integer, @klass.schema[:id]
12
- end
13
-
14
- test "::attribute" do
15
- @klass.attribute :name, :string
16
-
17
- assert_kind_of Sunstone::Type::String, @klass.schema[:name]
18
- end
19
-
20
- test "::attribute sets up readers" do
21
- @klass.attribute :name, :string
22
- model = @klass.new
23
-
24
- model.attributes[:name] = "my name"
25
- assert_equal "my name", model.name
26
- end
27
-
28
- test "::attributes sets up writer" do
29
- @klass.attribute :name, :string
30
- model = @klass.new
31
-
32
- model.schema[:name].expects(:type_cast_from_user).with("my name").returns("value")
33
- model.name = "my name"
34
-
35
- assert_equal "value", model.name
36
- assert_equal "value", model.attributes[:name]
37
- end
38
-
39
- test "::define_schema" do
40
- @klass.define_schema do
41
- attribute :name, :string
42
- integer :size
43
- end
44
-
45
- assert_kind_of Sunstone::Type::String, @klass.schema[:name]
46
- assert_kind_of Sunstone::Type::Integer, @klass.schema[:size]
47
- end
48
-
49
- test '#has?' do
50
- @klass.define_schema do
51
- attribute :name, :string
52
- integer :size
53
- end
54
- model = @klass.new(:size => 20)
55
-
56
- assert_equal false, model.has?(:name)
57
- assert_equal true, model.has?(:size)
58
- end
59
-
60
- end
@@ -1,173 +0,0 @@
1
- require 'test_helper'
2
-
3
- class Sunstone::Model::PersistenceTest < Minitest::Test
4
-
5
- class TestModel < Sunstone::Model
6
- define_schema do
7
- attribute :name, :string
8
- integer :size
9
- datetime :timestamp
10
- datetime :updated_at, :readonly => true
11
- end
12
- end
13
-
14
- def setup
15
- Sunstone.site = "http://test_api_key@testhost.com"
16
- @klass = Class.new(Sunstone::Model)
17
- end
18
-
19
- test '#serialize' do
20
- time = Time.now
21
- model = TestModel.new(:size => 20, :timestamp => time)
22
- assert_equal '{"id":null,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":null}', model.serialize
23
- end
24
-
25
- test '#serialize(:only => [KEYS])' do
26
- time = Time.now
27
- model = TestModel.new(:size => 20, :timestamp => time)
28
-
29
- assert_equal '{"size":20}', model.serialize(:only => ['size'])
30
- end
31
-
32
-
33
-
34
-
35
- test '#save a new record' do
36
- time = Time.now
37
- model = TestModel.new(:size => 20, :timestamp => time)
38
-
39
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
40
- .with(
41
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
42
- .to_return(
43
- :status => 200,
44
- :body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
45
-
46
- assert_equal true, model.save
47
- end
48
-
49
- test '#save a new invalid record' do
50
- time = Time.now
51
- model = TestModel.new(:size => 20, :timestamp => time)
52
-
53
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
54
- .with(
55
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
56
- .to_return(
57
- :status => 400,
58
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
59
-
60
- assert_equal false, model.save
61
- end
62
-
63
- test "#save a new record updates the model with the response" do
64
- time = Time.now
65
- model = TestModel.new(:size => 20, :timestamp => time)
66
-
67
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
68
- .with(
69
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
70
- .to_return(
71
- :status => 200,
72
- :body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
73
-
74
- model.save
75
- assert_equal 20, model.id
76
- assert_equal time.iso8601(3), model.updated_at.iso8601(3)
77
- end
78
-
79
- test "#save on an new record will set new_record? is false" do
80
- time = Time.now
81
- model = TestModel.new(:size => 20, :timestamp => time)
82
-
83
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
84
- .with(
85
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
86
- .to_return(
87
- :status => 200,
88
- :body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
89
-
90
- model.save
91
- assert_equal false, model.new_record?
92
- end
93
-
94
- test '#save on a persisted record' do
95
- time = Time.now
96
- model = TestModel.new(:id => 13, :size => 20, :timestamp => time)
97
- model.instance_variable_set(:@new_record, false)
98
-
99
- stub_request(:put, "http://testhost.com/sunstone_model_persistence_test_test_models/13")
100
- .with(
101
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
102
- .to_return(
103
- :status => 200,
104
- :body => '{"id":13,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
105
-
106
- assert_equal true, model.save
107
- end
108
-
109
- test '#save on a persisted record updates the model with the response' do
110
- time = Time.now
111
- model = TestModel.new(:id => 13, :size => 20, :timestamp => time)
112
- model.instance_variable_set(:@new_record, false)
113
-
114
- stub_request(:put, "http://testhost.com/sunstone_model_persistence_test_test_models/13")
115
- .with(
116
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
117
- .to_return(
118
- :status => 200,
119
- :body => '{"id":13,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
120
-
121
- model.save
122
- assert_equal 13, model.id
123
- assert_equal time.iso8601(3), model.updated_at.iso8601(3)
124
- end
125
-
126
- test '#save! a new record' do
127
- time = Time.now
128
- model = TestModel.new(:size => 20, :timestamp => time)
129
-
130
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
131
- .with(
132
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
133
- .to_return(
134
- :status => 200,
135
- :body => '{"id":20,"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
136
-
137
- assert_equal true, model.save!
138
- end
139
-
140
- test '#save! a new invalid record' do
141
- time = Time.now
142
- model = TestModel.new(:size => 20, :timestamp => time)
143
-
144
- stub_request(:post, "http://testhost.com/sunstone_model_persistence_test_test_models")
145
- .with(
146
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '"}')
147
- .to_return(
148
- :status => 400,
149
- :body => '{"name":null,"size":20,"timestamp":"' + time.iso8601(3) + '","updated_at":"' + time.iso8601(3) + '"}')
150
-
151
- assert_raises Sunstone::RecordInvalid do
152
- model.save!
153
- end
154
- end
155
-
156
-
157
- test '::find(id)' do
158
- stub_request(:get, "http://testhost.com/sunstone_model_persistence_test_test_models/324").to_return(:body => '{"size": 40}')
159
-
160
- model = TestModel.find('324')
161
- assert_kind_of TestModel, model
162
- assert_equal 40, model.size
163
- end
164
-
165
- test '::find(id) with 404' do
166
- stub_request(:get, "http://testhost.com/sunstone_model_persistence_test_test_models/324").to_return(:status => 404)
167
-
168
- assert_raises Sunstone::Exception::NotFound do
169
- TestModel.find('324')
170
- end
171
- end
172
-
173
- end