protobuf-mongoid 0.0.1
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 +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +59 -0
- data/lib/protobuf/mongoid/attribute_methods.rb +33 -0
- data/lib/protobuf/mongoid/errors.rb +50 -0
- data/lib/protobuf/mongoid/fields.rb +110 -0
- data/lib/protobuf/mongoid/model.rb +31 -0
- data/lib/protobuf/mongoid/nested_attributes.rb +60 -0
- data/lib/protobuf/mongoid/persistence.rb +58 -0
- data/lib/protobuf/mongoid/scope.rb +201 -0
- data/lib/protobuf/mongoid/serialization.rb +285 -0
- data/lib/protobuf/mongoid/transformation.rb +193 -0
- data/lib/protobuf/mongoid/transformer.rb +29 -0
- data/lib/protobuf/mongoid/validations.rb +45 -0
- data/lib/protobuf/mongoid/version.rb +7 -0
- data/lib/protobuf/mongoid.rb +13 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1dc8ea63ac8607eb6435e75b8638ff4cf5735c8a0f4d2fdd6df9d72cf2c78c4b
|
4
|
+
data.tar.gz: d6769b7aeaf095e6aa1b68444feea2c073e528b588f64dfc42a7cd2b57c14db2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b2edf7540ddebb909650e1741fd09b85d5fe517f1768364ffebd04f58929dcbcc2ceef2888f0ae4306a7ef892df87cbf9159ae98e44a1f6f66f0f0808ac9e3bb
|
7
|
+
data.tar.gz: af66b0131bb5e401620b5526ee21831f21c854a33c964c7bcfa64dc9875409a490fe9e22cf7cee0247ee5f0b3affbadec9e8e54f68b797bf3a573baeebe9a15a
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Luilver Garces
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# protobuf-mongoid
|
2
|
+
|
3
|
+
protobuf-mongoid is a Ruby gem that integrates Protocol Buffers with Mongoid, allowing for efficient serialization and deserialization of Mongoid documents using Protocol Buffers.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'protobuf-mongoid'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```
|
16
|
+
bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```
|
22
|
+
gem install protobuf-mongoid
|
23
|
+
```
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
To use protobuf-mongoid, include the necessary modules in your Mongoid models. Here is a basic example:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
class User
|
31
|
+
include Mongoid::Document
|
32
|
+
include Protobuf::Mongoid
|
33
|
+
|
34
|
+
field :name, type: String
|
35
|
+
field :email, type: String
|
36
|
+
|
37
|
+
# Define your Protocol Buffers message here
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
### Tests
|
42
|
+
|
43
|
+
To test protobuf-mongoid, run:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
rake
|
47
|
+
```
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it ( https://github.com/luilver/protobuf-mongoid/fork )
|
52
|
+
2. Create your feature branch (git checkout -b feature/my-new-feature)
|
53
|
+
3. Commit your changes (git commit -am 'Add some feature')
|
54
|
+
4. Push to the branch (git push origin feature/my-new-feature)
|
55
|
+
5. Create a new Pull Request
|
56
|
+
|
57
|
+
## License
|
58
|
+
|
59
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE.txt) file for details.
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Mongoid
|
3
|
+
module AttributeMethods
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def alias_field(field_alias, attribute)
|
8
|
+
alias_attribute field_alias, attribute
|
9
|
+
|
10
|
+
attribute_from_proto attribute, fetch_attribute_alias_from_proto(attribute, field_alias)
|
11
|
+
field_from_document field_alias, fetch_field_alias_from_document(attribute, field_alias)
|
12
|
+
end
|
13
|
+
|
14
|
+
def fetch_attribute_alias_from_proto(attribute, field_alias)
|
15
|
+
lambda do |proto|
|
16
|
+
value = proto.__send__(:"#{field_alias}!")
|
17
|
+
value ||= proto.__send__(:"#{attribute}!") if proto.respond_to?(attribute)
|
18
|
+
|
19
|
+
self._protobuf_convert_fields_to_attributes(attribute, value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def fetch_field_alias_from_document(attribute, _field_aliasd)
|
24
|
+
lambda do |document|
|
25
|
+
value = document.__send__(field_alias)
|
26
|
+
|
27
|
+
self._protobuf_convert_attributes_to_fields(attribute, value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Mongoid
|
3
|
+
# = Protobuf Mongoid errors
|
4
|
+
#
|
5
|
+
# Generic Protobuf Mongoid exception class
|
6
|
+
class ProtobufMongoidError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# Raised by `attribute_from_proto` when the transformer method
|
10
|
+
# given is not callable.
|
11
|
+
class AttributeTransformerError < ProtobufMongoidError
|
12
|
+
def message
|
13
|
+
"Attribute transformers must be called with a callable or block!"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised by `field_from_document` when the convert method
|
18
|
+
# given not callable.
|
19
|
+
class FieldTransformerError < ProtobufMongoidError
|
20
|
+
def message
|
21
|
+
"Field transformers must be called with a callable or block!"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Raised by `to_proto` when no protobuf message is defined.
|
26
|
+
class MessageNotDefined < ProtobufMongoidError
|
27
|
+
attr_reader :class_name
|
28
|
+
|
29
|
+
def initialize(klass)
|
30
|
+
@class_name = klass.name
|
31
|
+
end
|
32
|
+
|
33
|
+
def message
|
34
|
+
"#{class_name} does not define a protobuf message"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Raised by `field_scope` when given scope is not defined.
|
39
|
+
class SearchScopeError < ProtobufMongoidError
|
40
|
+
end
|
41
|
+
|
42
|
+
# Raised by `upsert_scope` when a given scope is not defined
|
43
|
+
class UpsertScopeError < ProtobufMongoidError
|
44
|
+
end
|
45
|
+
|
46
|
+
# Raised by `for_upsert` when no valid upsert_scopes are found
|
47
|
+
class UpsertNotFoundError < ProtobufMongoidError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# A key-value pair within a document
|
6
|
+
module Fields
|
7
|
+
include ::Heredity
|
8
|
+
extend ::ActiveSupport::Concern
|
9
|
+
|
10
|
+
FIELD_TYPE_MAP_MUTEX = ::Mutex.new
|
11
|
+
DATE_OR_TIME_TYPES = ::Set.new(%i[date datetime time timestamp])
|
12
|
+
|
13
|
+
inheritable_attributes :_protobuf_fields,
|
14
|
+
:_protobuf_field_types,
|
15
|
+
:_protobuf_date_datetime_time_or_timestamp_field,
|
16
|
+
:_protobuf_mapped_fields
|
17
|
+
|
18
|
+
##
|
19
|
+
# Class Methods
|
20
|
+
#
|
21
|
+
module ClassMethods
|
22
|
+
def _protobuf_fields
|
23
|
+
_protobuf_map_fields unless _protobuf_mapped_fields?
|
24
|
+
|
25
|
+
@_protobuf_fields
|
26
|
+
end
|
27
|
+
|
28
|
+
def _protobuf_field_types
|
29
|
+
_protobuf_map_fields unless _protobuf_mapped_fields?
|
30
|
+
|
31
|
+
@_protobuf_field_types
|
32
|
+
end
|
33
|
+
|
34
|
+
def _protobuf_date_datetime_time_or_timestamp_field
|
35
|
+
_protobuf_map_fields unless _protobuf_mapped_fields?
|
36
|
+
|
37
|
+
@_protobuf_date_datetime_time_or_timestamp_field
|
38
|
+
end
|
39
|
+
|
40
|
+
# :nodoc:
|
41
|
+
def _protobuf_date_field?(key)
|
42
|
+
_protobuf_field_types[:date].include?(key)
|
43
|
+
end
|
44
|
+
|
45
|
+
# :nodoc:
|
46
|
+
def _protobuf_date_datetime_time_or_timestamp_field?(key)
|
47
|
+
_protobuf_date_datetime_time_or_timestamp_field.include?(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
# :nodoc:
|
51
|
+
def _protobuf_datetime_field?(key)
|
52
|
+
_protobuf_field_types[:datetime].include?(key)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Map out the fields for future reference on type conversion
|
56
|
+
# :nodoc:
|
57
|
+
# TODO: Check if collection exists
|
58
|
+
# collection_exists? is not a Mongoid method. We need to check $exists?
|
59
|
+
# return unless collection_exists?
|
60
|
+
def _protobuf_map_fields(force = false)
|
61
|
+
FIELD_TYPE_MAP_MUTEX.synchronize do
|
62
|
+
@_protobuf_mapped_fields = false if force
|
63
|
+
return if _protobuf_mapped_fields?
|
64
|
+
|
65
|
+
initialize_protobuf_field_containers
|
66
|
+
map_protobuf_fields
|
67
|
+
|
68
|
+
@_protobuf_mapped_fields = true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def _protobuf_mapped_fields?
|
73
|
+
@_protobuf_mapped_fields
|
74
|
+
end
|
75
|
+
|
76
|
+
# :nodoc:
|
77
|
+
def _protobuf_time_field?(key)
|
78
|
+
_protobuf_field_types[:time].include?(key)
|
79
|
+
end
|
80
|
+
|
81
|
+
# :nodoc:
|
82
|
+
def _protobuf_timestamp_field?(key)
|
83
|
+
_protobuf_field_types[:timestamp].include?(key)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def initialize_protobuf_field_containers
|
89
|
+
@_protobuf_fields = {}
|
90
|
+
@_protobuf_field_types = ::Hash.new { |h, k| h[k] = ::Set.new }
|
91
|
+
@_protobuf_date_datetime_time_or_timestamp_field = ::Set.new
|
92
|
+
end
|
93
|
+
|
94
|
+
def map_protobuf_fields
|
95
|
+
fields.each do |field|
|
96
|
+
field_name_symbol = field[0].to_sym
|
97
|
+
field_type_symbol = field[1].options[:type].to_s.to_sym
|
98
|
+
|
99
|
+
@_protobuf_fields[field_name_symbol] = field
|
100
|
+
@_protobuf_field_types[field_type_symbol] << field_name_symbol
|
101
|
+
|
102
|
+
if DATE_OR_TIME_TYPES.include?(field_type_symbol)
|
103
|
+
@_protobuf_date_datetime_time_or_timestamp_field << field_name_symbol
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'protobuf/mongoid/attribute_methods'
|
4
|
+
require 'protobuf/mongoid/errors'
|
5
|
+
require 'protobuf/mongoid/fields'
|
6
|
+
require 'protobuf/mongoid/nested_attributes'
|
7
|
+
require 'protobuf/mongoid/persistence'
|
8
|
+
require 'protobuf/mongoid/scope'
|
9
|
+
require 'protobuf/mongoid/serialization'
|
10
|
+
require 'protobuf/mongoid/transformation'
|
11
|
+
require 'protobuf/mongoid/validations'
|
12
|
+
|
13
|
+
module Protobuf
|
14
|
+
module Mongoid
|
15
|
+
# Base for Protobuf-Mongoid models
|
16
|
+
module Model
|
17
|
+
extend ::ActiveSupport::Concern
|
18
|
+
|
19
|
+
included do
|
20
|
+
include Protobuf::Mongoid::AttributeMethods
|
21
|
+
include Protobuf::Mongoid::Fields
|
22
|
+
include Protobuf::Mongoid::NestedAttributes
|
23
|
+
include Protobuf::Mongoid::Persistence
|
24
|
+
include Protobuf::Mongoid::Serialization
|
25
|
+
include Protobuf::Mongoid::Scope
|
26
|
+
include Protobuf::Mongoid::Transformation
|
27
|
+
include Protobuf::Mongoid::Validations
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# Nested Attributes
|
6
|
+
module NestedAttributes
|
7
|
+
extend ::ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
include ::Heredity::InheritableClassInstanceVariables
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :_protobuf_nested_attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
@_protobuf_nested_attributes = []
|
17
|
+
|
18
|
+
inheritable_attributes :_protobuf_nested_attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# Class Methods
|
23
|
+
#
|
24
|
+
module ClassMethods
|
25
|
+
# :nodoc:
|
26
|
+
def accepts_nested_attributes_for(*attr_names)
|
27
|
+
attribute_names = attr_names.dup
|
28
|
+
attribute_names.extract_options!
|
29
|
+
attribute_names.map!(&:to_s)
|
30
|
+
|
31
|
+
super
|
32
|
+
|
33
|
+
self._protobuf_nested_attributes += attribute_names
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# :nodoc:
|
38
|
+
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
|
39
|
+
if attributes_collection.first.is_a?(::Protobuf::Message)
|
40
|
+
reflection = self.class._reflect_on_association(association_name)
|
41
|
+
attributes_collection = attributes_collection.map do |attributes|
|
42
|
+
reflection.klass.attributes_from_proto(attributes)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
super(association_name, attributes_collection)
|
47
|
+
end
|
48
|
+
|
49
|
+
# :nodoc:
|
50
|
+
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
|
51
|
+
if attributes.is_a?(::Protobuf::Message)
|
52
|
+
reflection = self.class._reflect_on_association(association_name)
|
53
|
+
attributes = reflection.klass.attributes_from_proto(attributes)
|
54
|
+
end
|
55
|
+
|
56
|
+
super(association_name, attributes)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# Persistence methods
|
6
|
+
module Persistence
|
7
|
+
extend ::ActiveSupport::Concern
|
8
|
+
|
9
|
+
##
|
10
|
+
# Class Methods
|
11
|
+
#
|
12
|
+
module ClassMethods
|
13
|
+
# :nodoc:
|
14
|
+
def create(attributes = {}, &block)
|
15
|
+
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
16
|
+
|
17
|
+
super(attributes, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
# :nodoc:
|
21
|
+
def create!(attributes = {}, &block)
|
22
|
+
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
23
|
+
|
24
|
+
super(attributes, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Override Mongoid's initialize method so it can accept a protobuf
|
29
|
+
# message as it's attributes.
|
30
|
+
# :noapi:
|
31
|
+
def initialize(*args, &block)
|
32
|
+
args[0] = attributes_from_proto(args.first) if args.first.is_a?(::Protobuf::Message)
|
33
|
+
super(*args, &block)
|
34
|
+
end
|
35
|
+
|
36
|
+
# :nodoc:
|
37
|
+
def assign_attributes(attributes)
|
38
|
+
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
39
|
+
|
40
|
+
super(attributes)
|
41
|
+
end
|
42
|
+
|
43
|
+
# :nodoc:
|
44
|
+
def update(attributes)
|
45
|
+
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
46
|
+
|
47
|
+
super(attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
# :nodoc:
|
51
|
+
def update!(attributes)
|
52
|
+
attributes = attributes_from_proto(attributes) if attributes.is_a?(::Protobuf::Message)
|
53
|
+
|
54
|
+
super(attributes)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Protobuf
|
6
|
+
module Mongoid
|
7
|
+
# Scope methods
|
8
|
+
module Scope
|
9
|
+
extend ::ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
class << self
|
13
|
+
alias_method :by_fields, :search_scope
|
14
|
+
alias_method :scope_from_proto, :search_scope
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Class Methods
|
20
|
+
#
|
21
|
+
module ClassMethods
|
22
|
+
# Define fields that should be searchable via `search_scope`. Accepts a
|
23
|
+
# protobuf field and an already defined scope. If no scope is specified,
|
24
|
+
# the scope will be the field name, prefixed with `by_` (e.g. when the
|
25
|
+
# field is :guid, the scope will be :by_guid).
|
26
|
+
#
|
27
|
+
# Optionally, a parser can be provided that will be called, passing the
|
28
|
+
# field value as an argument. This allows custom data parsers to be used
|
29
|
+
# so that they don't have to be handled by scopes. Parsers can be procs,
|
30
|
+
# lambdas, or symbolized method names and must accept the value of the
|
31
|
+
# field as a parameter.
|
32
|
+
#
|
33
|
+
# Examples:
|
34
|
+
#
|
35
|
+
# class User
|
36
|
+
# include Mongoid::Base
|
37
|
+
#
|
38
|
+
# scope :by_guid, lambda { |*guids| where(:guid => guids) }
|
39
|
+
# scope :custom_guid_scope, lambda { |*guids| where(:guid => guids) }
|
40
|
+
#
|
41
|
+
# # Equivalent to `field_scope :guid, :by_guid`
|
42
|
+
# field_scope :guid
|
43
|
+
#
|
44
|
+
# # With a custom scope
|
45
|
+
# field_scope :guid, :scope => :custom_guid_scope
|
46
|
+
#
|
47
|
+
# # With a custom parser that converts the value to an integer
|
48
|
+
# field_scope :guid, :scope => :custom_guid_scope, :parser => lambda { |value| value.to_i }
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
def field_scope(field, options = {})
|
52
|
+
scope_name = if options.include?(:scope)
|
53
|
+
options[:scope]
|
54
|
+
else
|
55
|
+
# When no scope is defined, assume the scope is the field, prefixed with `by_`
|
56
|
+
:"by_#{field}"
|
57
|
+
end
|
58
|
+
searchable_fields[field] = scope_name
|
59
|
+
|
60
|
+
searchable_field_parsers[field] = options[:parser] if options[:parser]
|
61
|
+
end
|
62
|
+
|
63
|
+
# :noapi:
|
64
|
+
def model_scope
|
65
|
+
all
|
66
|
+
end
|
67
|
+
|
68
|
+
# :noapi:
|
69
|
+
def parse_search_values(proto, field)
|
70
|
+
value = proto.__send__(field)
|
71
|
+
|
72
|
+
if searchable_field_parsers[field]
|
73
|
+
parser = searchable_field_parsers[field]
|
74
|
+
|
75
|
+
if parser.respond_to?(:to_sym)
|
76
|
+
value = self.__send__(parser.to_sym, value)
|
77
|
+
else
|
78
|
+
value = parser.call(value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
values = [value].flatten
|
83
|
+
values.map!(&:to_i) if proto.class.get_field(field, true).enum?
|
84
|
+
values
|
85
|
+
end
|
86
|
+
|
87
|
+
# Builds and returns a Arel relation based on the fields that are present
|
88
|
+
# in the given protobuf message using the searchable fields to determine
|
89
|
+
# what scopes to use. Provides several aliases for variety.
|
90
|
+
#
|
91
|
+
# Examples:
|
92
|
+
#
|
93
|
+
# # Search starting with the default scope and searchable fields
|
94
|
+
# User.search_scope(request)
|
95
|
+
# User.by_fields(request)
|
96
|
+
# User.scope_from_proto(request)
|
97
|
+
#
|
98
|
+
def search_scope(proto)
|
99
|
+
search_relation = model_scope
|
100
|
+
|
101
|
+
searchable_fields.each do |field, scope_name|
|
102
|
+
next unless proto.respond_to_and_has_and_present?(field)
|
103
|
+
|
104
|
+
search_values = parse_search_values(proto, field)
|
105
|
+
search_relation = search_relation.__send__(scope_name, *search_values)
|
106
|
+
end
|
107
|
+
|
108
|
+
search_relation
|
109
|
+
end
|
110
|
+
|
111
|
+
# :noapi:
|
112
|
+
def searchable_fields
|
113
|
+
@_searchable_fields ||= {}
|
114
|
+
end
|
115
|
+
|
116
|
+
# :noapi:
|
117
|
+
def searchable_field_parsers
|
118
|
+
@_searchable_field_parsers ||= {}
|
119
|
+
end
|
120
|
+
|
121
|
+
# Defines a scope that is eligible for upsert. The scope will be
|
122
|
+
# used to initialize a document with first_or_initialize. An upsert scope
|
123
|
+
# declariation must specify one or more fields that are required to
|
124
|
+
# be present on the request and also must have a field_scope defined.
|
125
|
+
#
|
126
|
+
# If multiple upsert scopes are specified, they will be searched in
|
127
|
+
# the order they are declared for the first valid scope.
|
128
|
+
#
|
129
|
+
# Examples:
|
130
|
+
#
|
131
|
+
# class User
|
132
|
+
# include Mongoid::Base
|
133
|
+
#
|
134
|
+
# scope :by_guid, lambda { |*guids| where(:guid => guids) }
|
135
|
+
# scope :by_external_guid, lambda { |*external_guids|
|
136
|
+
# where(:external_guid => exteranl_guids)
|
137
|
+
# }
|
138
|
+
# scope :by_client_guid, lambda { |*client_guids|
|
139
|
+
# joins(:client).where(
|
140
|
+
# :clients => { :guid => client_guids }
|
141
|
+
# )
|
142
|
+
# }
|
143
|
+
#
|
144
|
+
# field_scope :guid
|
145
|
+
# field_scope :client_guid
|
146
|
+
# field_scope :external_guid
|
147
|
+
#
|
148
|
+
# upsert_scope :external_guid, :client_guid
|
149
|
+
# upsert_scope :guid
|
150
|
+
#
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
def upsert_key(*fields)
|
154
|
+
fields = fields.flatten
|
155
|
+
|
156
|
+
fields.each do |field|
|
157
|
+
fail UpsertScopeError unless searchable_fields[field].present?
|
158
|
+
end
|
159
|
+
|
160
|
+
upsert_keys << fields
|
161
|
+
end
|
162
|
+
|
163
|
+
def upsert_keys
|
164
|
+
@_upsert_keys ||= []
|
165
|
+
end
|
166
|
+
|
167
|
+
def for_upsert(proto)
|
168
|
+
valid_upsert = upsert_keys.find do |upsert_key|
|
169
|
+
upsert_key.all? do |field|
|
170
|
+
proto.respond_to_and_has_and_present?(field)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
fail UpsertNotFoundError unless valid_upsert.present?
|
175
|
+
|
176
|
+
upsert_scope = model_scope
|
177
|
+
valid_upsert.each do |field|
|
178
|
+
value = proto.__send__(field)
|
179
|
+
upsert_scope = upsert_scope.__send__(searchable_fields[field], value)
|
180
|
+
end
|
181
|
+
|
182
|
+
upsert_scope.first_or_initialize
|
183
|
+
end
|
184
|
+
|
185
|
+
def upsert(proto)
|
186
|
+
document = for_upsert(proto)
|
187
|
+
document.assign_attributes(proto)
|
188
|
+
document.save
|
189
|
+
document
|
190
|
+
end
|
191
|
+
|
192
|
+
def upsert!(proto)
|
193
|
+
document = for_upsert(proto)
|
194
|
+
document.assign_attributes(proto)
|
195
|
+
document.save!
|
196
|
+
document
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# Serialization methods
|
6
|
+
module Serialization
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
class << self
|
11
|
+
attr_writer :_protobuf_field_symbol_transformers,
|
12
|
+
:_protobuf_field_transformers,
|
13
|
+
:_protobuf_field_options,
|
14
|
+
:protobuf_message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Class Methods
|
20
|
+
#
|
21
|
+
module ClassMethods
|
22
|
+
def _protobuf_field_objects
|
23
|
+
@_protobuf_field_objects ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def _protobuf_field_options
|
27
|
+
@_protobuf_field_options ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def _protobuf_field_symbol_transformers
|
31
|
+
@_protobuf_field_symbol_transformers ||= {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def _protobuf_field_transformers
|
35
|
+
@_protobuf_field_transformers ||= {}
|
36
|
+
end
|
37
|
+
|
38
|
+
def _protobuf_message_deprecated_fields
|
39
|
+
@_protobuf_message_deprecated_fields ||=
|
40
|
+
protobuf_message.all_fields.map do |field|
|
41
|
+
next if field.nil?
|
42
|
+
next unless field.deprecated?
|
43
|
+
|
44
|
+
field.name.to_sym
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def _protobuf_message_non_deprecated_fields
|
49
|
+
@_protobuf_message_non_deprecated_fields ||=
|
50
|
+
protobuf_message.all_fields.map do |field|
|
51
|
+
next if field.nil?
|
52
|
+
next if field.deprecated?
|
53
|
+
|
54
|
+
field.name.to_sym
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def field_from_document(field, transformer = nil, &block)
|
59
|
+
if transformer.is_a?(Symbol)
|
60
|
+
_protobuf_field_symbol_transformers[field] = transformer
|
61
|
+
return
|
62
|
+
end
|
63
|
+
|
64
|
+
transformer ||= block
|
65
|
+
callable = transformer
|
66
|
+
|
67
|
+
raise FieldTransformerError unless callable.respond_to?(:call)
|
68
|
+
|
69
|
+
_protobuf_field_transformers[field.to_sym] = callable
|
70
|
+
end
|
71
|
+
|
72
|
+
def protobuf_fields(*fields)
|
73
|
+
options = fields.extract_options!
|
74
|
+
options[:only] = fields if fields.present?
|
75
|
+
|
76
|
+
self._protobuf_field_options = options
|
77
|
+
end
|
78
|
+
|
79
|
+
def protobuf_message(message = nil, options = {})
|
80
|
+
unless message.nil?
|
81
|
+
@protobuf_message = message.to_s.classify.constantize
|
82
|
+
self._protobuf_field_options = options
|
83
|
+
end
|
84
|
+
|
85
|
+
@protobuf_message
|
86
|
+
end
|
87
|
+
|
88
|
+
class CollectionAssociationCaller
|
89
|
+
def initialize(method_name)
|
90
|
+
@method_name = method_name
|
91
|
+
end
|
92
|
+
|
93
|
+
def call(selph)
|
94
|
+
selph.__send__(@method_name).to_a
|
95
|
+
rescue NameError
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def _protobuf_collection_association_object(field)
|
101
|
+
CollectionAssociationCaller.new(field)
|
102
|
+
end
|
103
|
+
|
104
|
+
class DateCaller
|
105
|
+
def initialize(field)
|
106
|
+
@field = field
|
107
|
+
end
|
108
|
+
|
109
|
+
def call(selph)
|
110
|
+
value = selph.__send__(@field)
|
111
|
+
|
112
|
+
value&.to_time&.utc&.to_i
|
113
|
+
rescue NameError
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class DateTimeCaller
|
119
|
+
def initialize(field)
|
120
|
+
@field = field
|
121
|
+
end
|
122
|
+
|
123
|
+
def call(selph)
|
124
|
+
value = selph.__send__(@field)
|
125
|
+
|
126
|
+
value&.to_i
|
127
|
+
rescue NameError
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class NoConversionCaller
|
133
|
+
def initialize(field)
|
134
|
+
@field = field
|
135
|
+
end
|
136
|
+
|
137
|
+
def call(selph)
|
138
|
+
selph.__send__(@field)
|
139
|
+
rescue NameError
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def _protobuf_convert_to_fields_object(field)
|
145
|
+
is_datetime_time_or_timestamp_field = _protobuf_date_datetime_time_or_timestamp_field?(field)
|
146
|
+
is_date_field = _protobuf_date_field?(field)
|
147
|
+
|
148
|
+
if is_datetime_time_or_timestamp_field
|
149
|
+
if is_date_field
|
150
|
+
DateCaller.new(field)
|
151
|
+
else
|
152
|
+
DateTimeCaller.new(field)
|
153
|
+
end
|
154
|
+
else
|
155
|
+
NoConversionCaller.new(field)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def _protobuf_field_transformer_object(field)
|
160
|
+
_protobuf_field_transformers[field]
|
161
|
+
end
|
162
|
+
|
163
|
+
class NilMethodCaller
|
164
|
+
def initialize; end
|
165
|
+
|
166
|
+
def call(_selph)
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def _protobuf_nil_object(_field)
|
172
|
+
NilMethodCaller.new
|
173
|
+
end
|
174
|
+
|
175
|
+
class FieldSymbolTransformerCaller
|
176
|
+
def initialize(instance_class, method_name)
|
177
|
+
@instance_class = instance_class
|
178
|
+
@method_name = method_name
|
179
|
+
end
|
180
|
+
|
181
|
+
def call(selph)
|
182
|
+
@instance_class.__send__(@method_name, selph)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def _protobuf_symbol_transformer_object(field)
|
187
|
+
FieldSymbolTransformerCaller.new(self, _protobuf_field_symbol_transformers[field])
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def _filter_field_attributes(options = {})
|
192
|
+
options = _normalize_options(options)
|
193
|
+
|
194
|
+
fields = _filtered_fields(options)
|
195
|
+
fields &= [options[:only]].flatten if options[:only].present?
|
196
|
+
fields -= [options[:except]].flatten if options[:except].present?
|
197
|
+
|
198
|
+
fields
|
199
|
+
end
|
200
|
+
|
201
|
+
def _filtered_fields(options = {})
|
202
|
+
include_deprecated = options.fetch(:deprecated, true)
|
203
|
+
|
204
|
+
fields = []
|
205
|
+
fields.concat(self.class._protobuf_message_non_deprecated_fields)
|
206
|
+
fields.concat(self.class._protobuf_message_deprecated_fields) if include_deprecated
|
207
|
+
fields.concat([options[:include]].flatten) if options[:include].present?
|
208
|
+
fields.compact!
|
209
|
+
fields.uniq!
|
210
|
+
|
211
|
+
fields
|
212
|
+
end
|
213
|
+
|
214
|
+
def _is_collection_association?(field)
|
215
|
+
reflection = self.class.relations[field.to_s]
|
216
|
+
return false unless reflection
|
217
|
+
|
218
|
+
reflection.class.name.split('::').last.to_sym == :has_many
|
219
|
+
end
|
220
|
+
|
221
|
+
def _normalize_options(options)
|
222
|
+
options ||= {}
|
223
|
+
options[:only] ||= [] if options.fetch(:except, false)
|
224
|
+
options[:except] ||= [] if options.fetch(:only, false)
|
225
|
+
|
226
|
+
self.class._protobuf_field_options.merge(options)
|
227
|
+
end
|
228
|
+
|
229
|
+
def fields_from_document(options = {})
|
230
|
+
hash = {}
|
231
|
+
field_attributes = _filter_field_attributes(options)
|
232
|
+
|
233
|
+
if options[:include].present?
|
234
|
+
field_attributes.concat([options[:include]].flatten)
|
235
|
+
field_attributes.compact!
|
236
|
+
field_attributes.uniq!
|
237
|
+
end
|
238
|
+
|
239
|
+
field_attributes.each do |field|
|
240
|
+
field_object = _protobuf_field_objects(field)
|
241
|
+
hash[field] = field_object.call(self)
|
242
|
+
end
|
243
|
+
|
244
|
+
hash
|
245
|
+
end
|
246
|
+
|
247
|
+
# TODO: Assignment Branch Condition size for _protobuf_field_objects is too high. [<1, 19, 7> 20.27/17]
|
248
|
+
def _protobuf_field_objects(field)
|
249
|
+
self.class._protobuf_field_objects[field] ||=
|
250
|
+
if _protobuf_field_symbol_transformers.key?(field)
|
251
|
+
self.class._protobuf_symbol_transformer_object(field)
|
252
|
+
elsif _protobuf_field_transformers.key?(field)
|
253
|
+
self.class._protobuf_field_transformer_object(field)
|
254
|
+
elsif respond_to?(field)
|
255
|
+
if _is_collection_association?(field)
|
256
|
+
self.class._protobuf_collection_association_object(field)
|
257
|
+
else
|
258
|
+
self.class._protobuf_convert_to_fields_object(field)
|
259
|
+
end
|
260
|
+
else
|
261
|
+
self.class._protobuf_nil_object(field)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def _protobuf_field_symbol_transformers
|
266
|
+
self.class._protobuf_field_symbol_transformers
|
267
|
+
end
|
268
|
+
|
269
|
+
def _protobuf_field_transformers
|
270
|
+
self.class._protobuf_field_transformers
|
271
|
+
end
|
272
|
+
|
273
|
+
def _protobuf_message
|
274
|
+
self.class.protobuf_message
|
275
|
+
end
|
276
|
+
|
277
|
+
def to_proto(options = {})
|
278
|
+
raise MessageNotDefined, self.class if _protobuf_message.nil?
|
279
|
+
|
280
|
+
fields = fields_from_document(options)
|
281
|
+
_protobuf_message.new(fields)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'protobuf/mongoid/transformer'
|
4
|
+
|
5
|
+
module Protobuf
|
6
|
+
module Mongoid
|
7
|
+
# Transformation methods
|
8
|
+
module Transformation
|
9
|
+
extend ::ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
include ::Heredity::InheritableClassInstanceVariables
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :_protobuf_attribute_transformers
|
16
|
+
end
|
17
|
+
|
18
|
+
@_protobuf_attribute_transformers = {}
|
19
|
+
|
20
|
+
inheritable_attributes :_protobuf_attribute_transformers
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Class Methods
|
25
|
+
#
|
26
|
+
module ClassMethods
|
27
|
+
# Filters accessible attributes that exist in the given protobuf message's
|
28
|
+
# fields or have attribute transformers defined for them.
|
29
|
+
#
|
30
|
+
# Returns a hash of attribute fields with their respective values.
|
31
|
+
#
|
32
|
+
# :nodoc:
|
33
|
+
# TODO: Assignment Branch Condition size for _filter_attribute_fields is too high. [<13, 26, 9> 30.43/17]
|
34
|
+
# TODO: Use `each_with_object` instead of `inject`.
|
35
|
+
def _filter_attribute_fields(proto)
|
36
|
+
fields = proto.to_hash
|
37
|
+
fields.select! do |key, _value|
|
38
|
+
field = proto.class.get_field(key, true)
|
39
|
+
proto.field?(key) && !field.repeated?
|
40
|
+
end
|
41
|
+
|
42
|
+
filtered_attributes = _filtered_attributes + _protobuf_attribute_transformers.keys
|
43
|
+
|
44
|
+
attribute_fields = filtered_attributes.inject({}) do |hash, field_name|
|
45
|
+
symbolized_field = field_name.to_sym
|
46
|
+
|
47
|
+
if fields.key?(symbolized_field) || _protobuf_attribute_transformers.key?(symbolized_field)
|
48
|
+
hash[symbolized_field] = fields[symbolized_field]
|
49
|
+
end
|
50
|
+
|
51
|
+
hash
|
52
|
+
end
|
53
|
+
|
54
|
+
_protobuf_nested_attributes.each do |attribute_name|
|
55
|
+
nested_attribute_name = "#{attribute_name}_attributes".to_sym
|
56
|
+
value = if proto.field?(nested_attribute_name)
|
57
|
+
proto.__send__(nested_attribute_name)
|
58
|
+
elsif proto.field?(attribute_name)
|
59
|
+
proto.__send__(attribute_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
next unless value
|
63
|
+
|
64
|
+
attribute_fields[nested_attribute_name] = value
|
65
|
+
end
|
66
|
+
|
67
|
+
attribute_fields
|
68
|
+
end
|
69
|
+
|
70
|
+
# Overidden by mass assignment security when protected attributes is loaded.
|
71
|
+
#
|
72
|
+
# :nodoc:
|
73
|
+
def _filtered_attributes
|
74
|
+
return self.attribute_names
|
75
|
+
end
|
76
|
+
|
77
|
+
# :nodoc:
|
78
|
+
def _protobuf_convert_fields_to_attributes(key, value)
|
79
|
+
return nil if value.nil?
|
80
|
+
return value unless _protobuf_date_datetime_time_or_timestamp_field?(key)
|
81
|
+
|
82
|
+
value = case
|
83
|
+
when _protobuf_datetime_field?(key) then
|
84
|
+
convert_int64_to_datetime(value)
|
85
|
+
when _protobuf_timestamp_field?(key) then
|
86
|
+
convert_int64_to_time(value)
|
87
|
+
when _protobuf_time_field?(key) then
|
88
|
+
convert_int64_to_time(value)
|
89
|
+
when _protobuf_date_field?(key) then
|
90
|
+
convert_int64_to_date(value)
|
91
|
+
end
|
92
|
+
|
93
|
+
return value
|
94
|
+
end
|
95
|
+
|
96
|
+
# Define an attribute transformation from protobuf. Accepts a Symbol,
|
97
|
+
# callable, or block.
|
98
|
+
#
|
99
|
+
# When given a callable or block, it is directly used to convert the field.
|
100
|
+
#
|
101
|
+
# When a symbol is given, it extracts the method with the same name.
|
102
|
+
#
|
103
|
+
# The callable or method must accept a single parameter, which is the
|
104
|
+
# proto message.
|
105
|
+
#
|
106
|
+
# Examples:
|
107
|
+
# attribute_from_proto :public_key, :extract_public_key_from_proto
|
108
|
+
# attribute_from_proto :status, lambda { |proto| # Do some stuff... }
|
109
|
+
# attribute_from_proto :status do |proto|
|
110
|
+
# # Do some blocky stuff...
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# attribute_from_proto :status, lambda { |proto| nil }, :nullify_on => :status
|
114
|
+
# attribute_from_proto :status, :nullify_on => :status do |proto|
|
115
|
+
# nil
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
def attribute_from_proto(attribute, *args, &block)
|
119
|
+
options = args.extract_options!
|
120
|
+
symbol_or_block = args.first || block
|
121
|
+
|
122
|
+
if symbol_or_block.is_a?(Symbol)
|
123
|
+
callable = lambda { |value| self.__send__(symbol_or_block, value) }
|
124
|
+
else
|
125
|
+
raise AttributeTransformerError unless symbol_or_block.respond_to?(:call)
|
126
|
+
callable = symbol_or_block
|
127
|
+
end
|
128
|
+
|
129
|
+
if options[:nullify_on]
|
130
|
+
field = protobuf_message.get_field(:nullify)
|
131
|
+
unless field&.is_a?(::Protobuf::Field::StringField) && field&.repeated?
|
132
|
+
::Protobuf::Logging.logger.warn "Message: #{protobuf_message} is not compatible with :nullify_on option"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
transformer = ::Protobuf::Mongoid::Transformer.new(callable, options)
|
137
|
+
_protobuf_attribute_transformers[attribute.to_sym] = transformer
|
138
|
+
end
|
139
|
+
|
140
|
+
# Creates a hash of attributes from a given protobuf message.
|
141
|
+
#
|
142
|
+
# It converts and transforms field values using the field converters and
|
143
|
+
# attribute transformers, ignoring repeated and nil fields.
|
144
|
+
#
|
145
|
+
def attributes_from_proto(proto)
|
146
|
+
attribute_fields = _filter_attribute_fields(proto)
|
147
|
+
|
148
|
+
attributes = attribute_fields.inject({}) do |hash, (key, value)|
|
149
|
+
if _protobuf_attribute_transformers.key?(key)
|
150
|
+
transformer = _protobuf_attribute_transformers[key]
|
151
|
+
attribute = transformer.call(proto)
|
152
|
+
hash[key] = attribute unless attribute.nil?
|
153
|
+
hash[key] = nil if transformer.nullify?(proto)
|
154
|
+
else
|
155
|
+
hash[key] = _protobuf_convert_fields_to_attributes(key, value)
|
156
|
+
end
|
157
|
+
|
158
|
+
hash
|
159
|
+
end
|
160
|
+
|
161
|
+
return attributes unless proto.field?(:nullify) && proto.nullify.is_a?(Array)
|
162
|
+
|
163
|
+
proto.nullify.each do |attribute_name|
|
164
|
+
attributes[attribute_name.to_sym] = nil if attribute_names.include?(attribute_name.to_s)
|
165
|
+
end
|
166
|
+
|
167
|
+
attributes
|
168
|
+
end
|
169
|
+
|
170
|
+
# :nodoc:
|
171
|
+
def convert_int64_to_time(int64)
|
172
|
+
Time.at(int64.to_i)
|
173
|
+
end
|
174
|
+
|
175
|
+
# :nodoc:
|
176
|
+
def convert_int64_to_date(int64)
|
177
|
+
convert_int64_to_time(int64).utc.to_date
|
178
|
+
end
|
179
|
+
|
180
|
+
# :nodoc:
|
181
|
+
def convert_int64_to_datetime(int64)
|
182
|
+
convert_int64_to_time(int64).to_datetime
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Calls up to the class version of the method.
|
187
|
+
#
|
188
|
+
def attributes_from_proto(proto)
|
189
|
+
self.class.attributes_from_proto(proto)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# Transformer class
|
6
|
+
class Transformer
|
7
|
+
attr_accessor :callable, :options
|
8
|
+
|
9
|
+
def initialize(callable, options = {})
|
10
|
+
@callable = callable
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(proto)
|
15
|
+
return unless proto
|
16
|
+
|
17
|
+
callable.call(proto)
|
18
|
+
end
|
19
|
+
|
20
|
+
def nullify?(proto)
|
21
|
+
return false unless options[:nullify_on]
|
22
|
+
return false unless proto.field?(:nullify) && proto.nullify.is_a?(Array)
|
23
|
+
return false if proto.nullify.empty?
|
24
|
+
|
25
|
+
proto.nullify.include?(options[:nullify_on].to_s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Mongoid
|
5
|
+
# Validation methods
|
6
|
+
module Validations
|
7
|
+
extend ::ActiveSupport::Concern
|
8
|
+
|
9
|
+
##
|
10
|
+
# Class Methods
|
11
|
+
#
|
12
|
+
module ClassMethods
|
13
|
+
# Validates whether the value of the specified attribute is available in
|
14
|
+
# the given Protobuf Enum. The enumeration should be passed as a class
|
15
|
+
# that defines the enumeration:
|
16
|
+
#
|
17
|
+
# ```
|
18
|
+
# class User < Mongoid::Base
|
19
|
+
# include ::Protobuf::Mongoid::Model
|
20
|
+
#
|
21
|
+
# validates_enumeration_of :role_type, :with => RoleType, :allow_nil => true
|
22
|
+
# end
|
23
|
+
# ```
|
24
|
+
#
|
25
|
+
# In this example, RoleType is a defined as a protobuf enum.
|
26
|
+
#
|
27
|
+
# It accepts the same options as `validates_inclusion_of` (the :in option
|
28
|
+
# is automatically set and will be overwritten).
|
29
|
+
#
|
30
|
+
def validates_enumeration_of(*args)
|
31
|
+
options = args.extract_options!
|
32
|
+
enumerable = options.delete(:with)
|
33
|
+
|
34
|
+
raise ArgumentError, ':with must be specified' if enumerable.nil?
|
35
|
+
|
36
|
+
options[:in] = enumerable.all_tags if enumerable < ::Protobuf::Enum
|
37
|
+
|
38
|
+
args << options
|
39
|
+
|
40
|
+
validates_inclusion_of(*args)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'heredity'
|
5
|
+
|
6
|
+
require 'protobuf/mongoid/model'
|
7
|
+
require 'protobuf/mongoid/version'
|
8
|
+
|
9
|
+
module Protobuf
|
10
|
+
# Main module for Protobuf-Mongoid integration
|
11
|
+
module Mongoid
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: protobuf-mongoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Luilver Garces
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-04-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: google-protobuf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.30.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.30.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: heredity
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.1.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.1.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mongoid
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 9.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 9.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: protobuf
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.10.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.10.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: securerandom
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.4.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.4.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.15.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.15.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: timecop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.9.0
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.9.0
|
125
|
+
description: This gem provides functionality to serialize and deserialize Mongoid
|
126
|
+
documents using Protocol Buffers.
|
127
|
+
email:
|
128
|
+
- luilver@gmail.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- LICENSE.txt
|
134
|
+
- README.md
|
135
|
+
- lib/protobuf/mongoid.rb
|
136
|
+
- lib/protobuf/mongoid/attribute_methods.rb
|
137
|
+
- lib/protobuf/mongoid/errors.rb
|
138
|
+
- lib/protobuf/mongoid/fields.rb
|
139
|
+
- lib/protobuf/mongoid/model.rb
|
140
|
+
- lib/protobuf/mongoid/nested_attributes.rb
|
141
|
+
- lib/protobuf/mongoid/persistence.rb
|
142
|
+
- lib/protobuf/mongoid/scope.rb
|
143
|
+
- lib/protobuf/mongoid/serialization.rb
|
144
|
+
- lib/protobuf/mongoid/transformation.rb
|
145
|
+
- lib/protobuf/mongoid/transformer.rb
|
146
|
+
- lib/protobuf/mongoid/validations.rb
|
147
|
+
- lib/protobuf/mongoid/version.rb
|
148
|
+
homepage: https://github.com/yourusername/protobuf-mongoid
|
149
|
+
licenses:
|
150
|
+
- MIT
|
151
|
+
metadata: {}
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
require_paths:
|
155
|
+
- lib
|
156
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 3.2.2
|
161
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
requirements: []
|
167
|
+
rubygems_version: 3.5.6
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: A gem to integrate Protocol Buffers with Mongoid.
|
171
|
+
test_files: []
|