trax_model 0.0.92 → 0.0.93

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -1
  3. data/README.md +227 -86
  4. data/lib/trax.rb +0 -1
  5. data/lib/trax/model.rb +23 -29
  6. data/lib/trax/model/attributes.rb +3 -1
  7. data/lib/trax/model/attributes/attribute.rb +11 -0
  8. data/lib/trax/model/attributes/definitions.rb +16 -0
  9. data/lib/trax/model/attributes/errors.rb +8 -0
  10. data/lib/trax/model/attributes/fields.rb +74 -0
  11. data/lib/trax/model/attributes/mixin.rb +48 -19
  12. data/lib/trax/model/attributes/type.rb +4 -0
  13. data/lib/trax/model/attributes/types/array.rb +8 -25
  14. data/lib/trax/model/attributes/types/boolean.rb +51 -0
  15. data/lib/trax/model/attributes/types/enum.rb +53 -12
  16. data/lib/trax/model/attributes/types/json.rb +36 -33
  17. data/lib/trax/model/attributes/types/string.rb +50 -0
  18. data/lib/trax/model/attributes/types/uuid_array.rb +17 -28
  19. data/lib/trax/model/attributes/value.rb +16 -0
  20. data/lib/trax/model/errors.rb +7 -0
  21. data/lib/trax/model/mixins.rb +11 -0
  22. data/lib/trax/model/mixins/field_scopes.rb +60 -0
  23. data/lib/trax/model/mixins/id_scopes.rb +36 -0
  24. data/lib/trax/model/mixins/sort_by_scopes.rb +25 -0
  25. data/lib/trax/model/railtie.rb +1 -0
  26. data/lib/trax/model/scopes.rb +16 -0
  27. data/lib/trax/model/struct.rb +168 -14
  28. data/lib/trax/model/unique_id.rb +14 -21
  29. data/lib/trax/model/uuid.rb +1 -1
  30. data/lib/trax/validators/enum_attribute_validator.rb +9 -0
  31. data/lib/trax/validators/future_validator.rb +1 -1
  32. data/lib/trax/validators/json_attribute_validator.rb +3 -3
  33. data/lib/trax/validators/string_attribute_validator.rb +17 -0
  34. data/lib/trax_model/version.rb +1 -1
  35. data/spec/db/database.yml +16 -0
  36. data/spec/db/schema/default_tables.rb +68 -0
  37. data/spec/db/schema/pg_tables.rb +27 -0
  38. data/spec/spec_helper.rb +20 -3
  39. data/spec/support/models.rb +123 -0
  40. data/spec/support/pg/models.rb +103 -0
  41. data/spec/trax/model/attributes/fields_spec.rb +88 -0
  42. data/spec/trax/model/attributes/types/enum_spec.rb +51 -0
  43. data/spec/trax/model/attributes/types/json_spec.rb +107 -0
  44. data/spec/trax/model/attributes_spec.rb +13 -0
  45. data/spec/trax/model/errors_spec.rb +1 -2
  46. data/spec/trax/model/mixins/field_scopes_spec.rb +7 -0
  47. data/spec/trax/model/struct_spec.rb +1 -1
  48. data/spec/trax/model/unique_id_spec.rb +1 -3
  49. data/spec/trax/validators/url_validator_spec.rb +1 -1
  50. data/trax_model.gemspec +4 -4
  51. metadata +57 -19
  52. data/lib/trax/model/config.rb +0 -16
  53. data/lib/trax/model/validators.rb +0 -15
  54. data/lib/trax/validators/enum_validator.rb +0 -16
  55. data/spec/support/schema.rb +0 -151
  56. data/spec/trax/model/config_spec.rb +0 -13
@@ -8,17 +8,10 @@ module Trax
8
8
  option :uuid_map, :default => {}
9
9
  end
10
10
 
11
- included do
11
+ after_included do |options|
12
12
  define_configuration_options!(:unique_id) do
13
+
13
14
  option :uuid_prefix,
14
- :setter => lambda{ |prefix|
15
- if(::Trax::Model::UniqueId.config.uuid_map.values.include?(prefix) && ::Trax::Model::UniqueId.config.uuid_map[self.source.name] != prefix)
16
- raise ::Trax::Model::Errors::DuplicatePrefixRegistered.new(:prefix => prefix, :model => self.source.name)
17
- end
18
-
19
- ::Trax::Model::UniqueId.config.uuid_map[self.source.name] = prefix
20
- ::Trax::Model::UUIDPrefix.new(prefix)
21
- },
22
15
  :validates => {
23
16
  :exclusion => {
24
17
  :in => ::Trax::Model::Registry.uuid_map.values
@@ -31,15 +24,25 @@ module Trax
31
24
  }
32
25
 
33
26
  option :uuid_column, :default => ::Trax::Model::UniqueId.config.uuid_column
27
+
28
+ klass do
29
+ def uuid_prefix=(prefix)
30
+ if(::Trax::Model::UniqueId.config.uuid_map.values.include?(prefix) && ::Trax::Model::UniqueId.config.uuid_map[self.source.name] != prefix)
31
+ raise ::Trax::Model::Errors::DuplicatePrefixRegistered.new(:prefix => prefix, :model => self.source.name)
32
+ end
33
+
34
+ ::Trax::Model::UniqueId.config.uuid_map[self.source.name] = prefix
35
+ super(::Trax::Model::UUIDPrefix.new(prefix))
36
+ end
37
+ end
38
+
34
39
  end
35
40
 
36
41
  #grab prefix from uuid registry if uuids are defined in an initializer
37
42
  if ::Trax::Model.mixin_registry.key?(:unique_id) && ::Trax::Model::UUID.klass_prefix_map.key?(self.name)
38
43
  self.unique_id_config.uuid_prefix = ::Trax::Model::UUID.klass_prefix_map[self.name]
39
44
  end
40
- end
41
45
 
42
- after_included do |options|
43
46
  self.unique_id_config.merge!(options)
44
47
 
45
48
  if(self.unique_id_config.uuid_prefix)
@@ -76,16 +79,6 @@ module Trax
76
79
  self.unique_id_config.uuid_prefix
77
80
  end
78
81
  end
79
-
80
- # def self.apply_mixin(target, options)
81
- # target.unique_id_config.merge!(options)
82
- #
83
- # if(target.unique_id_config.uuid_prefix)
84
- # target.default_value_for(:"#{target.unique_id_config.uuid_column}") {
85
- # ::Trax::Model::UUID.generate(target.unique_id_config.uuid_prefix)
86
- # }
87
- # end
88
- # end
89
82
  end
90
83
  end
91
84
  end
@@ -28,7 +28,7 @@ module Trax
28
28
  end
29
29
 
30
30
  def record
31
- @record ||= record_type ? record_type.find_by(:"#{record_type.uuid_column}" => self) : nil
31
+ @record ||= record_type ? record_type.find_by(:"#{record_type.unique_id_config.uuid_column}" => self) : nil
32
32
  end
33
33
 
34
34
  def record_type
@@ -0,0 +1,9 @@
1
+ class EnumAttributeValidator < ActiveModel::EachValidator
2
+ def validate_each(object, attribute, value)
3
+ enum_attribute = object.class.fields_module[attribute]
4
+
5
+ unless value.is_a?(enum_attribute) && enum_attribute === value
6
+ object.errors[attribute] = "#{value} is not an allowed value"
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  class FutureValidator < ActiveModel::EachValidator
2
2
  def validate_each(object, attribute, value)
3
- object.errors[attribute] << 'Must be in future' if value < ::DateTime.now
3
+ object.errors[attribute] << 'Must be in future' if value && (value < ::DateTime.now)
4
4
  end
5
5
  end
@@ -3,13 +3,13 @@
3
3
  # that a hash is not provided
4
4
  class JsonAttributeValidator < ActiveModel::EachValidator
5
5
  def validate_each(object, attribute, value)
6
- json_attribute = object.class.trax_attribute_fields[:json][attribute]
6
+ json_attribute = object.class.fields_module[attribute]
7
7
 
8
8
  unless value.is_a?(json_attribute) && value.valid?
9
9
  if value.is_a?(json_attribute)
10
10
  value.errors.messages.each_pair do |k,v|
11
- v = v.join(", ") if v.is_a?(Array)
12
- object.errors.add(:"#{attribute}.#{k}", v)
11
+ v.flatten.join(", ") if v.is_a?(Array)
12
+ object.errors.add("#{attribute}.#{k}", v)
13
13
  end
14
14
  else
15
15
  object.errors[attribute] << "can not be blank"
@@ -0,0 +1,17 @@
1
+ # validates each json property and bubbles up any errors
2
+ # also throws a generic can not be blank error, in the event
3
+ # that a hash is not provided
4
+ class StringAttributeValidator < ActiveModel::EachValidator
5
+ def validate_each(object, attribute, value)
6
+ string_attribute = value.class
7
+
8
+ unless value.valid?
9
+ if value.is_a?(string_attribute)
10
+ value.errors.messages.each_pair do |k,v|
11
+ v.flatten.join(", ") if v.is_a?(Array)
12
+ object.errors.add("#{attribute}.#{k}", v)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module TraxModel
2
- VERSION = '0.0.92'
2
+ VERSION = '0.0.93'
3
3
  end
@@ -0,0 +1,16 @@
1
+ default: &default
2
+ adapter: sqlite3
3
+ database: spec/test.db
4
+
5
+ sqllite:
6
+ <<: *default
7
+
8
+ postgres:
9
+ <<: *default
10
+ adapter: postgresql
11
+ encoding: unicode
12
+ database: trax_model_tests
13
+ pool: 5
14
+ host: localhost
15
+ username: postgres
16
+ password:
@@ -0,0 +1,68 @@
1
+ DEFAULT_TABLES = Proc.new do
2
+ create_table "products", :force => true do |t|
3
+ t.string "name"
4
+ t.integer "category_id"
5
+ t.integer "user_id"
6
+ t.decimal "price"
7
+ t.integer "in_stock_quantity"
8
+ t.integer "on_order_quantity"
9
+ t.boolean "active"
10
+ t.string "uuid"
11
+ t.integer "status"
12
+ t.integer "size"
13
+ t.datetime "created_at", :null => false
14
+ t.datetime "updated_at", :null => false
15
+ end
16
+
17
+ create_table "messages", :force => true do |t|
18
+ t.string "title"
19
+ t.text "body"
20
+ t.integer "status"
21
+ t.string "uuid"
22
+ t.boolean "deleted"
23
+ t.datetime "deleted_at"
24
+ t.datetime "deliver_at"
25
+ t.datetime "created_at", :null => false
26
+ t.datetime "updated_at", :null => false
27
+ end
28
+
29
+ create_table "widgets", :force => true do |t|
30
+ t.string "uuid"
31
+ t.string "email_address"
32
+ t.string "subdomain"
33
+ t.string "website"
34
+ t.integer "status"
35
+ t.datetime "created_at", :null => false
36
+ t.datetime "updated_at", :null => false
37
+ end
38
+
39
+ create_table "things", :force => true do |t|
40
+ t.string "name"
41
+ t.string "uuid"
42
+ t.datetime "created_at", :null => false
43
+ t.datetime "updated_at", :null => false
44
+ end
45
+
46
+ create_table "people", :force => true do |t|
47
+ t.string "name"
48
+ t.string "uuid"
49
+ t.datetime "created_at", :null => false
50
+ t.datetime "updated_at", :null => false
51
+ end
52
+
53
+ create_table "staplers", :force => true do |t|
54
+ t.string "name"
55
+ t.string "type"
56
+ t.integer "attribute_set_id"
57
+ t.datetime "created_at", :null => false
58
+ t.datetime "updated_at", :null => false
59
+ end
60
+
61
+ create_table "swingline_stapler_attribute_sets", :force => true do |t|
62
+ t.float "speed"
63
+ t.string "owner"
64
+
65
+ t.datetime "created_at", :null => false
66
+ t.datetime "updated_at", :null => false
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ PG_TABLES = Proc.new do
2
+ execute %q{CREATE EXTENSION IF NOT EXISTS "uuid-ossp";}
3
+ execute %q{CREATE EXTENSION IF NOT EXISTS "pg_trgm";}
4
+
5
+ create_table "ecommerce_products", :id => :uuid, :force => true do |t|
6
+ t.string "name"
7
+ t.string "type"
8
+ t.uuid "category_id"
9
+ t.uuid "user_id"
10
+ t.decimal "price"
11
+ t.boolean "active"
12
+ t.integer "status"
13
+ t.jsonb "custom_fields"
14
+ t.jsonb "stock"
15
+ t.datetime "created_at", :null => false
16
+ t.datetime "updated_at", :null => false
17
+ end
18
+
19
+ create_table "ecommerce_product_attribute_sets", :id => :uuid, :force => true do |t|
20
+ t.uuid "user_id"
21
+ t.uuid "product_id"
22
+ t.string "type"
23
+ t.jsonb "specifics"
24
+ t.datetime "created_at", :null => false
25
+ t.datetime "updated_at", :null => false
26
+ end
27
+ end
@@ -1,18 +1,35 @@
1
1
  require 'rubygems'
2
2
  require 'bundler'
3
3
  require 'simplecov'
4
- require 'pry'
4
+ # require 'pry'
5
5
  require 'trax_model'
6
+ require 'active_record'
6
7
 
7
8
  SimpleCov.start do
8
9
  add_filter '/spec/'
9
10
  end
10
11
 
12
+ ENV["DB"] ||= "sqllite"
13
+ ENV["DB"] = "postgres" if ENV["DB"] == "pg" || ENV["pg"] == "true"
14
+
11
15
  RSpec.configure do |config|
16
+ config.filter_run_excluding :postgres => true unless ENV["DB"] == "postgres"
17
+
12
18
  config.before(:suite) do
19
+ db_config = ::YAML::load(::File.open("#{File.dirname(__FILE__)}/db/database.yml"))
20
+
21
+ ::ActiveRecord::Base.establish_connection(db_config[ENV["DB"]])
22
+
23
+ ::ActiveRecord::Base.connection.tables.each do |table|
24
+ ::ActiveRecord::Base.connection.drop_table(table)
25
+ end
26
+
27
+ ::Trax::Model.configure do |config|
28
+ config.auto_include = false
29
+ end
30
+
31
+ ::Dir["#{::File.dirname(__FILE__)}/support/*.rb"].each { |f| require f }
13
32
  end
14
33
  end
15
34
 
16
35
  Bundler.require(:default, :development, :test)
17
-
18
- ::Dir["#{::File.dirname(__FILE__)}/support/*.rb"].each {|f| require f }
@@ -0,0 +1,123 @@
1
+ require 'active_record'
2
+
3
+ ::ActiveRecord::Schema.define(:version => 1) do
4
+ require_relative '../db/schema/default_tables'
5
+ instance_eval(&DEFAULT_TABLES)
6
+
7
+ if ENV["DB"] == "postgres"
8
+ require_relative '../db/schema/pg_tables'
9
+ instance_eval(&PG_TABLES)
10
+ end
11
+ end
12
+
13
+ if ENV["DB"] == "postgres"
14
+ require_relative 'pg/models'
15
+ end
16
+
17
+ class Product < ::ActiveRecord::Base
18
+ include ::Trax::Model
19
+ include ::Trax::Model::Attributes::Mixin
20
+
21
+ mixins :unique_id => {
22
+ :uuid_column => "uuid",
23
+ :uuid_prefix => "1a"
24
+ }
25
+
26
+ define_attributes do
27
+ enum :status, :default => :in_stock do
28
+ define :in_stock, 1
29
+ define :out_of_stock, 2
30
+ define :backordered, 3
31
+ end
32
+
33
+ boolean :active, :default => false
34
+ end
35
+ end
36
+
37
+ module Products
38
+ class Shoes < Product
39
+ include ::Trax::Model
40
+ include ::Trax::Model::Attributes::Mixin
41
+ end
42
+
43
+ class MensShoes < Shoes
44
+ include ::Trax::Model
45
+ include ::Trax::Model::Attributes::Mixin
46
+
47
+ define_attributes do
48
+ enum :size, :default => :mens_9 do
49
+ define :mens_6, 1
50
+ define :mens_7, 2
51
+ define :mens_8, 3
52
+ define :mens_9, 4
53
+ define :mens_10, 5
54
+ define :mens_11, 6
55
+ define :mens_12, 7
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ class Widget < ::ActiveRecord::Base
62
+ include ::Trax::Model
63
+
64
+ mixins :unique_id => {
65
+ :uuid_column => "uuid",
66
+ :uuid_prefix => "2a"
67
+ }
68
+
69
+ validates :subdomain, :subdomain => true, :allow_nil => true
70
+ validates :email_address, :email => true, :allow_nil => true
71
+ validates :website, :url => true, :allow_nil => true
72
+ end
73
+
74
+ class Message < ::ActiveRecord::Base
75
+ include ::Trax::Model
76
+
77
+ mixins :unique_id => { :uuid_column => "uuid", :uuid_prefix => "3a" },
78
+ :freezable => true,
79
+ :restorable => { :field => :deleted }
80
+
81
+ enum :status => [ :queued, :scheduled, :delivered, :failed_delivery ]
82
+
83
+ default_value_for :status do
84
+ self.statuses[:queued]
85
+ end
86
+
87
+ validates :deliver_at, :future => true, :allow_nil => true
88
+
89
+ freezable_by_enum :status => [ :delivered, :failed_delivery ]
90
+ end
91
+
92
+ class Thing < ::ActiveRecord::Base
93
+ include ::Trax::Model
94
+
95
+ mixins :unique_id => { :uuid_column => "uuid", :uuid_prefix => "4a" }
96
+ end
97
+
98
+ class Person < ::ActiveRecord::Base
99
+ include ::Trax::Model
100
+
101
+ mixins :unique_id => { :uuid_column => "uuid", :uuid_prefix => "5a" }
102
+ end
103
+
104
+ class Stapler < ::ActiveRecord::Base
105
+ include ::Trax::Model
106
+ end
107
+
108
+ class SwinglineStapler < ::Stapler
109
+ include ::Trax::Model::STI::Attributes
110
+ end
111
+
112
+ class SwinglineStaplerAttributeSet < ::ActiveRecord::Base
113
+ end
114
+
115
+ require 'trax/model/struct'
116
+
117
+ class StoreCategory < ::Trax::Model::Struct
118
+ string :name
119
+ struct :meta_attributes do
120
+ string :description
121
+ string :keywords
122
+ end
123
+ end
@@ -0,0 +1,103 @@
1
+ module Ecommerce
2
+ class ProductAttributeSet < ::ActiveRecord::Base
3
+ self.table_name = "ecommerce_product_attribute_sets"
4
+
5
+ include ::Trax::Model
6
+ include ::Trax::Model::Attributes::Mixin
7
+
8
+ mixins :unique_id => { :uuid_prefix => "c2" }
9
+
10
+ belongs_to :user, :class_name => "Ecommerce::User"
11
+ belongs_to :product, :class_name => "Ecommerce::Product"
12
+ end
13
+
14
+ class ShippingAttributes < ::Ecommerce::ProductAttributeSet
15
+ include ::Trax::Model
16
+ include ::Trax::Model::Attributes::Mixin
17
+
18
+ define_attributes do
19
+ struct :specifics, :validate => true do
20
+ string :cost, :default => 0
21
+
22
+ validates(:cost, :length => {:minimum => 10})
23
+
24
+ enum :service do
25
+ define :usps, 1
26
+ define :fedex, 2
27
+ end
28
+
29
+ struct :dimensions, :validate => true do
30
+ string :length
31
+ string :width
32
+ string :height
33
+
34
+ validates(:length, :length => {:maximum => 10})
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ class Product < ::ActiveRecord::Base
41
+ self.table_name = "ecommerce_products"
42
+
43
+ include ::Trax::Model
44
+ include ::Trax::Model::Attributes::Mixin
45
+
46
+ mixins :unique_id => { :uuid_prefix => "9a" }
47
+
48
+ belongs_to :store, :class_name => "Ecommerce::Store"
49
+
50
+ define_attributes do
51
+ string :name, :default => "Whatever" do
52
+ validates(self, :length => { :minimum => 20 })
53
+ end
54
+ boolean :active, :default => true
55
+
56
+ enum :status, :default => :in_stock do
57
+ define :in_stock, 1
58
+ define :out_of_stock, 2
59
+ define :backordered, 3
60
+ end
61
+ end
62
+ end
63
+
64
+ module Products
65
+ class Shoes < ::Ecommerce::Product
66
+ include ::Trax::Model
67
+ include ::Trax::Model::Attributes::Mixin
68
+ end
69
+
70
+ class MensShoes < ::Ecommerce::Products::Shoes
71
+ include ::Trax::Model
72
+ include ::Trax::Model::Attributes::Mixin
73
+
74
+ define_attributes do
75
+ string :name, :default => "Some Shoe Name", :define_scopes => true
76
+ boolean :active, :default => true, :define_scopes => true
77
+
78
+ struct :custom_fields do
79
+ string :primary_utility, :default => "Skateboarding", :define_scopes => true
80
+ string :sole_material
81
+ boolean :has_shoelaces, :define_scopes => true
82
+
83
+ enum :color, :default => :blue, :define_scopes => false do
84
+ define :red, 1
85
+ define :blue, 2
86
+ define :green, 3
87
+ define :black, 4
88
+ end
89
+
90
+ enum :size, :default => :mens_9, :define_scopes => true do
91
+ define :mens_6, 1
92
+ define :mens_7, 2
93
+ define :mens_8, 3
94
+ define :mens_9, 4
95
+ define :mens_10, 5
96
+ define :mens_11, 6
97
+ define :mens_12, 7
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end