sunstone 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/active_record/connection_adapters/sunstone/column.rb +19 -0
- data/lib/active_record/connection_adapters/sunstone/database_statements.rb +40 -0
- data/lib/active_record/connection_adapters/sunstone/schema_statements.rb +95 -0
- data/lib/active_record/connection_adapters/sunstone/type/date_time.rb +22 -0
- data/lib/active_record/connection_adapters/sunstone_adapter.rb +177 -0
- data/lib/arel/collectors/sunstone.rb +75 -0
- data/lib/arel/visitors/sunstone.rb +769 -0
- data/lib/ext/active_record/associations/builder/has_and_belongs_to_many.rb +48 -0
- data/lib/ext/active_record/relation.rb +26 -0
- data/lib/ext/active_record/statement_cache.rb +24 -0
- data/lib/sunstone.rb +37 -347
- data/lib/sunstone/connection.rb +337 -0
- data/sunstone.gemspec +3 -2
- data/test/sunstone/connection_test.rb +319 -0
- data/test/sunstone/parser_test.rb +21 -21
- metadata +30 -36
- data/lib/sunstone/model.rb +0 -23
- data/lib/sunstone/model/attributes.rb +0 -99
- data/lib/sunstone/model/persistence.rb +0 -168
- data/lib/sunstone/schema.rb +0 -38
- data/lib/sunstone/type/boolean.rb +0 -19
- data/lib/sunstone/type/date_time.rb +0 -20
- data/lib/sunstone/type/decimal.rb +0 -19
- data/lib/sunstone/type/integer.rb +0 -17
- data/lib/sunstone/type/mutable.rb +0 -16
- data/lib/sunstone/type/string.rb +0 -18
- data/lib/sunstone/type/value.rb +0 -97
- data/test/sunstone/model/associations_test.rb +0 -55
- data/test/sunstone/model/attributes_test.rb +0 -60
- data/test/sunstone/model/persistence_test.rb +0 -173
- data/test/sunstone/model_test.rb +0 -11
- data/test/sunstone/schema_test.rb +0 -25
- data/test/sunstone/type/boolean_test.rb +0 -24
- data/test/sunstone/type/date_time_test.rb +0 -31
- data/test/sunstone/type/decimal_test.rb +0 -27
- data/test/sunstone/type/integer_test.rb +0 -29
- data/test/sunstone/type/string_test.rb +0 -54
- data/test/sunstone/type/value_test.rb +0 -27
data/lib/sunstone/schema.rb
DELETED
@@ -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,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,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
|
data/lib/sunstone/type/string.rb
DELETED
data/lib/sunstone/type/value.rb
DELETED
@@ -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
|