panko_serializer 0.1.8 → 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/yosiat/panko_serializer.svg?branch=master)](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
|