pb-serializer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f67d4a17784718471b0092c70c74d8ad19c3c7dcd7d0003268d0b52ee1cff8b5
4
- data.tar.gz: 970526e14d3bacab347a57fb1a556ea041529cca3e2d9ad0e5aaf4482f4808bb
3
+ metadata.gz: 3d65ab2cd7830751ed61e5cd72eca1d688fac910b544167994780d065e55fa3b
4
+ data.tar.gz: e991534beffa6fb92b4c23f05bf59b5ba0ef6872cd34dc801148e08ec3f2c075
5
5
  SHA512:
6
- metadata.gz: 922d74b4ca48c70e6fc37358a994630fceb3244acb8af39523dc60b8288a25c8f4f44f45c67e663743b01800fb8ec7a60b5f6804598d698ea42531947d5cb81d
7
- data.tar.gz: 87fb4dec4bb9e073d6b461fd1b0d80803e8f1763a021e33746b9e789dfe71566dc9ccdf45ae9ca3834c4aeeb152b53660ee4bb4fedbd1525d4d81304b7f6c233
6
+ metadata.gz: 0a138f78df718b226cbf65cef851380a941c34306ed80bdc2fb65093f0dec804515d0187d3f0b11e4fcd36bbc339dfca08f2beef49989d6417ccf157ddf9da97
7
+ data.tar.gz: bf343a1d3f7f055370f652616fc6914dc682f2fdc6840c6975614537d5ecf02241974b8df986505f96a517401b676e0756aa2040d181898e8dc866ee76ab305c
data/README.md CHANGED
@@ -6,24 +6,29 @@ class UserSerializer < Pb::Serializer::Base
6
6
 
7
7
  attribute :id, required: true
8
8
  attribute :name, required: true
9
- attribute :posts, required: true, serializer: PostSerializer
9
+ attribute :posts, required: true
10
10
 
11
- define_loader :posts do |users, subdeps, **|
12
- posts = Post.where(user_id: users.map(&:id)).index_by(&:user_id)
13
- users.each do |user|
14
- user.posts = posts[user.id]
15
- end
11
+ define_primary_loader :user do |subdeps, ids:, **|
12
+ User.where(id: ids).preload(subdeps).map { |u| new(u) }
13
+ end
14
+
15
+ define_loader :posts, key: -> { id } do |user_ids, subdeps, **|
16
+ PostSerializer.bulk_load(user_id: user_ids, with: subdeps).group_by { |s| s.post.user_id }
16
17
  end
17
18
 
18
19
  dependency :posts
19
20
  computed def post_count
20
- object.posts.size
21
+ posts.count
21
22
  end
22
23
  end
23
24
 
24
25
  class PostSerializer < Pb::Serializer::Base
25
26
  message YourApp::Post
26
27
 
28
+ define_primary_loader :post do |subdeps, user_ids:, **|
29
+ Post.where(user_id: user_ids).preload(subdeps).map { |p| new(p) }
30
+ end
31
+
27
32
  attribute :id, required: true
28
33
  attribute :title, required: true
29
34
  attribute :body, required: true
@@ -34,22 +39,23 @@ class UserGrpcService < YourApp::UserService::Service
34
39
  # @param call [GRPC::ActiveCall::SingleReqView]
35
40
  # @return [YourApp::User]
36
41
  def get_users(req, call)
37
- user = User.find(id: req.user_id)
38
- UserSerializer.serialize(user, with: req.field_mask)
42
+ UserSerializer.bulk_load_and_serialize(ids: [req.user_id], with: req.field_mask)[0]
39
43
  end
40
44
 
41
45
  # @param req [YourApp::ListFriendUsersRequest]
42
46
  # @param call [GRPC::ActiveCall::SingleReqView]
43
47
  # @return [YourApp::ListFriendUsersResponse]
44
48
  def list_friend_users(req, call)
45
- friends = User.find(current_user_id).friends
49
+ current_user = User.find(current_user_id)
46
50
  YourApp::ListFriendUsersResponse.new(
47
- users: UserSerializer.serialize_repeated(friends, with: req.field_mask),
51
+ users: UserSerializer.bulk_load_and_serialize(ids: current_user.friend_ids, with: req.field_mask)
48
52
  )
49
53
  end
50
54
  end
51
55
  ```
52
56
 
57
+ More examples are available under [./spec/examples](./spec/examples).
58
+
53
59
 
54
60
  ## Installation
55
61
 
@@ -3,14 +3,11 @@ module Pb
3
3
  def self.included(base)
4
4
  base.extend ClassMethods
5
5
  base.include ComputedModel
6
+ base.singleton_class.prepend Hook
6
7
  end
7
8
 
8
9
  def to_pb(with: nil)
9
- if with.nil?
10
- with = ::Pb::Serializer.build_default_mask(self.class.message_class.descriptor)
11
- end
12
-
13
- self.class.bulk_load_and_compute(Array(self), with)
10
+ # TODO: apply masks
14
11
 
15
12
  oneof_set = []
16
13
 
@@ -26,14 +23,14 @@ module Pb
26
23
  v = attr.convert_to_pb(v)
27
24
 
28
25
  if attr.required && attr.field_descriptor.default == v
29
- raise ::Pb::Serializer::ValidationError, "#{object.class.name}##{attr.name} is required"
26
+ raise ::Pb::Serializer::ValidationError, "#{primary_object.class.name}##{attr.name} is required"
30
27
  end
31
28
 
32
29
  next if v.nil?
33
30
 
34
31
  if attr.oneof?
35
32
  if oneof_set.include?(attr.oneof)
36
- raise ::Pb::Serializer::ConflictOneofError, "#{object.class.name}##{attr.name} is oneof attribute"
33
+ raise ::Pb::Serializer::ConflictOneofError, "#{primary_object.class.name}##{attr.name} is oneof attribute"
37
34
  end
38
35
  oneof_set << attr.oneof
39
36
  end
@@ -48,14 +45,47 @@ module Pb
48
45
  self.class.oneofs.each do |oneof|
49
46
  next if oneof_set.include?(oneof.name)
50
47
  next unless oneof.required?
51
- raise ::Pb::Serializer::ValidationError, "#{object.class.name}##{oneof.name} is required"
48
+ raise ::Pb::Serializer::ValidationError, "#{primary_object.class.name}##{oneof.name} is required"
52
49
  end
53
50
 
54
51
  o
55
52
  end
56
53
 
54
+ private def primary_object
55
+ primary_object_name = self.class.__pb_serializer_primary_model_name
56
+ if primary_object_name
57
+ send(primary_object_name)
58
+ elsif kind_of?(Serializer::Base)
59
+ send(:object)
60
+ else
61
+ self
62
+ end
63
+ end
64
+
65
+ module Hook
66
+ def define_primary_loader(name)
67
+ self.__pb_serializer_primary_model_name = name
68
+
69
+ super
70
+ end
71
+
72
+ def computed(name)
73
+ __pb_serializer_attrs << name
74
+
75
+ super
76
+ end
77
+
78
+ def define_loader(name, **)
79
+ __pb_serializer_attrs << name
80
+
81
+ super
82
+ end
83
+ end
84
+
57
85
  module ClassMethods
58
86
  attr_reader :message_class
87
+ attr_accessor :__pb_serializer_primary_model_name
88
+
59
89
  def message(klass)
60
90
  @message_class = klass
61
91
  end
@@ -79,21 +109,21 @@ module Pb
79
109
  @attr_by_name[name] = attr
80
110
 
81
111
  define_method attr.name do
82
- object.public_send(attr.name) # FIXME: This does not work without ::Pb::Serializer::Base
112
+ primary_object.public_send(attr.name)
83
113
  end
114
+ end
84
115
 
85
- dependency # FIXME
86
- computed attr.name
116
+ # @param with [Array, Google::Protobuf::FieldMask, nil]
117
+ # @return [Array]
118
+ def bulk_load_and_serialize(with: nil, **args)
119
+ bulk_load(with: with, **args).map { |s| s.to_pb(with: with) }
87
120
  end
88
121
 
89
- # @param object [Object, Array]
90
- # @param message_class [Class]
91
- def serialize(object, with: nil)
92
- if self < ::Pb::Serializer::Base
93
- new(object).to_pb
94
- else
95
- object.to_pb
96
- end
122
+ def bulk_load(with: nil, **args)
123
+ with ||= ::Pb::Serializer.build_default_mask(message_class.descriptor)
124
+ with = with.reject { |c| (__pb_serializer_attrs & (c.kind_of?(Hash) ? c.keys : [c])).empty? }
125
+
126
+ bulk_load_and_compute(with, **args)
97
127
  end
98
128
 
99
129
  def oneof(name, required: true)
@@ -108,6 +138,10 @@ module Pb
108
138
  @current_oneof = nil
109
139
  end
110
140
 
141
+ private def __pb_serializer_attrs
142
+ @__pb_serializer_attrs ||= Set.new
143
+ end
144
+
111
145
  # @param fd [Google::Protobuf::FieldDescriptor] a field descriptor
112
146
  # @return [Pb::Serializer::Attribute, nil]
113
147
  def find_attribute_by_field_descriptor(fd)
@@ -42,7 +42,7 @@ module Pb
42
42
  when "google.protobuf.BytesValue" then Pb.to_bytesval(v)
43
43
  else
44
44
  return nil if v.nil?
45
- return serializer_class.serialize(v) if serializer_class
45
+ return serializer_class.new(v).to_pb if serializer_class
46
46
  return v.to_pb if v.kind_of?(::Pb::Serializable)
47
47
 
48
48
  raise "serializer was not found for #{field_descriptor.submsg_name}"
@@ -3,6 +3,7 @@ module Pb
3
3
  class Base
4
4
  def self.inherited(base)
5
5
  base.include ::Pb::Serializable
6
+ base.singleton_class.prepend Hook
6
7
  end
7
8
 
8
9
  attr_reader :object
@@ -10,6 +11,18 @@ module Pb
10
11
  def initialize(object)
11
12
  @object = object
12
13
  end
14
+
15
+ module Hook
16
+ def define_primary_loader(name, &block)
17
+ class_eval <<~RUBY
18
+ def initialize(object)
19
+ @#{name} = object
20
+ end
21
+ RUBY
22
+
23
+ super
24
+ end
25
+ end
13
26
  end
14
27
  end
15
28
  end
@@ -1,5 +1,5 @@
1
1
  module Pb
2
2
  module Serializer
3
- VERSION = "0.1.0".freeze
3
+ VERSION = "0.2.0".freeze
4
4
  end
5
5
  end
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  rails_versions = [">= 5.2", "< 6.1"]
30
30
  spec.add_runtime_dependency "google-protobuf", "~> 3.0"
31
31
  spec.add_runtime_dependency "the_pb", "~> 0.0.1"
32
- spec.add_runtime_dependency "computed_model", "~> 0.1.0"
32
+ spec.add_runtime_dependency "computed_model", "~> 0.2.1"
33
33
 
34
34
  spec.add_development_dependency "activerecord", rails_versions
35
35
  spec.add_development_dependency "bundler", "~> 2.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pb-serializer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - izumin5210
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-17 00:00:00.000000000 Z
11
+ date: 2020-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.1.0
47
+ version: 0.2.1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.1.0
54
+ version: 0.2.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -205,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
205
205
  - !ruby/object:Gem::Version
206
206
  version: '0'
207
207
  requirements: []
208
- rubygems_version: 3.0.3
208
+ rubygems_version: 3.1.2
209
209
  signing_key:
210
210
  specification_version: 4
211
211
  summary: Serialize objects into Protocol Buffers messages