panko_serializer 0.1.8 → 0.1.9
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 +4 -4
- data/README.md +93 -3
- data/benchmarks/bm_serialization_descriptor.rb +85 -0
- data/ext/panko_serializer/panko_serializer.c +4 -4
- data/lib/panko/serialization_descriptor.rb +42 -19
- data/lib/panko/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c6bed38967e51bd9b7902aa9b98378c47ed947e
|
4
|
+
data.tar.gz: a538bbe197fabf3220485e05c886a47d6cf22713
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16fb0300a61dfd66e5b364640846dd1bdb7944a707e44e904f043b332b0ab700d878de100f5828577fdc1acc1b7e0247411b99a770ca9f3aa0b7e90b6acd79d5
|
7
|
+
data.tar.gz: ec5ac08ac0c6b8f20c714d3cd2079667ef45bd0f332df9d3a2eb527221c0e147e8cc183ae972d9b7b8bff2518b6a384ed8df08e8874535e4f35b2db23f2f9c53
|
data/README.md
CHANGED
@@ -2,13 +2,103 @@
|
|
2
2
|
|
3
3
|
[](https://travis-ci.org/yosiat/panko_serializer)
|
4
4
|
|
5
|
-
Panko is
|
5
|
+
Panko is library which is inspired by ActiveModelSerializers 0.9 for serializing ActiveRecord objects to JSON strings, fast.
|
6
6
|
|
7
|
-
|
7
|
+
To achieve it's performance:
|
8
8
|
|
9
|
-
|
9
|
+
* Oj - Panko relies Oj since it's fast and allow to to serialize incrementally using `Oj::StringWriter`
|
10
|
+
* Serialization Descriptor - Panko computes most of the metadata ahead of time, to save time later in serialization.
|
11
|
+
* Type casting — Panko does type casting by it's self, instead of relying ActiveRecord.
|
10
12
|
|
13
|
+
To dig deeper about the performance choices, read [Design Choices](https://github.com/yosiat/panko_serializer/wiki/Design-Choices).
|
11
14
|
|
15
|
+
### Status
|
16
|
+
|
17
|
+
Panko is not ready for official release - it's missing documentation, tests which all be done incrementally.
|
18
|
+
If you want to start using Panko to see if it helps you, you are welcome! but check it well before deploying to Production.
|
19
|
+
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
To install Panko, all you need is to add it to your Gemfile:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
gem "panko_serializer"
|
27
|
+
```
|
28
|
+
|
29
|
+
Then, install it on the command line:
|
30
|
+
|
31
|
+
```
|
32
|
+
> bundle install
|
33
|
+
```
|
34
|
+
|
35
|
+
> Since the Gem name and namespace differ, you need to require "panko" explicitly. This will be fixed before official release.
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
### Getting Started
|
42
|
+
|
43
|
+
Let's create serializer and use it inside Rails controller.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class PostSerializer < Panko::Serializer
|
47
|
+
attributes :title
|
48
|
+
end
|
49
|
+
|
50
|
+
class UserSerializer < Panko::Serializer
|
51
|
+
attributes :id, :name, :age
|
52
|
+
|
53
|
+
has_many :posts, serializer: PostSerializer
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
As you can see, defining serializers is simple and resembles ActiveModelSerializers 0.9,
|
58
|
+
To utilize the `UserSerializer` inside a Rails controller and serialize some users, all we need to do is:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
class UsersController < ApplicationController
|
62
|
+
def index
|
63
|
+
users = User.includes(:posts).all
|
64
|
+
render json: Panko::ArraySerializer(users, each_serializer: UserSerializer).to_json
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
And voila, we have endpoint which serializers user records using Panko!
|
70
|
+
|
71
|
+
|
72
|
+
## Features
|
73
|
+
|
74
|
+
### Attributes
|
75
|
+
|
76
|
+
Attributes allow you to specify which record attributes you want to serialize,
|
77
|
+
There are two types of attributes:
|
78
|
+
|
79
|
+
* Field - simple columns defined on the record it self.
|
80
|
+
* Virtual/Method - this allows to include properties beyond simple fields.
|
81
|
+
|
82
|
+
Example:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class UserSerializer < Panko::Serializer
|
86
|
+
attributes :full_name
|
87
|
+
|
88
|
+
def full_name
|
89
|
+
"#{object.first_name} #{object.last_name}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
As you can see, in order to access the serialized record, you need to access `object`.
|
95
|
+
If you want to pass data to the serializer, beyond the serialized record, you can pass `context` to the serializer (both in single and array serializer).
|
96
|
+
|
97
|
+
#### TODO:
|
98
|
+
Finished feature, will add documentation sson:
|
99
|
+
- Realtionships - `has_one`, `has_many`
|
100
|
+
- Filters & Nested Filters
|
101
|
+
- Reponse bag
|
12
102
|
|
13
103
|
## License
|
14
104
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "./benchmarking_support"
|
3
|
+
require "rails"
|
4
|
+
require "active_model"
|
5
|
+
require "active_support"
|
6
|
+
require "active_support/json"
|
7
|
+
require "action_controller"
|
8
|
+
require "action_controller/railtie"
|
9
|
+
|
10
|
+
|
11
|
+
require "memory_profiler"
|
12
|
+
require "ruby-prof"
|
13
|
+
require "ruby-prof-flamegraph"
|
14
|
+
require "panko_serializer"
|
15
|
+
|
16
|
+
def generate_attributes(count)
|
17
|
+
(1..count).map { |i| "attr_#{i}".to_sym }
|
18
|
+
end
|
19
|
+
|
20
|
+
class LeafASerializer < Panko::Serializer
|
21
|
+
attributes *generate_attributes(5)
|
22
|
+
end
|
23
|
+
|
24
|
+
class LeafBSerializer < Panko::Serializer
|
25
|
+
attributes *generate_attributes(6)
|
26
|
+
end
|
27
|
+
|
28
|
+
class ChildrenSerializer < Panko::Serializer
|
29
|
+
attributes *generate_attributes(28)
|
30
|
+
|
31
|
+
has_one :leaf_a, serializer: LeafASerializer
|
32
|
+
has_one :leaf_b, serializer: LeafBSerializer
|
33
|
+
|
34
|
+
def attr_1
|
35
|
+
end
|
36
|
+
|
37
|
+
def attr_2
|
38
|
+
end
|
39
|
+
|
40
|
+
def attr_3
|
41
|
+
end
|
42
|
+
|
43
|
+
def attr_4
|
44
|
+
end
|
45
|
+
|
46
|
+
def attr_5
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ParentSerializer < Panko::Serializer
|
51
|
+
attributes *generate_attributes(46)
|
52
|
+
|
53
|
+
has_many :children, serializer: ChildrenSerializer
|
54
|
+
|
55
|
+
|
56
|
+
def attr_1
|
57
|
+
end
|
58
|
+
|
59
|
+
def attr_2
|
60
|
+
end
|
61
|
+
|
62
|
+
def attr_3
|
63
|
+
end
|
64
|
+
|
65
|
+
def attr_4
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
attrs = generate_attributes(21)
|
70
|
+
attrs << :children
|
71
|
+
filters = {
|
72
|
+
instance: attrs,
|
73
|
+
children: generate_attributes(11)
|
74
|
+
}
|
75
|
+
Benchmark.run("NoFilters") do
|
76
|
+
Panko::SerializationDescriptor.build(ParentSerializer)
|
77
|
+
end
|
78
|
+
|
79
|
+
Benchmark.run("Attribute") do
|
80
|
+
Panko::SerializationDescriptor.build(ParentSerializer, only: [:children])
|
81
|
+
end
|
82
|
+
|
83
|
+
Benchmark.run("AssociationFilters") do
|
84
|
+
Panko::SerializationDescriptor.build(ParentSerializer, only: filters)
|
85
|
+
end
|
@@ -62,7 +62,7 @@ void serialize_fields(VALUE subject,
|
|
62
62
|
serialize_method_fields(subject, str_writer, descriptor, context);
|
63
63
|
}
|
64
64
|
|
65
|
-
void
|
65
|
+
void serialize_has_one_associations(VALUE subject,
|
66
66
|
VALUE str_writer,
|
67
67
|
VALUE context,
|
68
68
|
SerializationDescriptor descriptor,
|
@@ -84,7 +84,7 @@ void serialize_has_one_associatoins(VALUE subject,
|
|
84
84
|
}
|
85
85
|
}
|
86
86
|
|
87
|
-
void
|
87
|
+
void serialize_has_many_associations(VALUE subject,
|
88
88
|
VALUE str_writer,
|
89
89
|
VALUE context,
|
90
90
|
SerializationDescriptor descriptor,
|
@@ -116,12 +116,12 @@ VALUE serialize_subject(VALUE key,
|
|
116
116
|
serialize_fields(subject, str_writer, descriptor, context);
|
117
117
|
|
118
118
|
if (RARRAY_LEN(descriptor->has_one_associations) >= 0) {
|
119
|
-
|
119
|
+
serialize_has_one_associations(subject, str_writer, context, descriptor,
|
120
120
|
descriptor->has_one_associations);
|
121
121
|
}
|
122
122
|
|
123
123
|
if (RARRAY_LEN(descriptor->has_many_associations) >= 0) {
|
124
|
-
|
124
|
+
serialize_has_many_associations(subject, str_writer, context, descriptor,
|
125
125
|
descriptor->has_many_associations);
|
126
126
|
}
|
127
127
|
|
@@ -35,6 +35,8 @@ module Panko
|
|
35
35
|
# Applies attributes and association filters
|
36
36
|
#
|
37
37
|
def apply_filters(options)
|
38
|
+
return unless options.key?(:only) || options.key?(:except)
|
39
|
+
|
38
40
|
attributes_only_filters, associations_only_filters = resolve_filters(options, :only)
|
39
41
|
attributes_except_filters, associations_except_filters = resolve_filters(options, :except)
|
40
42
|
|
@@ -50,36 +52,57 @@ module Panko
|
|
50
52
|
attributes_except_filters
|
51
53
|
)
|
52
54
|
|
53
|
-
self.has_many_associations
|
54
|
-
self.has_many_associations
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
unless self.has_many_associations.empty?
|
56
|
+
self.has_many_associations = apply_association_filters(
|
57
|
+
self.has_many_associations,
|
58
|
+
{ attributes: attributes_only_filters, associations: associations_only_filters },
|
59
|
+
{ attributes: attributes_except_filters, associations: associations_except_filters }
|
60
|
+
)
|
61
|
+
end
|
58
62
|
|
59
|
-
self.has_one_associations
|
60
|
-
self.has_one_associations
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
unless self.has_one_associations.empty?
|
64
|
+
self.has_one_associations = apply_association_filters(
|
65
|
+
self.has_one_associations,
|
66
|
+
{ attributes: attributes_only_filters, associations: associations_only_filters },
|
67
|
+
{ attributes: attributes_except_filters, associations: associations_except_filters }
|
68
|
+
)
|
69
|
+
end
|
64
70
|
end
|
65
71
|
|
66
72
|
def apply_association_filters(associations, only_filters, except_filters)
|
67
|
-
attributes_only_filters = only_filters[:attributes]
|
68
|
-
|
73
|
+
attributes_only_filters = only_filters[:attributes] || []
|
74
|
+
unless attributes_only_filters.empty?
|
75
|
+
associations.select! do |association|
|
76
|
+
attributes_only_filters.include?(association.first)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
69
80
|
attributes_except_filters = except_filters[:attributes] || []
|
81
|
+
unless attributes_except_filters.empty?
|
82
|
+
associations.reject! do |association|
|
83
|
+
attributes_except_filters.include?(association.first)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
associations_only_filters = only_filters[:associations]
|
88
|
+
associations_except_filters = except_filters[:associations]
|
70
89
|
|
90
|
+
if associations_only_filters.empty? && associations_except_filters.empty?
|
91
|
+
return associations
|
92
|
+
end
|
71
93
|
|
72
94
|
associations.map do |association|
|
73
95
|
name = association.first
|
74
|
-
next if attributes_except_filters.include? name
|
75
|
-
next unless attributes_only_filters.include? name
|
76
|
-
|
77
96
|
descriptor = association.last
|
78
97
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
98
|
+
only_filter = associations_only_filters[name]
|
99
|
+
except_filter = associations_except_filters[name]
|
100
|
+
|
101
|
+
filters = {}
|
102
|
+
filters[:only] = only_filter unless only_filter.nil?
|
103
|
+
filters[:except] = except_filter unless except_filter.nil?
|
104
|
+
|
105
|
+
descriptor.apply_filters(filters) unless filters.empty?
|
83
106
|
|
84
107
|
association
|
85
108
|
end.compact
|
data/lib/panko/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panko_serializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yosi Attias
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- benchmarks/bm_controller.rb
|
106
106
|
- benchmarks/bm_panko_json.rb
|
107
107
|
- benchmarks/bm_panko_object.rb
|
108
|
+
- benchmarks/bm_serialization_descriptor.rb
|
108
109
|
- benchmarks/profile.rb
|
109
110
|
- benchmarks/sanity.rb
|
110
111
|
- benchmarks/setup.rb
|