protobuf-activerecord 2.1.0 → 3.0.0.pre

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 (35) hide show
  1. checksums.yaml +6 -14
  2. data/Gemfile +0 -4
  3. data/lib/protobuf-activerecord.rb +26 -3
  4. data/lib/protobuf/active_record/attribute_methods.rb +35 -0
  5. data/lib/protobuf/active_record/columns.rb +74 -0
  6. data/lib/protobuf/active_record/config.rb +11 -0
  7. data/lib/protobuf/active_record/errors.rb +23 -0
  8. data/lib/protobuf/active_record/mass_assignment_security.rb +16 -0
  9. data/lib/protobuf/active_record/mass_assignment_security/persistence.rb +57 -0
  10. data/lib/protobuf/active_record/mass_assignment_security/transformation.rb +27 -0
  11. data/lib/protobuf/active_record/model.rb +32 -0
  12. data/lib/protobuf/active_record/persistence.rb +55 -0
  13. data/lib/protobuf/active_record/railtie.rb +11 -0
  14. data/lib/protobuf/active_record/scope.rb +121 -0
  15. data/lib/protobuf/active_record/serialization.rb +194 -0
  16. data/lib/protobuf/active_record/transformation.rb +155 -0
  17. data/lib/protobuf/active_record/validations.rb +43 -0
  18. data/lib/protobuf/{activerecord → active_record}/version.rb +1 -1
  19. data/protobuf-activerecord.gemspec +4 -5
  20. data/spec/{protoable → protobuf/active_record}/columns_spec.rb +2 -2
  21. data/spec/{protoable → protobuf/active_record}/persistence_spec.rb +1 -1
  22. data/spec/{protoable → protobuf/active_record}/scope_spec.rb +1 -8
  23. data/spec/{protoable → protobuf/active_record}/serialization_spec.rb +2 -2
  24. data/spec/{protoable → protobuf/active_record}/transformation_spec.rb +12 -12
  25. data/spec/support/models/user.rb +1 -1
  26. metadata +59 -68
  27. data/lib/protobuf/activerecord/protoable.rb +0 -19
  28. data/lib/protobuf/activerecord/protoable/columns.rb +0 -56
  29. data/lib/protobuf/activerecord/protoable/errors.rb +0 -22
  30. data/lib/protobuf/activerecord/protoable/persistence.rb +0 -56
  31. data/lib/protobuf/activerecord/protoable/scope.rb +0 -121
  32. data/lib/protobuf/activerecord/protoable/serialization.rb +0 -190
  33. data/lib/protobuf/activerecord/protoable/transformation.rb +0 -158
  34. data/lib/protobuf/activerecord/protoable/validations.rb +0 -39
  35. data/lib/protobuf/activerecord/protobuf_ext/message.rb +0 -16
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- OWVlMmI0NmI3ODc3MjI1NDk3NTUyMDhlODIyZDE0ODg3NGNmODlhZQ==
5
- data.tar.gz: !binary |-
6
- NjEwNzFlMTAyZGE1Yzk5NGZjNDVjZmJlYmU5ODExYjFkNWIwMTVjOA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NzkzN2ZkMGY3YzdiN2NlZjAwZTAwZjMzZDc0NTQzMjMwNzgzOWY2NDg1MWQ5
10
- YzBhZTI3ZmFjMGIzOWRlYjgxMmRhN2Y1NDZlNGE4MzI5OTY3NWVjZjljNzc1
11
- NjU4MjUxZjRlNGE5NmI3MzMzMzc0YWM1YTRmYTQxMDQwYTMzMDA=
12
- data.tar.gz: !binary |-
13
- ZmY0YWY3OGRkNTdkNzAwYzQ1YTkzZjVhZjk5ZDAwMGUzMDdkNjUyNGY2MzBk
14
- ODY4ZGZlYWQ2NmFmOGQyNjdiZjY4MmI4NDI1YWZhNzEzY2MwYWQyZWFkZGUx
15
- OWM0NDc5MWRmYjhhYjYwMGQ4YzE5NzE4ZjgzNjkxNDY4NGFjOTM=
2
+ SHA1:
3
+ metadata.gz: 222a25f863e0432deaee84af24cdb1afcf54d470
4
+ data.tar.gz: 2db3c1dce2882e7495cfe2d7b3eed18f01677b19
5
+ SHA512:
6
+ metadata.gz: 96dd33216999495aca093656d30918711af9c1641e4476ea028b929ba162607510ce0d36253762821e4b48c210c4834188166a3c12e9b7d0a77a6ef58045bdf4
7
+ data.tar.gz: c0ef76053aff3bcdbf00a3a8d9bb894367491c753a4e583799fef3d1a2d928445306cb898b1cd6b9d1d94ae8795050c016958ad9f262f8419c2671e173f027f0
data/Gemfile CHANGED
@@ -2,7 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in protobuf-activerecord.gemspec
4
4
  gemspec
5
-
6
- gem 'builder', '~> 3.0.4' # Builder 3.1.x is not supported by Active Record
7
- # and Bundler has trouble resolving the dependency
8
- # with Geminabox.
@@ -3,6 +3,29 @@ require 'active_support/concern'
3
3
  require 'heredity'
4
4
  require 'protobuf'
5
5
 
6
- require 'protobuf/activerecord/version'
7
- require 'protobuf/activerecord/protobuf_ext/message'
8
- require 'protobuf/activerecord/protoable'
6
+ require 'protobuf/active_record/config'
7
+ require 'protobuf/active_record/model'
8
+ require 'protobuf/active_record/version'
9
+
10
+ module Protobuf
11
+ module ActiveRecord
12
+ module LoadHooks
13
+ def inherited(klass)
14
+ super
15
+
16
+ klass.class_eval do
17
+ include Protobuf::ActiveRecord::Model
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.config
23
+ @config ||= Protobuf::ActiveRecord::Config.new
24
+ end
25
+
26
+ # Initialize the config
27
+ config
28
+ end
29
+ end
30
+
31
+ require 'protobuf/active_record/railtie' if defined?(Rails)
@@ -0,0 +1,35 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module AttributeMethods
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ def alias_field(field_alias, attribute)
10
+ alias_attribute field_alias, attribute
11
+
12
+ attribute_from_proto attribute, fetch_attribute_alias_from_proto(attribute, field_alias)
13
+ field_from_record field_alias, fetch_field_alias_from_record(attribute, field_alias)
14
+ end
15
+
16
+ def fetch_attribute_alias_from_proto(attribute, field_alias)
17
+ lambda do |proto|
18
+ value = proto.__send__(:"#{field_alias}!")
19
+ value ||= proto.__send__(:"#{attribute}!") if proto.respond_to?(attribute)
20
+
21
+ self._protobuf_convert_fields_to_attributes(attribute, value)
22
+ end
23
+ end
24
+
25
+ def fetch_field_alias_from_record(attribute, field_aliasd)
26
+ lambda do |record|
27
+ value = record.__send__(field_alias)
28
+
29
+ self._protobuf_convert_attributes_to_fields(attribute, value)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,74 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module Columns
6
+ extend ::ActiveSupport::Concern
7
+
8
+ included do
9
+ include ::Heredity
10
+
11
+ inheritable_attributes :_protobuf_columns,
12
+ :_protobuf_column_types,
13
+ :_protobuf_mapped_columns
14
+ end
15
+
16
+ module ClassMethods
17
+ def _protobuf_columns
18
+ _protobuf_map_columns unless _protobuf_mapped_columns?
19
+
20
+ @_protobuf_columns
21
+ end
22
+
23
+ def _protobuf_column_types
24
+ _protobuf_map_columns unless _protobuf_mapped_columns?
25
+
26
+ @_protobuf_column_types
27
+ end
28
+
29
+ # :nodoc:
30
+ def _protobuf_date_column?(key)
31
+ _protobuf_column_types.fetch(:date, false) && _protobuf_column_types[:date].include?(key)
32
+ end
33
+
34
+ # :nodoc:
35
+ def _protobuf_datetime_column?(key)
36
+ _protobuf_column_types.fetch(:datetime, false) && _protobuf_column_types[:datetime].include?(key)
37
+ end
38
+
39
+ # Map out the columns for future reference on type conversion
40
+ # :nodoc:
41
+ def _protobuf_map_columns(force = false)
42
+ return unless table_exists?
43
+
44
+ @_protobuf_mapped_columns = false if force
45
+ return if _protobuf_mapped_columns?
46
+
47
+ @_protobuf_columns = {}
48
+ @_protobuf_column_types = Hash.new { |h,k| h[k] = [] }
49
+
50
+ columns.map do |column|
51
+ @_protobuf_columns[column.name.to_sym] = column
52
+ @_protobuf_column_types[column.type.to_sym] << column.name.to_sym
53
+ end
54
+
55
+ @_protobuf_mapped_columns = true
56
+ end
57
+
58
+ def _protobuf_mapped_columns?
59
+ @_protobuf_mapped_columns
60
+ end
61
+
62
+ # :nodoc:
63
+ def _protobuf_time_column?(key)
64
+ _protobuf_column_types.fetch(:time, false) && _protobuf_column_types[:time].include?(key)
65
+ end
66
+
67
+ # :nodoc:
68
+ def _protobuf_timestamp_column?(key)
69
+ _protobuf_column_types.fetch(:timestamp, false) && _protobuf_column_types[:timestamp].include?(key)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,11 @@
1
+ module Protobuf
2
+ module ActiveRecord
3
+ class Config < ActiveSupport::OrderedOptions
4
+ def initialize(options = {})
5
+ super
6
+
7
+ self[:autoload] = true
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module Protobuf
2
+ module ActiveRecord
3
+ # = Protobuf Active Record errors
4
+ #
5
+ # Generic Protobuf Active Record exception class
6
+ class ProtobufActiveRecordError < StandardError
7
+ end
8
+
9
+ # Raised by `attribute_from_proto` when the transformer method
10
+ # given is not callable.
11
+ class AttributeTransformerError < ProtobufActiveRecordError
12
+ end
13
+
14
+ # Raised by `field_from_record` when the convert method
15
+ # given not callable.
16
+ class FieldTransformerError < ProtobufActiveRecordError
17
+ end
18
+
19
+ # Raised by `field_scope` when given scope is not defined.
20
+ class SearchScopeError < ProtobufActiveRecordError
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_support/concern'
2
+ require 'protobuf/active_record/mass_assignment_security/persistence'
3
+ require 'protobuf/active_record/mass_assignment_security/transformation'
4
+
5
+ module Protobuf
6
+ module ActiveRecord
7
+ module MassAssignmentSecurity
8
+ extend ::ActiveSupport::Concern
9
+
10
+ included do
11
+ include Protobuf::ActiveRecord::MassAssignmentSecurity::Persistence
12
+ include Protobuf::ActiveRecord::MassAssignmentSecurity::Transformation
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module MassAssignmentSecurity
6
+ module Persistence
7
+ extend ::ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # :nodoc:
11
+ def create(attributes, options = {}, &block)
12
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
13
+
14
+ super(attributes, options)
15
+ end
16
+
17
+ # :nodoc:
18
+ def create!(attributes, options = {}, &block)
19
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
20
+
21
+ super(attributes, options)
22
+ end
23
+ end
24
+
25
+ # :nodoc:
26
+ def assign_attributes(attributes, options = {})
27
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
28
+
29
+ super(attributes, options)
30
+ end
31
+
32
+ # :nodoc:
33
+ def update_attributes(attributes, options = {})
34
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
35
+
36
+ super(attributes, options)
37
+ end
38
+
39
+ # :nodoc:
40
+ def update_attributes!(attributes, options = {})
41
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
42
+
43
+ super(attributes, options)
44
+ end
45
+ end
46
+
47
+ # Override Active Record's initialize method so it can accept a protobuf
48
+ # message as it's attributes.
49
+ # :noapi:
50
+ def initialize(*args, &block)
51
+ args[0] = attributes_from_proto(args.first) if args.first.is_a?(::Protobuf::Message)
52
+
53
+ super(*args, &block)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module MassAssignmentSecurity
6
+ module Transformation
7
+ extend ::ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ # Filters protected attributes from the available attributes list. When
11
+ # set through accessible attributes, returns the accessible attributes.
12
+ # When set through protected attributes, returns the attributes minus any
13
+ # protected attributes.
14
+ #
15
+ # :nodoc:
16
+ def _filtered_attributes
17
+ if accessible_attributes.present?
18
+ accessible_attributes.to_a
19
+ else
20
+ self.attribute_names - protected_attributes.to_a
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ require 'protobuf/active_record/attribute_methods'
2
+ require 'protobuf/active_record/columns'
3
+ require 'protobuf/active_record/errors'
4
+ require 'protobuf/active_record/mass_assignment_security'
5
+ require 'protobuf/active_record/persistence'
6
+ require 'protobuf/active_record/scope'
7
+ require 'protobuf/active_record/serialization'
8
+ require 'protobuf/active_record/transformation'
9
+ require 'protobuf/active_record/validations'
10
+
11
+ module Protobuf
12
+ module ActiveRecord
13
+ module Model
14
+ extend ::ActiveSupport::Concern
15
+
16
+ included do
17
+ include Protobuf::ActiveRecord::AttributeMethods
18
+ include Protobuf::ActiveRecord::Columns
19
+ include Protobuf::ActiveRecord::Serialization
20
+ include Protobuf::ActiveRecord::Scope
21
+ include Protobuf::ActiveRecord::Transformation
22
+ include Protobuf::ActiveRecord::Validations
23
+
24
+ if defined?(::ActiveModel::MassAssignmentSecurity)
25
+ include Protobuf::ActiveRecord::MassAssignmentSecurity
26
+ else
27
+ include Protobuf::ActiveRecord::Persistence
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,55 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module Persistence
6
+ extend ::ActiveSupport::Concern
7
+
8
+ module ClassMethods
9
+ # :nodoc:
10
+ def create(attributes = {}, &block)
11
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
12
+
13
+ super(attributes, &block)
14
+ end
15
+
16
+ # :nodoc:
17
+ def create!(attributes = {}, &block)
18
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
19
+
20
+ super(attributes, &block)
21
+ end
22
+ end
23
+
24
+ # Override Active Record's initialize method so it can accept a protobuf
25
+ # message as it's attributes.
26
+ # :noapi:
27
+ def initialize(*args, &block)
28
+ args[0] = attributes_from_proto(args.first) if args.first.is_a?(::Protobuf::Message)
29
+
30
+ super(*args, &block)
31
+ end
32
+
33
+ # :nodoc:
34
+ def assign_attributes(attributes)
35
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
36
+
37
+ super(attributes)
38
+ end
39
+
40
+ # :nodoc:
41
+ def update_attributes(attributes)
42
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
43
+
44
+ super(attributes)
45
+ end
46
+
47
+ # :nodoc:
48
+ def update_attributes!(attributes)
49
+ attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
50
+
51
+ super(attributes)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,11 @@
1
+ module Protobuf
2
+ module ActiveRecord
3
+ class Railtie < Rails::Railtie
4
+ config.protobuf_active_record = Protobuf::ActiveRecord.config
5
+
6
+ ActiveSupport.on_load(:active_record) do
7
+ extend Protobuf::ActiveRecord::LoadHooks if Protobuf::ActiveRecord.config.autoload
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,121 @@
1
+ require 'active_support/concern'
2
+
3
+ module Protobuf
4
+ module ActiveRecord
5
+ module Scope
6
+ extend ::ActiveSupport::Concern
7
+
8
+ included do
9
+ class << self
10
+ alias_method :by_fields, :search_scope
11
+ alias_method :scope_from_proto, :search_scope
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ # Define fields that should be searchable via `search_scope`. Accepts a
17
+ # protobuf field and an already defined scope. If no scope is specified,
18
+ # the scope will be the field name, prefixed with `by_` (e.g. when the
19
+ # field is :guid, the scope will be :by_guid).
20
+ #
21
+ # Optionally, a parser can be provided that will be called, passing the
22
+ # field value as an argument. This allows custom data parsers to be used
23
+ # so that they don't have to be handled by scopes. Parsers can be procs,
24
+ # lambdas, or symbolized method names and must accept the value of the
25
+ # field as a parameter.
26
+ #
27
+ # Examples:
28
+ #
29
+ # class User < ActiveRecord::Base
30
+ # scope :by_guid, lambda { |*guids| where(:guid => guids) }
31
+ # scope :custom_guid_scope, lambda { |*guids| where(:guid => guids) }
32
+ #
33
+ # # Equivalent to `field_scope :guid, :by_guid`
34
+ # field_scope :guid
35
+ #
36
+ # # With a custom scope
37
+ # field_scope :guid, :scope => :custom_guid_scope
38
+ #
39
+ # # With a custom parser that converts the value to an integer
40
+ # field_scope :guid, :scope => :custom_guid_scope, :parser => lambda { |value| value.to_i }
41
+ # end
42
+ #
43
+ def field_scope(field, options = {})
44
+ scope_name = if options.include?(:scope)
45
+ options[:scope]
46
+ else
47
+ # When no scope is defined, assume the scope is the field, prefixed with `by_`
48
+ :"by_#{field}"
49
+ end
50
+ searchable_fields[field] = scope_name
51
+
52
+ searchable_field_parsers[field] = options[:parser] if options[:parser]
53
+ end
54
+
55
+ # Get an ARel relation to build off of. If we're in Rails 4 we need to
56
+ # use `all` instead of `scoped`.
57
+ # :noapi:
58
+ def model_scope
59
+ ::ActiveRecord::VERSION::MAJOR >= 4 ? all : scoped
60
+ end
61
+
62
+ # :noapi:
63
+ def parse_search_values(proto, field)
64
+ value = proto.__send__(field)
65
+
66
+ if searchable_field_parsers[field]
67
+ parser = searchable_field_parsers[field]
68
+
69
+ if parser.respond_to?(:to_sym)
70
+ value = self.__send__(parser.to_sym, value)
71
+ else
72
+ value = parser.call(value)
73
+ end
74
+ end
75
+
76
+ values = [ value ].flatten
77
+ values.map!(&:to_i) if proto.get_field_by_name(field).enum?
78
+ values
79
+ end
80
+
81
+ # Builds and returns a Arel relation based on the fields that are present
82
+ # in the given protobuf message using the searchable fields to determine
83
+ # what scopes to use. Provides several aliases for variety.
84
+ #
85
+ # Examples:
86
+ #
87
+ # # Search starting with the default scope and searchable fields
88
+ # User.search_scope(request)
89
+ # User.by_fields(request)
90
+ # User.scope_from_proto(request)
91
+ #
92
+ def search_scope(proto)
93
+ search_relation = model_scope
94
+
95
+ searchable_fields.each do |field, scope_name|
96
+ next unless proto.respond_to_and_has_and_present?(field)
97
+
98
+ unless self.respond_to?(scope_name)
99
+ raise Protobuf::ActiveRecord::SearchScopeError, "Undefined scope :#{scope_name}."
100
+ end
101
+
102
+ search_values = parse_search_values(proto, field)
103
+ search_relation = search_relation.__send__(scope_name, *search_values)
104
+ end
105
+
106
+ return search_relation
107
+ end
108
+
109
+ # :noapi:
110
+ def searchable_fields
111
+ @_searchable_fields ||= {}
112
+ end
113
+
114
+ # :noapi:
115
+ def searchable_field_parsers
116
+ @_searchable_field_parsers ||= {}
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end