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.
- 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
|