sunstone 0.1.0 → 1.0.0

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