protobuf-activerecord 2.1.0 → 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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