panko_serializer 0.1.10 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -2
- data/Gemfile +8 -9
- data/benchmarks/type_casts/bm_active_record.rb +41 -13
- data/benchmarks/type_casts/bm_panko.rb +8 -3
- data/ext/panko_serializer/attributes_iterator.c +49 -25
- data/ext/panko_serializer/type_cast.c +11 -5
- data/lib/panko/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f657c0585ef9811fe8d9fcf0e2d1556869823b72
|
4
|
+
data.tar.gz: 9e4cc917aabb38d3b803e0978fc312b5fe5696da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd44b3774e47cbd74a400c53040f41bc9edb7f58c1dc63a1e7c530827b2c878948bdfebe6c0250c59ea5af122ef281113f09402fd282e4f16aff5d883ca5df8f
|
7
|
+
data.tar.gz: 3da4b8644375ed05481a7d9e00e27082ee5274eea06a60282395abe5aab06b90f0c17d4b525bcc4c44c08a5e48108f6cc725e9c6a6e85ee40c6c70b4f21e9102
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -2,7 +2,13 @@ sudo: false
|
|
2
2
|
cache: bundler
|
3
3
|
language: ruby
|
4
4
|
rvm:
|
5
|
-
- 2.4.
|
6
|
-
|
5
|
+
- 2.4.2
|
6
|
+
install: bundle install --path=vendor/bundle --retry=3 --jobs=3
|
7
7
|
before_install: gem install bundler
|
8
8
|
after_success: bundle exec rake benchmarks
|
9
|
+
|
10
|
+
env:
|
11
|
+
matrix:
|
12
|
+
- "RAILS_VERSION=4.2"
|
13
|
+
- "RAILS_VERSION=5.0"
|
14
|
+
- "RAILS_VERSION=5.1"
|
data/Gemfile
CHANGED
@@ -3,15 +3,14 @@ source "https://rubygems.org"
|
|
3
3
|
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
gem "
|
10
|
-
gem "
|
11
|
-
gem "
|
12
|
-
gem "
|
13
|
-
gem "
|
14
|
-
gem "activerecord", gem_version, group: :test
|
6
|
+
rails_version = "~> #{ENV.fetch("RAILS_VERSION", "4.2")}"
|
7
|
+
|
8
|
+
gem "rails", rails_version
|
9
|
+
gem "railties", rails_version
|
10
|
+
gem "activesupport", rails_version
|
11
|
+
gem "activemodel", rails_version
|
12
|
+
gem "actionpack", rails_version
|
13
|
+
gem "activerecord", rails_version, group: :test
|
15
14
|
|
16
15
|
group :benchmarks do
|
17
16
|
gem "sqlite3"
|
@@ -3,14 +3,27 @@ require_relative "./support"
|
|
3
3
|
|
4
4
|
def ar_type_convert(type_klass, from, to)
|
5
5
|
converter = type_klass.new
|
6
|
-
assert type_klass.name, converter.type_cast_from_database(from), to
|
7
6
|
|
8
|
-
|
9
|
-
converter.type_cast_from_database(from)
|
10
|
-
|
7
|
+
if ENV["RAILS_VERSION"].start_with? "4.2"
|
8
|
+
assert type_klass.name, converter.type_cast_from_database(from), to
|
9
|
+
|
10
|
+
Benchmark.run("#{type_klass.name}_TypeCast") do
|
11
|
+
converter.type_cast_from_database(from)
|
12
|
+
end
|
13
|
+
|
14
|
+
Benchmark.run("#{type_klass.name}_NoTypeCast") do
|
15
|
+
converter.type_cast_from_database(to)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
assert type_klass.name, converter.deserialize(from), to
|
11
19
|
|
12
|
-
|
13
|
-
|
20
|
+
Benchmark.run("#{type_klass.name}_TypeCast") do
|
21
|
+
converter.deserialize(from)
|
22
|
+
end
|
23
|
+
|
24
|
+
Benchmark.run("#{type_klass.name}_NoTypeCast") do
|
25
|
+
converter.deserialize(to)
|
26
|
+
end
|
14
27
|
end
|
15
28
|
end
|
16
29
|
|
@@ -22,8 +35,14 @@ def utc_ar_time
|
|
22
35
|
type = ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime.new
|
23
36
|
converter = ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter.new(type)
|
24
37
|
|
25
|
-
|
26
|
-
|
38
|
+
if ENV["RAILS_VERSION"].start_with? "4.2"
|
39
|
+
Benchmark.run("#{tz}_#{type.class.name}_TypeCast") do
|
40
|
+
converter.type_cast_from_database(from).iso8601
|
41
|
+
end
|
42
|
+
else
|
43
|
+
Benchmark.run("#{tz}_#{type.class.name}_TypeCast") do
|
44
|
+
converter.deserialize(from).iso8601
|
45
|
+
end
|
27
46
|
end
|
28
47
|
end
|
29
48
|
|
@@ -35,8 +54,15 @@ def db_ar_time
|
|
35
54
|
|
36
55
|
from = "2017-07-10 09:26:40.937392"
|
37
56
|
|
38
|
-
|
39
|
-
|
57
|
+
|
58
|
+
if ENV["RAILS_VERSION"].start_with? "4.2"
|
59
|
+
Benchmark.run("ActiveRecord_Time_TypeCast_WithISO8601") do
|
60
|
+
converter.type_cast_from_database(from).iso8601
|
61
|
+
end
|
62
|
+
else
|
63
|
+
Benchmark.run("ActiveRecord_Time_TypeCast_WithISO8601") do
|
64
|
+
converter.deserialize(from).iso8601
|
65
|
+
end
|
40
66
|
end
|
41
67
|
end
|
42
68
|
|
@@ -48,9 +74,11 @@ ar_type_convert ActiveRecord::Type::Float, "Infinity", 0.0
|
|
48
74
|
ar_type_convert ActiveRecord::Type::Boolean, "true", true
|
49
75
|
ar_type_convert ActiveRecord::Type::Boolean, "t", true
|
50
76
|
|
51
|
-
|
52
|
-
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::
|
53
|
-
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "
|
77
|
+
if ENV["RAILS_VERSION"].start_with? "4.2"
|
78
|
+
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer, "1", 1
|
79
|
+
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "1.23", 1.23
|
80
|
+
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "Infinity", ::Float::INFINITY
|
81
|
+
end
|
54
82
|
ar_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Json, '{"a":1}', {a:1}
|
55
83
|
|
56
84
|
db_ar_time
|
@@ -44,6 +44,9 @@ def db_panko_time
|
|
44
44
|
Panko::_type_cast(converter, from)
|
45
45
|
end
|
46
46
|
end
|
47
|
+
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Json, '{"a":1}', {a:1}
|
48
|
+
db_panko_time
|
49
|
+
utc_panko_time
|
47
50
|
|
48
51
|
panko_type_convert ActiveRecord::Type::String, 1, "1"
|
49
52
|
panko_type_convert ActiveRecord::Type::Text, 1, "1"
|
@@ -53,9 +56,11 @@ panko_type_convert ActiveRecord::Type::Float, "Infinity", ::Float::INFINITY
|
|
53
56
|
panko_type_convert ActiveRecord::Type::Boolean, "true", true
|
54
57
|
panko_type_convert ActiveRecord::Type::Boolean, "t", true
|
55
58
|
|
56
|
-
|
57
|
-
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::
|
58
|
-
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "
|
59
|
+
if ENV["RAILS_VERSION"].start_with? "4.2"
|
60
|
+
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer, "1", 1
|
61
|
+
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "1.23", 1.23
|
62
|
+
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Float, "Infinity", ::Float::INFINITY
|
63
|
+
end
|
59
64
|
|
60
65
|
panko_type_convert ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Json, '{"a":1}', {a:1}
|
61
66
|
db_panko_time
|
@@ -14,19 +14,15 @@ VALUE read_attributes(VALUE obj) {
|
|
14
14
|
}
|
15
15
|
|
16
16
|
VALUE panko_read_lazy_attributes_hash(VALUE object) {
|
17
|
-
volatile VALUE attributes_set,
|
17
|
+
volatile VALUE attributes_set, lazy_attributes_hash;
|
18
18
|
|
19
19
|
attributes_set = read_attributes(object);
|
20
20
|
if (attributes_set == Qnil) {
|
21
21
|
return Qnil;
|
22
22
|
}
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
return Qnil;
|
27
|
-
}
|
28
|
-
|
29
|
-
return attributes_hash;
|
24
|
+
lazy_attributes_hash = read_attributes(attributes_set);
|
25
|
+
return lazy_attributes_hash;
|
30
26
|
}
|
31
27
|
|
32
28
|
void panko_read_types_and_value(VALUE attributes_hash,
|
@@ -38,28 +34,60 @@ void panko_read_types_and_value(VALUE attributes_hash,
|
|
38
34
|
*values = rb_ivar_get(attributes_hash, values_id);
|
39
35
|
}
|
40
36
|
|
37
|
+
bool panko_is_empty_hash(VALUE hash) {
|
38
|
+
if (hash == Qnil || hash == Qundef) {
|
39
|
+
return true;
|
40
|
+
}
|
41
|
+
|
42
|
+
return RHASH_SIZE(hash) == 0;
|
43
|
+
}
|
44
|
+
|
45
|
+
void read_attribute_from_hash(VALUE attributes_hash,
|
46
|
+
VALUE member,
|
47
|
+
volatile VALUE* value,
|
48
|
+
volatile VALUE* type) {
|
49
|
+
volatile VALUE attribute_metadata = rb_hash_aref(attributes_hash, member);
|
50
|
+
if (attribute_metadata != Qnil) {
|
51
|
+
*value = rb_ivar_get(attribute_metadata, value_before_type_cast_id);
|
52
|
+
*type = rb_ivar_get(attribute_metadata, type_id);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
41
56
|
VALUE panko_each_attribute(VALUE obj,
|
42
57
|
VALUE attributes,
|
43
58
|
VALUE aliases,
|
44
59
|
EachAttributeFunc func,
|
45
60
|
VALUE context) {
|
46
|
-
volatile VALUE
|
61
|
+
volatile VALUE lazy_attribute_hash, delegate_hash;
|
62
|
+
VALUE values = Qundef;
|
63
|
+
VALUE types = Qundef;
|
64
|
+
VALUE additional_types = Qundef;
|
47
65
|
int i;
|
48
66
|
|
49
|
-
|
50
|
-
if (
|
67
|
+
lazy_attribute_hash = panko_read_lazy_attributes_hash(obj);
|
68
|
+
if (lazy_attribute_hash == Qnil) {
|
51
69
|
return Qnil;
|
52
70
|
}
|
53
71
|
|
54
|
-
|
55
|
-
bool
|
72
|
+
bool tryToReadFromDelegateHash = false;
|
73
|
+
bool tryToReadFromAdditionalTypes = false;
|
56
74
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
75
|
+
// If lazy_attribute_hash is not ActiveRecord::LazyAttributeHash
|
76
|
+
// and it's actually hash, read from it
|
77
|
+
if (RB_TYPE_P(lazy_attribute_hash, T_HASH)) {
|
78
|
+
delegate_hash = lazy_attribute_hash;
|
79
|
+
tryToReadFromDelegateHash = true;
|
80
|
+
} else {
|
81
|
+
delegate_hash = rb_ivar_get(lazy_attribute_hash, delegate_hash_id);
|
82
|
+
tryToReadFromDelegateHash = !panko_is_empty_hash(delegate_hash);
|
61
83
|
|
62
|
-
|
84
|
+
panko_read_types_and_value(lazy_attribute_hash, &types, &additional_types,
|
85
|
+
&values);
|
86
|
+
|
87
|
+
tryToReadFromAdditionalTypes = !panko_is_empty_hash(additional_types);
|
88
|
+
}
|
89
|
+
|
90
|
+
bool tryToReadFromAliases = !panko_is_empty_hash(aliases);
|
63
91
|
|
64
92
|
for (i = 0; i < RARRAY_LEN(attributes); i++) {
|
65
93
|
volatile VALUE member_raw = RARRAY_AREF(attributes, i);
|
@@ -72,14 +100,10 @@ VALUE panko_each_attribute(VALUE obj,
|
|
72
100
|
// If the object was create in memory `User.new(name: "Yosi")`
|
73
101
|
// it won't exist in types/values
|
74
102
|
if (tryToReadFromDelegateHash) {
|
75
|
-
|
76
|
-
if (attribute_metadata != Qnil) {
|
77
|
-
value = rb_ivar_get(attribute_metadata, value_before_type_cast_id);
|
78
|
-
type_metadata = rb_ivar_get(attribute_metadata, type_id);
|
79
|
-
}
|
103
|
+
read_attribute_from_hash(delegate_hash, member, &value, &type_metadata);
|
80
104
|
}
|
81
105
|
|
82
|
-
if (value == Qundef) {
|
106
|
+
if (values != Qundef && value == Qundef) {
|
83
107
|
value = rb_hash_aref(values, member);
|
84
108
|
|
85
109
|
if (tryToReadFromAdditionalTypes) {
|
@@ -90,9 +114,9 @@ VALUE panko_each_attribute(VALUE obj,
|
|
90
114
|
}
|
91
115
|
}
|
92
116
|
|
93
|
-
if(tryToReadFromAliases) {
|
117
|
+
if (tryToReadFromAliases) {
|
94
118
|
volatile VALUE alias_name = rb_hash_aref(aliases, member_raw);
|
95
|
-
if(alias_name != Qnil) {
|
119
|
+
if (alias_name != Qnil) {
|
96
120
|
member = rb_sym2str(alias_name);
|
97
121
|
}
|
98
122
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#include "type_cast.h"
|
2
2
|
#include "time_conversion.h"
|
3
3
|
|
4
|
-
ID
|
4
|
+
ID deserialize_from_db_id = 0;
|
5
5
|
ID to_s_id = 0;
|
6
6
|
ID to_i_id = 0;
|
7
7
|
|
@@ -79,7 +79,7 @@ void cache_type_lookup() {
|
|
79
79
|
|
80
80
|
initiailized = 1;
|
81
81
|
|
82
|
-
VALUE ar, ar_type;
|
82
|
+
VALUE ar, ar_type, ar_type_methods;
|
83
83
|
|
84
84
|
ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
|
85
85
|
|
@@ -93,6 +93,13 @@ void cache_type_lookup() {
|
|
93
93
|
ar_boolean_type = rb_const_get_at(ar_type, rb_intern("Boolean"));
|
94
94
|
ar_date_time_type = rb_const_get_at(ar_type, rb_intern("DateTime"));
|
95
95
|
|
96
|
+
ar_type_methods = rb_class_instance_methods(0, NULL, ar_string_type);
|
97
|
+
if(rb_ary_includes(ar_type_methods, rb_to_symbol(rb_str_new_cstr("deserialize")))) {
|
98
|
+
deserialize_from_db_id = rb_intern("deserialize");
|
99
|
+
} else {
|
100
|
+
deserialize_from_db_id = rb_intern("type_cast_from_database");
|
101
|
+
}
|
102
|
+
|
96
103
|
// TODO: if we get error or not, add this to some debug log
|
97
104
|
int isErrored;
|
98
105
|
rb_protect(cache_postgres_type_lookup, ar, &isErrored);
|
@@ -241,7 +248,7 @@ VALUE cast_date_time_type(VALUE value) {
|
|
241
248
|
}
|
242
249
|
|
243
250
|
VALUE type_cast(VALUE type_metadata, VALUE value) {
|
244
|
-
if(value == Qnil || value == Qundef) {
|
251
|
+
if (value == Qnil || value == Qundef) {
|
245
252
|
return value;
|
246
253
|
}
|
247
254
|
|
@@ -261,7 +268,7 @@ VALUE type_cast(VALUE type_metadata, VALUE value) {
|
|
261
268
|
}
|
262
269
|
|
263
270
|
if (typeCastedValue == Qundef) {
|
264
|
-
return rb_funcall(type_metadata,
|
271
|
+
return rb_funcall(type_metadata, deserialize_from_db_id, 1, value);
|
265
272
|
}
|
266
273
|
|
267
274
|
return typeCastedValue;
|
@@ -272,7 +279,6 @@ VALUE public_type_cast(VALUE module, VALUE type_metadata, VALUE value) {
|
|
272
279
|
}
|
273
280
|
|
274
281
|
void panko_init_type_cast(VALUE mPanko) {
|
275
|
-
type_cast_from_database_id = rb_intern_const("type_cast_from_database");
|
276
282
|
to_s_id = rb_intern_const("to_s");
|
277
283
|
to_i_id = rb_intern_const("to_i");
|
278
284
|
|
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.
|
4
|
+
version: 0.2.0
|
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-10-
|
11
|
+
date: 2017-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|