superstore 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 (100) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG +0 -0
  5. data/Gemfile +19 -0
  6. data/LICENSE +13 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +100 -0
  9. data/Rakefile +12 -0
  10. data/lib/superstore/adapters/abstract_adapter.rb +49 -0
  11. data/lib/superstore/adapters/cassandra_adapter.rb +181 -0
  12. data/lib/superstore/adapters/hstore_adapter.rb +163 -0
  13. data/lib/superstore/attribute_methods/definition.rb +22 -0
  14. data/lib/superstore/attribute_methods/dirty.rb +36 -0
  15. data/lib/superstore/attribute_methods/primary_key.rb +25 -0
  16. data/lib/superstore/attribute_methods/typecasting.rb +59 -0
  17. data/lib/superstore/attribute_methods.rb +96 -0
  18. data/lib/superstore/base.rb +33 -0
  19. data/lib/superstore/belongs_to/association.rb +48 -0
  20. data/lib/superstore/belongs_to/builder.rb +40 -0
  21. data/lib/superstore/belongs_to/reflection.rb +30 -0
  22. data/lib/superstore/belongs_to.rb +63 -0
  23. data/lib/superstore/callbacks.rb +29 -0
  24. data/lib/superstore/cassandra_schema/statements.rb +52 -0
  25. data/lib/superstore/cassandra_schema/tasks.rb +47 -0
  26. data/lib/superstore/cassandra_schema.rb +9 -0
  27. data/lib/superstore/connection.rb +39 -0
  28. data/lib/superstore/core.rb +59 -0
  29. data/lib/superstore/errors.rb +10 -0
  30. data/lib/superstore/identity.rb +26 -0
  31. data/lib/superstore/inspect.rb +25 -0
  32. data/lib/superstore/log_subscriber.rb +44 -0
  33. data/lib/superstore/model.rb +37 -0
  34. data/lib/superstore/persistence.rb +153 -0
  35. data/lib/superstore/railtie.rb +30 -0
  36. data/lib/superstore/railties/controller_runtime.rb +45 -0
  37. data/lib/superstore/schema.rb +20 -0
  38. data/lib/superstore/scope/batches.rb +32 -0
  39. data/lib/superstore/scope/finder_methods.rb +48 -0
  40. data/lib/superstore/scope/query_methods.rb +49 -0
  41. data/lib/superstore/scope.rb +49 -0
  42. data/lib/superstore/scoping.rb +27 -0
  43. data/lib/superstore/tasks/ks.rake +54 -0
  44. data/lib/superstore/timestamps.rb +19 -0
  45. data/lib/superstore/type.rb +16 -0
  46. data/lib/superstore/types/array_type.rb +20 -0
  47. data/lib/superstore/types/base_type.rb +26 -0
  48. data/lib/superstore/types/boolean_type.rb +20 -0
  49. data/lib/superstore/types/date_type.rb +22 -0
  50. data/lib/superstore/types/float_type.rb +16 -0
  51. data/lib/superstore/types/integer_type.rb +20 -0
  52. data/lib/superstore/types/json_type.rb +13 -0
  53. data/lib/superstore/types/string_type.rb +19 -0
  54. data/lib/superstore/types/time_type.rb +16 -0
  55. data/lib/superstore/types.rb +8 -0
  56. data/lib/superstore/validations.rb +44 -0
  57. data/lib/superstore.rb +69 -0
  58. data/superstore.gemspec +23 -0
  59. data/test/support/cassandra.rb +44 -0
  60. data/test/support/hstore.rb +40 -0
  61. data/test/support/issue.rb +10 -0
  62. data/test/test_helper.rb +42 -0
  63. data/test/unit/active_model_test.rb +18 -0
  64. data/test/unit/adapters/adapter_test.rb +6 -0
  65. data/test/unit/attribute_methods/definition_test.rb +13 -0
  66. data/test/unit/attribute_methods/dirty_test.rb +72 -0
  67. data/test/unit/attribute_methods/primary_key_test.rb +26 -0
  68. data/test/unit/attribute_methods/typecasting_test.rb +118 -0
  69. data/test/unit/attribute_methods_test.rb +51 -0
  70. data/test/unit/base_test.rb +20 -0
  71. data/test/unit/belongs_to/reflection_test.rb +12 -0
  72. data/test/unit/belongs_to_test.rb +62 -0
  73. data/test/unit/callbacks_test.rb +46 -0
  74. data/test/unit/cassandra_schema/statements_test.rb +47 -0
  75. data/test/unit/cassandra_schema/tasks_test.rb +31 -0
  76. data/test/unit/connection_test.rb +10 -0
  77. data/test/unit/core_test.rb +55 -0
  78. data/test/unit/identity_test.rb +26 -0
  79. data/test/unit/inspect_test.rb +26 -0
  80. data/test/unit/log_subscriber_test.rb +26 -0
  81. data/test/unit/persistence_test.rb +213 -0
  82. data/test/unit/railties/controller_runtime_test.rb +48 -0
  83. data/test/unit/schema_test.rb +27 -0
  84. data/test/unit/scope/batches_test.rb +30 -0
  85. data/test/unit/scope/finder_methods_test.rb +51 -0
  86. data/test/unit/scope/query_methods_test.rb +27 -0
  87. data/test/unit/scoping_test.rb +7 -0
  88. data/test/unit/serialization_test.rb +10 -0
  89. data/test/unit/timestamps_test.rb +27 -0
  90. data/test/unit/types/array_type_test.rb +21 -0
  91. data/test/unit/types/base_type_test.rb +19 -0
  92. data/test/unit/types/boolean_type_test.rb +24 -0
  93. data/test/unit/types/date_type_test.rb +15 -0
  94. data/test/unit/types/float_type_test.rb +17 -0
  95. data/test/unit/types/integer_type_test.rb +19 -0
  96. data/test/unit/types/json_type_test.rb +23 -0
  97. data/test/unit/types/string_type_test.rb +30 -0
  98. data/test/unit/types/time_type_test.rb +19 -0
  99. data/test/unit/validations_test.rb +27 -0
  100. metadata +170 -0
@@ -0,0 +1,22 @@
1
+ module Superstore
2
+ module Types
3
+ class DateType < BaseType
4
+ FORMAT = '%Y-%m-%d'
5
+ REGEX = /\A\d{4}-\d{2}-\d{2}\Z/
6
+
7
+ def encode(value)
8
+ raise ArgumentError.new("#{value.inspect} is not a Date") unless value.kind_of?(Date)
9
+ value.strftime(FORMAT)
10
+ end
11
+
12
+ def decode(str)
13
+ return nil if str.empty?
14
+ Date.parse(str)
15
+ end
16
+
17
+ def typecast(value)
18
+ value.to_date
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ module Superstore
2
+ module Types
3
+ class FloatType < BaseType
4
+ REGEX = /\A[-+]?\d+(\.\d+)?\Z/
5
+ def encode(float)
6
+ raise ArgumentError.new("#{float.inspect} is not a Float") unless float.kind_of?(Float)
7
+ float.to_s
8
+ end
9
+
10
+ def decode(str)
11
+ return nil if str.empty?
12
+ str.to_f
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Superstore
2
+ module Types
3
+ class IntegerType < BaseType
4
+ REGEX = /\A[-+]?\d+\Z/
5
+ def encode(int)
6
+ raise ArgumentError.new("#{int.inspect} is not an Integer.") unless int.kind_of?(Integer)
7
+ int.to_s
8
+ end
9
+
10
+ def decode(str)
11
+ return nil if str.empty?
12
+ str.to_i
13
+ end
14
+
15
+ def typecast(value)
16
+ value.to_i
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Superstore
2
+ module Types
3
+ class JsonType < BaseType
4
+ def encode(hash)
5
+ ActiveSupport::JSON.encode(hash)
6
+ end
7
+
8
+ def decode(str)
9
+ ActiveSupport::JSON.decode(str)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Superstore
2
+ module Types
3
+ class StringType < BaseType
4
+ def encode(str)
5
+ raise ArgumentError.new("#{str.inspect} is not a String") unless str.kind_of?(String)
6
+
7
+ unless str.encoding == Encoding::UTF_8
8
+ (str.frozen? ? str.dup : str).force_encoding('UTF-8')
9
+ else
10
+ str
11
+ end
12
+ end
13
+
14
+ def typecast(value)
15
+ value.to_s
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module Superstore
2
+ module Types
3
+ class TimeType < BaseType
4
+ def encode(time)
5
+ raise ArgumentError.new("#{time.inspect} is not a Time") unless time.kind_of?(Time)
6
+ time.utc.xmlschema(6)
7
+ end
8
+
9
+ def decode(str)
10
+ Time.parse(str).in_time_zone if str
11
+ rescue
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ Superstore::Type.register(:array, Superstore::Types::ArrayType)
2
+ Superstore::Type.register(:boolean, Superstore::Types::BooleanType)
3
+ Superstore::Type.register(:date, Superstore::Types::DateType)
4
+ Superstore::Type.register(:float, Superstore::Types::FloatType)
5
+ Superstore::Type.register(:integer, Superstore::Types::IntegerType)
6
+ Superstore::Type.register(:json, Superstore::Types::JsonType)
7
+ Superstore::Type.register(:time, Superstore::Types::TimeType)
8
+ Superstore::Type.register(:string, Superstore::Types::StringType)
@@ -0,0 +1,44 @@
1
+ module Superstore
2
+ class RecordInvalid < StandardError
3
+ attr_reader :record
4
+ def initialize(record)
5
+ @record = record
6
+ super("Invalid record: #{@record.errors.full_messages.to_sentence}")
7
+ end
8
+ end
9
+
10
+ module Validations
11
+ extend ActiveSupport::Concern
12
+ include ActiveModel::Validations
13
+
14
+ included do
15
+ define_callbacks :validate, scope: :name
16
+ end
17
+
18
+ module ClassMethods
19
+ def create!(attributes = {})
20
+ new(attributes).tap do |object|
21
+ object.save!
22
+ end
23
+ end
24
+ end
25
+
26
+ def save(options={})
27
+ if perform_validations(options)
28
+ super
29
+ true
30
+ else
31
+ false
32
+ end
33
+ end
34
+
35
+ def save!
36
+ save || raise(RecordInvalid.new(self))
37
+ end
38
+
39
+ protected
40
+ def perform_validations(options={})
41
+ (options[:validate] != false) ? valid? : true
42
+ end
43
+ end
44
+ end
data/lib/superstore.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'active_support/all'
2
+ require 'active_model'
3
+ require 'superstore/errors'
4
+
5
+ module Superstore
6
+ extend ActiveSupport::Autoload
7
+
8
+ autoload :AttributeMethods
9
+ autoload :Base
10
+ autoload :BelongsTo
11
+ autoload :Callbacks
12
+ autoload :Connection
13
+ autoload :Core
14
+ autoload :Identity
15
+ autoload :Inspect
16
+ autoload :Model
17
+ autoload :Persistence
18
+ autoload :Schema
19
+ autoload :CassandraSchema
20
+ autoload :Scope
21
+ autoload :Scoping
22
+ autoload :Serialization
23
+ autoload :Timestamps
24
+ autoload :Type
25
+ autoload :Validations
26
+
27
+ module AttributeMethods
28
+ extend ActiveSupport::Autoload
29
+
30
+ eager_autoload do
31
+ autoload :Definition
32
+ autoload :Dirty
33
+ autoload :PrimaryKey
34
+ autoload :Typecasting
35
+ end
36
+ end
37
+
38
+ module Adapters
39
+ extend ActiveSupport::Autoload
40
+
41
+ autoload :AbstractAdapter
42
+ autoload :CassandraAdapter
43
+ autoload :HstoreAdapter
44
+ end
45
+
46
+ module BelongsTo
47
+ extend ActiveSupport::Autoload
48
+
49
+ autoload :Association
50
+ autoload :Builder
51
+ autoload :Reflection
52
+ end
53
+
54
+ module Types
55
+ extend ActiveSupport::Autoload
56
+
57
+ autoload :BaseType
58
+ autoload :ArrayType
59
+ autoload :BooleanType
60
+ autoload :DateType
61
+ autoload :FloatType
62
+ autoload :IntegerType
63
+ autoload :JsonType
64
+ autoload :StringType
65
+ autoload :TimeType
66
+ end
67
+ end
68
+
69
+ require 'superstore/railtie' if defined?(Rails)
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'superstore'
5
+ s.version = '1.0.0'
6
+ s.description = 'ActiveModel for many attributes'
7
+ s.summary = 'Cassandra ActiveModel'
8
+ s.authors = ["Michael Koziarski", "gotime"]
9
+ s.email = 'developer@matthewhiggins.com'
10
+ s.homepage = 'http://github.com/data-axle/superstore'
11
+
12
+ s.required_ruby_version = '>= 2.0.0'
13
+ s.required_rubygems_version = '>= 1.3.5'
14
+
15
+ s.extra_rdoc_files = ["README.md"]
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test}/*`.split("\n")
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_runtime_dependency('activemodel', '>= 3.0')
21
+
22
+ s.add_development_dependency('bundler')
23
+ end
@@ -0,0 +1,44 @@
1
+ Bundler.require :cassandra
2
+
3
+ Superstore::Base.config = {
4
+ keyspace: 'superstore_test',
5
+ servers: '127.0.0.1:9160',
6
+ consistency: 'QUORUM',
7
+ thrift: {
8
+ timeout: 5
9
+ }
10
+ }
11
+
12
+ begin
13
+ Superstore::CassandraSchema.drop_keyspace 'superstore_test'
14
+ rescue Exception => e
15
+ end
16
+
17
+ sleep 1
18
+ Superstore::CassandraSchema.create_keyspace 'superstore_test'
19
+ Superstore::CassandraSchema.create_column_family 'Issues'
20
+
21
+ Superstore::Base.class_eval do
22
+ class_attribute :created_records
23
+ self.created_records = []
24
+
25
+ after_create do
26
+ created_records << self
27
+ end
28
+
29
+ def self.delete_after_test
30
+ # created_records.reject(&:destroyed?).each(&:destroy)
31
+ Issue.delete_all
32
+ created_records.clear
33
+ end
34
+ end
35
+
36
+ module ActiveSupport
37
+ class TestCase
38
+ teardown do
39
+ if Superstore::Base.created_records.any?
40
+ Superstore::Base.delete_after_test
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,40 @@
1
+ Bundler.require :hstore
2
+ require 'active_record'
3
+
4
+ Superstore::Base.config = {'adapter' => 'hstore'}
5
+
6
+ class PGInitializer
7
+ def self.initialize!
8
+ config = {
9
+ 'adapter' => 'postgresql',
10
+ 'encoding' => 'unicode',
11
+ 'database' => 'superstore_test',
12
+ 'pool' => 5,
13
+ 'username' => 'postgres'
14
+ }
15
+
16
+ ActiveRecord::Base.configurations = { test: config }
17
+
18
+ ActiveRecord::Tasks::DatabaseTasks.drop config
19
+ ActiveRecord::Tasks::DatabaseTasks.create config
20
+ ActiveRecord::Base.establish_connection config
21
+
22
+ Superstore::Base.adapter.create_table('issues')
23
+ end
24
+
25
+ def self.table_names
26
+ %w(issues)
27
+ end
28
+ end
29
+
30
+ PGInitializer.initialize!
31
+
32
+ module ActiveSupport
33
+ class TestCase
34
+ teardown do
35
+ PGInitializer.table_names.each do |table_name|
36
+ ActiveRecord::Base.connection.execute "TRUNCATE #{table_name}"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ class Issue < Superstore::Base
2
+ string :description
3
+ string :title
4
+
5
+ before_create { self.description ||= 'funny' }
6
+
7
+ def self.for_key key
8
+ where_ids(key)
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ require 'bundler/setup'
2
+ Bundler.require(:default, :test)
3
+
4
+ I18n.config.enforce_available_locales = false
5
+
6
+ require 'rails/test_help'
7
+ require 'mocha/setup'
8
+
9
+ # require 'support/hstore'
10
+ require 'support/cassandra'
11
+ require 'support/issue'
12
+
13
+ def MiniTest.filter_backtrace(bt)
14
+ bt
15
+ end
16
+
17
+ module Superstore
18
+ class TestCase < ActiveSupport::TestCase
19
+ def temp_object(&block)
20
+ Class.new(Superstore::Base) do
21
+ self.column_family = 'Issues'
22
+ string :force_save
23
+ before_save { self.force_save = 'junk' }
24
+
25
+ def self.name
26
+ 'Issue'
27
+ end
28
+
29
+ instance_eval(&block) if block_given?
30
+ end
31
+ end
32
+ end
33
+
34
+ module Types
35
+ class TestCase < Superstore::TestCase
36
+ attr_accessor :coder
37
+ setup do
38
+ @coder = self.class.name.sub(/Test$/, '').constantize.new
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class ActiveModelTest < Superstore::TestCase
4
+
5
+ include ActiveModel::Lint::Tests
6
+
7
+ # overrides ActiveModel::Lint::Tests#test_to_param
8
+ def test_to_param
9
+ end
10
+
11
+ # overrides ActiveModel::Lint::Tests#test_to_key
12
+ def test_to_key
13
+ end
14
+
15
+ def setup
16
+ @model = Issue.new
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ require 'test_helper'
2
+
3
+ class Superstore::Adapters::AdapterTest < Superstore::TestCase
4
+ test 'create_table' do
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ class Superstore::AttributeMethods::DefinitionTest < Superstore::TestCase
4
+ class TestType < Superstore::Types::BaseType
5
+ end
6
+
7
+ test 'typecast' do
8
+ definition = Superstore::AttributeMethods::Definition.new(:foo, TestType, {a: :b})
9
+
10
+ assert_equal 'foo', definition.name
11
+ assert_kind_of TestType, definition.coder
12
+ end
13
+ end
@@ -0,0 +1,72 @@
1
+ require 'test_helper'
2
+
3
+ class Superstore::AttributeMethods::DirtyTest < Superstore::TestCase
4
+ test 'save clears dirty' do
5
+ record = temp_object do
6
+ string :name
7
+ end.new name: 'foo'
8
+
9
+ assert record.changed?
10
+
11
+ record.save!
12
+
13
+ assert_equal [nil, 'foo'], record.previous_changes['name']
14
+ assert !record.changed?
15
+ end
16
+
17
+ test 'reload clears dirty' do
18
+ record = temp_object do
19
+ string :name
20
+ end.create! name: 'foo'
21
+
22
+ record.name = 'bar'
23
+ assert record.changed?
24
+
25
+ record.reload
26
+
27
+ assert !record.changed?
28
+ end
29
+
30
+ test 'typecast float before dirty check' do
31
+ record = temp_object do
32
+ float :price
33
+ end.create(price: 5.01)
34
+
35
+ record.price = '5.01'
36
+ assert !record.changed?
37
+
38
+ record.price = '7.12'
39
+ assert record.changed?
40
+ end
41
+
42
+ test 'typecast boolean before dirty check' do
43
+ record = temp_object do
44
+ boolean :awesome
45
+ end.create(awesome: false)
46
+
47
+ record.awesome = false
48
+ assert !record.changed?
49
+
50
+ record.awesome = true
51
+ assert record.changed?
52
+ end
53
+
54
+ test 'write_attribute' do
55
+ object = temp_object do
56
+ string :name
57
+ end
58
+
59
+ expected = {"name"=>[nil, "foo"]}
60
+
61
+ object.new.tap do |record|
62
+ record.name = 'foo'
63
+ assert_equal expected, record.changes
64
+ end
65
+
66
+ object.new.tap do |record|
67
+ record[:name] = 'foo'
68
+ # record.write_attribute(:name, 'foo')
69
+ assert_equal expected, record.changes
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class Superstore::AttributeMethods::PrimaryKeyTest < Superstore::TestCase
4
+ test 'get id' do
5
+ model = temp_object do
6
+ key do
7
+ "foo"
8
+ end
9
+ end
10
+ record = model.new
11
+
12
+ assert_equal 'foo', record.id
13
+ end
14
+
15
+ test 'set id' do
16
+ issue = Issue.new id: 'foo'
17
+
18
+ assert_equal 'foo', issue.id
19
+ end
20
+
21
+ test 'attributes' do
22
+ issue = Issue.new
23
+
24
+ assert_not_nil issue.attributes['id']
25
+ end
26
+ end
@@ -0,0 +1,118 @@
1
+ require 'test_helper'
2
+
3
+ class Superstore::AttributeMethods::TypecastingTest < Superstore::TestCase
4
+ class CustomType
5
+ end
6
+
7
+ class CustomCoder < Superstore::Types::BaseType
8
+ end
9
+
10
+ class TestIssue < Superstore::Base
11
+ self.column_family = 'Issues'
12
+
13
+ attribute :custom_column, type: CustomType, coder: CustomCoder
14
+ boolean :enabled
15
+ float :rating
16
+ integer :price
17
+ json :orders
18
+ string :name
19
+ end
20
+
21
+ class TestChildIssue < TestIssue
22
+ string :description
23
+ end
24
+
25
+ test 'attributes not shared' do
26
+ assert_nothing_raised { Issue.new.description }
27
+ assert_raise(NoMethodError) { TestIssue.new.description }
28
+ assert_nothing_raised { TestChildIssue.new.description }
29
+ end
30
+
31
+ test 'custom attribute definer' do
32
+ model_attribute = TestIssue.attribute_definitions['custom_column']
33
+
34
+ assert_kind_of CustomCoder, model_attribute.coder
35
+ assert_equal 'custom_column', model_attribute.name
36
+ end
37
+
38
+ test 'typecast_attribute' do
39
+ assert_equal 1, TestIssue.typecast_attribute(TestIssue.new, 'price', 1)
40
+ assert_equal 1, TestIssue.typecast_attribute(TestIssue.new, :price, 1)
41
+
42
+ assert_raise NoMethodError do
43
+ TestIssue.typecast_attribute(TestIssue.new, 'wtf', 1)
44
+ end
45
+ end
46
+
47
+ test 'boolean attribute' do
48
+ issue = TestIssue.create! enabled: '1'
49
+ assert_equal true, issue.enabled
50
+
51
+ issue = TestIssue.find issue.id
52
+ assert_equal true, issue.enabled
53
+ end
54
+
55
+ test 'float attribute' do
56
+ issue = TestIssue.create! rating: '4.5'
57
+ assert_equal 4.5, issue.rating
58
+
59
+ issue = TestIssue.find issue.id
60
+ assert_equal(4.5, issue.rating)
61
+ end
62
+
63
+ test 'integer attribute' do
64
+ issue = TestIssue.create! price: '101'
65
+ assert_equal 101, issue.price
66
+
67
+ issue = TestIssue.find issue.id
68
+ assert_equal(101, issue.price)
69
+
70
+ issue = TestIssue.new price: ''
71
+ assert_nil issue.price
72
+ end
73
+
74
+ test 'json attribute' do
75
+ issue = TestIssue.create! orders: {'a' => 'b'}
76
+ assert_equal({'a' => 'b'}, issue.orders)
77
+
78
+ issue = TestIssue.find issue.id
79
+ assert_equal({'a' => 'b'}, issue.orders)
80
+ end
81
+
82
+ test 'string attribute' do
83
+ issue = TestIssue.create! name: 'hola'
84
+ assert_equal('hola', issue.name)
85
+
86
+ issue = TestIssue.find issue.id
87
+ assert_equal('hola', issue.name)
88
+
89
+ issue = TestIssue.create! name: 42
90
+ assert_equal '42', issue.name
91
+ end
92
+
93
+ test 'multiple attributes definition' do
94
+ class MultipleAttributesIssue < Superstore::Base
95
+ self.column_family = 'Issues'
96
+ end
97
+
98
+ assert_nothing_raised {
99
+ MultipleAttributesIssue.string :hello, :greetings, :bye
100
+ }
101
+ issue = MultipleAttributesIssue.new :hello => 'hey', :greetings => 'how r u', :bye => 'see ya'
102
+
103
+ assert_equal 'how r u', issue.greetings
104
+ end
105
+
106
+ test 'multiple attributes with options' do
107
+ class MultipleAttributesIssue < Superstore::Base
108
+ self.column_family = 'Issues'
109
+ end
110
+
111
+ MultipleAttributesIssue.expects(:attribute).with(:hello, { :unique => :true, :type => :string })
112
+ MultipleAttributesIssue.expects(:attribute).with(:world, { :unique => :true, :type => :string })
113
+
114
+ class MultipleAttributesIssue < Superstore::Base
115
+ string :hello, :world, :unique => :true
116
+ end
117
+ end
118
+ end