panko_serializer 0.8.5 → 1.0.0
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 +6 -4
- data/lib/panko/array_serializer.rb +55 -16
- data/lib/panko/code_gen/active_record/access_classifier.rb +65 -0
- data/lib/panko/code_gen/active_record/define_attribute_methods.rb +13 -0
- data/lib/panko/code_gen/code_builder.rb +32 -0
- data/lib/panko/code_gen/compile_cache.rb +28 -0
- data/lib/panko/code_gen/compiler.rb +56 -0
- data/lib/panko/code_gen/config.rb +79 -0
- data/lib/panko/code_gen/datetime_format.rb +38 -0
- data/lib/panko/code_gen/descriptor.rb +136 -0
- data/lib/panko/code_gen/descriptor_builder.rb +166 -0
- data/lib/panko/code_gen/dump.rb +52 -0
- data/lib/panko/code_gen/errors.rb +21 -0
- data/lib/panko/code_gen/filter.rb +29 -0
- data/lib/panko/code_gen/filter_adapter.rb +44 -0
- data/lib/panko/code_gen/filters/indexed.rb +62 -0
- data/lib/panko/code_gen/filters/none.rb +19 -0
- data/lib/panko/code_gen/generator.rb +23 -0
- data/lib/panko/code_gen/generators/banner.rb +27 -0
- data/lib/panko/code_gen/generators/class_emitter.rb +120 -0
- data/lib/panko/code_gen/generators/cycle_membership.rb +53 -0
- data/lib/panko/code_gen/generators/descriptor_walk.rb +22 -0
- data/lib/panko/code_gen/generators/fanout.rb +60 -0
- data/lib/panko/code_gen/generators/field_index.rb +31 -0
- data/lib/panko/code_gen/generators/field_walk.rb +38 -0
- data/lib/panko/code_gen/generators/generated_names.rb +73 -0
- data/lib/panko/code_gen/generators/hash_sink.rb +217 -0
- data/lib/panko/code_gen/generators/json_sink.rb +290 -0
- data/lib/panko/code_gen/generators/record_access/generic.rb +92 -0
- data/lib/panko/code_gen/generators/record_access/specialized.rb +90 -0
- data/lib/panko/code_gen/generators/release.rb +60 -0
- data/lib/panko/code_gen/generators/sink.rb +80 -0
- data/lib/panko/code_gen/instance_pool.rb +27 -0
- data/lib/panko/code_gen/runtime.rb +27 -0
- data/lib/panko/code_gen/serializer_cache.rb +242 -0
- data/lib/panko/code_gen/validators/callable_arity.rb +42 -0
- data/lib/panko/code_gen/validators/name_uniqueness.rb +44 -0
- data/lib/panko/code_gen/validators/source_resolution.rb +48 -0
- data/lib/panko/code_gen/validators/validator.rb +19 -0
- data/lib/panko/code_gen/writers_pool.rb +51 -0
- data/lib/panko/code_gen.rb +82 -0
- data/lib/panko/compile_all.rb +80 -0
- data/lib/panko/compile_all_result.rb +21 -0
- data/lib/panko/config.rb +71 -0
- data/lib/panko/descriptor.rb +93 -0
- data/lib/panko/response.rb +40 -8
- data/lib/panko/serializer.rb +175 -91
- data/lib/panko/serializer_resolver.rb +2 -8
- data/lib/panko/version.rb +1 -1
- data/lib/panko_serializer.rb +3 -5
- metadata +49 -35
- data/ext/panko_serializer/attributes_writer/active_record.c +0 -181
- data/ext/panko_serializer/attributes_writer/active_record.h +0 -17
- data/ext/panko_serializer/attributes_writer/attributes_writer.c +0 -55
- data/ext/panko_serializer/attributes_writer/attributes_writer.h +0 -35
- data/ext/panko_serializer/attributes_writer/common.c +0 -10
- data/ext/panko_serializer/attributes_writer/common.h +0 -9
- data/ext/panko_serializer/attributes_writer/hash.c +0 -13
- data/ext/panko_serializer/attributes_writer/hash.h +0 -7
- data/ext/panko_serializer/attributes_writer/plain.c +0 -13
- data/ext/panko_serializer/attributes_writer/plain.h +0 -7
- data/ext/panko_serializer/attributes_writer/type_cast/time_conversion.c +0 -156
- data/ext/panko_serializer/attributes_writer/type_cast/time_conversion.h +0 -10
- data/ext/panko_serializer/attributes_writer/type_cast/type_cast.c +0 -409
- data/ext/panko_serializer/attributes_writer/type_cast/type_cast.h +0 -81
- data/ext/panko_serializer/common.h +0 -9
- data/ext/panko_serializer/extconf.rb +0 -28
- data/ext/panko_serializer/panko_serializer.c +0 -181
- data/ext/panko_serializer/panko_serializer.h +0 -12
- data/ext/panko_serializer/serialization_descriptor/association.c +0 -90
- data/ext/panko_serializer/serialization_descriptor/association.h +0 -20
- data/ext/panko_serializer/serialization_descriptor/attribute.c +0 -96
- data/ext/panko_serializer/serialization_descriptor/attribute.h +0 -27
- data/ext/panko_serializer/serialization_descriptor/serialization_descriptor.c +0 -177
- data/ext/panko_serializer/serialization_descriptor/serialization_descriptor.h +0 -30
- data/lib/panko/association.rb +0 -17
- data/lib/panko/attribute.rb +0 -29
- data/lib/panko/object_writer.rb +0 -68
- data/lib/panko/serialization_descriptor.rb +0 -180
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
#include "type_cast.h"
|
|
2
|
-
|
|
3
|
-
#include "time_conversion.h"
|
|
4
|
-
|
|
5
|
-
ID deserialize_from_db_id = 0;
|
|
6
|
-
ID to_s_id = 0;
|
|
7
|
-
ID to_i_id = 0;
|
|
8
|
-
|
|
9
|
-
static VALUE oj_type = Qundef;
|
|
10
|
-
static VALUE oj_parseerror_type = Qundef;
|
|
11
|
-
ID oj_sc_parse_id = 0;
|
|
12
|
-
|
|
13
|
-
// Caching ActiveRecord Types
|
|
14
|
-
static VALUE ar_string_type = Qundef;
|
|
15
|
-
static VALUE ar_text_type = Qundef;
|
|
16
|
-
static VALUE ar_float_type = Qundef;
|
|
17
|
-
static VALUE ar_integer_type = Qundef;
|
|
18
|
-
static VALUE ar_boolean_type = Qundef;
|
|
19
|
-
static VALUE ar_date_time_type = Qundef;
|
|
20
|
-
static VALUE ar_time_zone_converter = Qundef;
|
|
21
|
-
static VALUE ar_json_type = Qundef;
|
|
22
|
-
|
|
23
|
-
static VALUE ar_pg_integer_type = Qundef;
|
|
24
|
-
static VALUE ar_pg_float_type = Qundef;
|
|
25
|
-
static VALUE ar_pg_uuid_type = Qundef;
|
|
26
|
-
static VALUE ar_pg_json_type = Qundef;
|
|
27
|
-
static VALUE ar_pg_jsonb_type = Qundef;
|
|
28
|
-
static VALUE ar_pg_array_type = Qundef;
|
|
29
|
-
static VALUE ar_pg_date_time_type = Qundef;
|
|
30
|
-
static VALUE ar_pg_timestamp_type = Qundef;
|
|
31
|
-
|
|
32
|
-
static int initiailized = 0;
|
|
33
|
-
|
|
34
|
-
VALUE cache_postgres_type_lookup(VALUE ar) {
|
|
35
|
-
VALUE ar_connection_adapters, ar_postgresql, ar_oid;
|
|
36
|
-
|
|
37
|
-
if (rb_const_defined_at(ar, rb_intern("ConnectionAdapters")) != (int)Qtrue) {
|
|
38
|
-
return Qfalse;
|
|
39
|
-
}
|
|
40
|
-
ar_connection_adapters = rb_const_get_at(ar, rb_intern("ConnectionAdapters"));
|
|
41
|
-
|
|
42
|
-
if (rb_const_defined_at(ar_connection_adapters, rb_intern("PostgreSQL")) !=
|
|
43
|
-
(int)Qtrue) {
|
|
44
|
-
return Qfalse;
|
|
45
|
-
}
|
|
46
|
-
ar_postgresql =
|
|
47
|
-
rb_const_get_at(ar_connection_adapters, rb_intern("PostgreSQL"));
|
|
48
|
-
|
|
49
|
-
if (rb_const_defined_at(ar_postgresql, rb_intern("OID")) != (int)Qtrue) {
|
|
50
|
-
return Qfalse;
|
|
51
|
-
}
|
|
52
|
-
ar_oid = rb_const_get_at(ar_postgresql, rb_intern("OID"));
|
|
53
|
-
|
|
54
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Float")) == (int)Qtrue) {
|
|
55
|
-
ar_pg_float_type = rb_const_get_at(ar_oid, rb_intern("Float"));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Integer")) == (int)Qtrue) {
|
|
59
|
-
ar_pg_integer_type = rb_const_get_at(ar_oid, rb_intern("Integer"));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Uuid")) == (int)Qtrue) {
|
|
63
|
-
ar_pg_uuid_type = rb_const_get_at(ar_oid, rb_intern("Uuid"));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Json")) == (int)Qtrue) {
|
|
67
|
-
ar_pg_json_type = rb_const_get_at(ar_oid, rb_intern("Json"));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Jsonb")) == (int)Qtrue) {
|
|
71
|
-
ar_pg_jsonb_type = rb_const_get_at(ar_oid, rb_intern("Jsonb"));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (rb_const_defined_at(ar_oid, rb_intern("DateTime")) == (int)Qtrue) {
|
|
75
|
-
ar_pg_date_time_type = rb_const_get_at(ar_oid, rb_intern("DateTime"));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (rb_const_defined_at(ar_oid, rb_intern("Timestamp")) == (int)Qtrue) {
|
|
79
|
-
ar_pg_timestamp_type = rb_const_get_at(ar_oid, rb_intern("Timestamp"));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return Qtrue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
VALUE cache_time_zone_type_lookup(VALUE ar) {
|
|
86
|
-
VALUE ar_attr_methods, ar_time_zone_conversion;
|
|
87
|
-
|
|
88
|
-
// ActiveRecord::AttributeMethods
|
|
89
|
-
if (rb_const_defined_at(ar, rb_intern("AttributeMethods")) != (int)Qtrue) {
|
|
90
|
-
return Qfalse;
|
|
91
|
-
}
|
|
92
|
-
ar_attr_methods = rb_const_get_at(ar, rb_intern("AttributeMethods"));
|
|
93
|
-
|
|
94
|
-
// ActiveRecord::AttributeMethods::TimeZoneConversion
|
|
95
|
-
if (rb_const_defined_at(ar_attr_methods, rb_intern("TimeZoneConversion")) !=
|
|
96
|
-
(int)Qtrue) {
|
|
97
|
-
return Qfalse;
|
|
98
|
-
}
|
|
99
|
-
ar_time_zone_conversion =
|
|
100
|
-
rb_const_get_at(ar_attr_methods, rb_intern("TimeZoneConversion"));
|
|
101
|
-
|
|
102
|
-
if (rb_const_defined_at(ar_time_zone_conversion,
|
|
103
|
-
rb_intern("TimeZoneConverter")) != (int)Qtrue) {
|
|
104
|
-
return Qfalse;
|
|
105
|
-
}
|
|
106
|
-
ar_time_zone_converter =
|
|
107
|
-
rb_const_get_at(ar_time_zone_conversion, rb_intern("TimeZoneConverter"));
|
|
108
|
-
|
|
109
|
-
return Qtrue;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
void cache_type_lookup() {
|
|
113
|
-
if (initiailized == 1) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
initiailized = 1;
|
|
118
|
-
|
|
119
|
-
VALUE ar, ar_type, ar_type_methods;
|
|
120
|
-
|
|
121
|
-
ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
|
|
122
|
-
|
|
123
|
-
// ActiveRecord::Type
|
|
124
|
-
ar_type = rb_const_get_at(ar, rb_intern("Type"));
|
|
125
|
-
|
|
126
|
-
ar_string_type = rb_const_get_at(ar_type, rb_intern("String"));
|
|
127
|
-
ar_text_type = rb_const_get_at(ar_type, rb_intern("Text"));
|
|
128
|
-
ar_float_type = rb_const_get_at(ar_type, rb_intern("Float"));
|
|
129
|
-
ar_integer_type = rb_const_get_at(ar_type, rb_intern("Integer"));
|
|
130
|
-
ar_boolean_type = rb_const_get_at(ar_type, rb_intern("Boolean"));
|
|
131
|
-
ar_date_time_type = rb_const_get_at(ar_type, rb_intern("DateTime"));
|
|
132
|
-
|
|
133
|
-
ar_type_methods = rb_class_instance_methods(0, NULL, ar_string_type);
|
|
134
|
-
if (rb_ary_includes(ar_type_methods,
|
|
135
|
-
rb_to_symbol(rb_str_new_cstr("deserialize")))) {
|
|
136
|
-
deserialize_from_db_id = rb_intern("deserialize");
|
|
137
|
-
} else {
|
|
138
|
-
deserialize_from_db_id = rb_intern("type_cast_from_database");
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (rb_const_defined_at(ar_type, rb_intern("Json")) == (int)Qtrue) {
|
|
142
|
-
ar_json_type = rb_const_get_at(ar_type, rb_intern("Json"));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
int isErrored;
|
|
146
|
-
rb_protect(cache_postgres_type_lookup, ar, &isErrored);
|
|
147
|
-
if (isErrored) {
|
|
148
|
-
rb_set_errinfo(Qnil);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
rb_protect(cache_time_zone_type_lookup, ar, &isErrored);
|
|
152
|
-
if (isErrored) {
|
|
153
|
-
rb_set_errinfo(Qnil);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
bool is_string_or_text_type(VALUE type_klass) {
|
|
158
|
-
return type_klass == ar_string_type || type_klass == ar_text_type ||
|
|
159
|
-
(ar_pg_uuid_type != Qundef && type_klass == ar_pg_uuid_type);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
VALUE cast_string_or_text_type(VALUE value) {
|
|
163
|
-
if (RB_TYPE_P(value, T_STRING)) {
|
|
164
|
-
return value;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (value == Qtrue) {
|
|
168
|
-
return rb_str_new_cstr("t");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (value == Qfalse) {
|
|
172
|
-
return rb_str_new_cstr("f");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return rb_funcall(value, to_s_id, 0);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
bool is_float_type(VALUE type_klass) {
|
|
179
|
-
return type_klass == ar_float_type ||
|
|
180
|
-
(ar_pg_float_type != Qundef && type_klass == ar_pg_float_type);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
VALUE cast_float_type(VALUE value) {
|
|
184
|
-
if (RB_TYPE_P(value, T_FLOAT)) {
|
|
185
|
-
return value;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (RB_TYPE_P(value, T_STRING)) {
|
|
189
|
-
const char* val = StringValuePtr(value);
|
|
190
|
-
return rb_float_new(strtod(val, NULL));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return Qundef;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
bool is_integer_type(VALUE type_klass) {
|
|
197
|
-
return type_klass == ar_integer_type ||
|
|
198
|
-
(ar_pg_integer_type != Qundef && type_klass == ar_pg_integer_type);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
VALUE cast_integer_type(VALUE value) {
|
|
202
|
-
if (RB_INTEGER_TYPE_P(value)) {
|
|
203
|
-
return value;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (RB_TYPE_P(value, T_STRING)) {
|
|
207
|
-
const char* val = StringValuePtr(value);
|
|
208
|
-
if (strlen(val) == 0) {
|
|
209
|
-
return Qnil;
|
|
210
|
-
}
|
|
211
|
-
return rb_cstr2inum(val, 10);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (RB_FLOAT_TYPE_P(value)) {
|
|
215
|
-
// We are calling the `to_i` here, because ruby internal
|
|
216
|
-
// `flo_to_i` is not accessible
|
|
217
|
-
return rb_funcall(value, to_i_id, 0);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (value == Qtrue) {
|
|
221
|
-
return INT2NUM(1);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (value == Qfalse) {
|
|
225
|
-
return INT2NUM(0);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// At this point, we handled integer, float, string and booleans
|
|
229
|
-
// any thing other than this (array, hashes, etc) should result in nil
|
|
230
|
-
return Qnil;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
bool is_json_type(VALUE type_klass) {
|
|
234
|
-
return ((ar_pg_json_type != Qundef && type_klass == ar_pg_json_type) ||
|
|
235
|
-
(ar_pg_jsonb_type != Qundef && type_klass == ar_pg_jsonb_type) ||
|
|
236
|
-
(ar_json_type != Qundef && type_klass == ar_json_type));
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
bool is_boolean_type(VALUE type_klass) { return type_klass == ar_boolean_type; }
|
|
240
|
-
|
|
241
|
-
VALUE cast_boolean_type(VALUE value) {
|
|
242
|
-
if (value == Qtrue || value == Qfalse) {
|
|
243
|
-
return value;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (value == Qnil) {
|
|
247
|
-
return Qnil;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (RB_TYPE_P(value, T_STRING)) {
|
|
251
|
-
if (RSTRING_LEN(value) == 0) {
|
|
252
|
-
return Qnil;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const char* val = StringValuePtr(value);
|
|
256
|
-
|
|
257
|
-
bool isFalseValue =
|
|
258
|
-
(*val == '0' || (*val == 'f' || *val == 'F') ||
|
|
259
|
-
(strcmp(val, "false") == 0 || strcmp(val, "FALSE") == 0) ||
|
|
260
|
-
(strcmp(val, "off") == 0 || strcmp(val, "OFF") == 0));
|
|
261
|
-
|
|
262
|
-
return isFalseValue ? Qfalse : Qtrue;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
if (RB_INTEGER_TYPE_P(value)) {
|
|
266
|
-
return value == INT2NUM(1) ? Qtrue : Qfalse;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return Qundef;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
bool is_date_time_type(VALUE type_klass) {
|
|
273
|
-
return (type_klass == ar_date_time_type) ||
|
|
274
|
-
(ar_pg_date_time_type != Qundef &&
|
|
275
|
-
type_klass == ar_pg_date_time_type) ||
|
|
276
|
-
(ar_pg_timestamp_type != Qundef &&
|
|
277
|
-
type_klass == ar_pg_timestamp_type) ||
|
|
278
|
-
(ar_time_zone_converter != Qundef &&
|
|
279
|
-
type_klass == ar_time_zone_converter);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
VALUE cast_date_time_type(VALUE value) {
|
|
283
|
-
// Instead of take strings to comparing them to time zones
|
|
284
|
-
// and then comparing them back to string
|
|
285
|
-
// We will just make sure we have string on ISO8601 and it's utc
|
|
286
|
-
if (RB_TYPE_P(value, T_STRING)) {
|
|
287
|
-
const char* val = StringValuePtr(value);
|
|
288
|
-
// 'Z' in ISO8601 says it's UTC
|
|
289
|
-
if (val[strlen(val) - 1] == 'Z' && is_iso8601_time_string(val) == Qtrue) {
|
|
290
|
-
return value;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
volatile VALUE iso8601_string = iso_ar_iso_datetime_string(val);
|
|
294
|
-
if (iso8601_string != Qnil) {
|
|
295
|
-
return iso8601_string;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
return Qundef;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
VALUE rescue_func(VALUE _arg, VALUE _data) { return Qfalse; }
|
|
303
|
-
|
|
304
|
-
VALUE parse_json(VALUE value) {
|
|
305
|
-
return rb_funcall(oj_type, oj_sc_parse_id, 2, rb_cObject, value);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
VALUE is_json_value(VALUE value) {
|
|
309
|
-
if (!RB_TYPE_P(value, T_STRING)) {
|
|
310
|
-
return value;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (RSTRING_LEN(value) == 0) {
|
|
314
|
-
return Qfalse;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
volatile VALUE result =
|
|
318
|
-
rb_rescue2(parse_json, value, rescue_func, Qundef, oj_parseerror_type, 0);
|
|
319
|
-
|
|
320
|
-
if (NIL_P(result)) {
|
|
321
|
-
return Qtrue;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (result == Qfalse) {
|
|
325
|
-
return Qfalse;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// TODO: fix me!
|
|
329
|
-
return Qfalse;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
VALUE type_cast(VALUE type_metadata, VALUE value, volatile VALUE* isJson) {
|
|
333
|
-
if (value == Qnil || value == Qundef) {
|
|
334
|
-
return value;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
cache_type_lookup();
|
|
338
|
-
|
|
339
|
-
VALUE type_klass, typeCastedValue;
|
|
340
|
-
|
|
341
|
-
type_klass = CLASS_OF(type_metadata);
|
|
342
|
-
typeCastedValue = Qundef;
|
|
343
|
-
|
|
344
|
-
TypeCast typeCast;
|
|
345
|
-
for (typeCast = type_casts; typeCast->canCast != NULL; typeCast++) {
|
|
346
|
-
if (typeCast->canCast(type_klass)) {
|
|
347
|
-
typeCastedValue = typeCast->typeCast(value);
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
if (is_json_type(type_klass)) {
|
|
353
|
-
if (is_json_value(value) == Qfalse) {
|
|
354
|
-
return Qnil;
|
|
355
|
-
}
|
|
356
|
-
*isJson = Qtrue;
|
|
357
|
-
return value;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (typeCastedValue == Qundef) {
|
|
361
|
-
return rb_funcall(type_metadata, deserialize_from_db_id, 1, value);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return typeCastedValue;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
VALUE public_type_cast(int argc, VALUE* argv, VALUE self) {
|
|
368
|
-
VALUE type_metadata, value, isJson;
|
|
369
|
-
rb_scan_args(argc, argv, "21", &type_metadata, &value, &isJson);
|
|
370
|
-
|
|
371
|
-
if (isJson == Qnil || isJson == Qundef) {
|
|
372
|
-
isJson = Qfalse;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return type_cast(type_metadata, value, &isJson);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
void panko_init_type_cast(VALUE mPanko) {
|
|
379
|
-
to_s_id = rb_intern("to_s");
|
|
380
|
-
to_i_id = rb_intern("to_i");
|
|
381
|
-
|
|
382
|
-
oj_type = rb_const_get_at(rb_cObject, rb_intern("Oj"));
|
|
383
|
-
oj_parseerror_type = rb_const_get_at(oj_type, rb_intern("ParseError"));
|
|
384
|
-
oj_sc_parse_id = rb_intern("sc_parse");
|
|
385
|
-
|
|
386
|
-
// TODO: pass 3 arguments here
|
|
387
|
-
rb_define_singleton_method(mPanko, "_type_cast", public_type_cast, -1);
|
|
388
|
-
|
|
389
|
-
panko_init_time(mPanko);
|
|
390
|
-
|
|
391
|
-
rb_global_variable(&oj_type);
|
|
392
|
-
rb_global_variable(&oj_parseerror_type);
|
|
393
|
-
rb_global_variable(&ar_string_type);
|
|
394
|
-
rb_global_variable(&ar_text_type);
|
|
395
|
-
rb_global_variable(&ar_float_type);
|
|
396
|
-
rb_global_variable(&ar_integer_type);
|
|
397
|
-
rb_global_variable(&ar_boolean_type);
|
|
398
|
-
rb_global_variable(&ar_date_time_type);
|
|
399
|
-
rb_global_variable(&ar_time_zone_converter);
|
|
400
|
-
rb_global_variable(&ar_json_type);
|
|
401
|
-
rb_global_variable(&ar_pg_integer_type);
|
|
402
|
-
rb_global_variable(&ar_pg_float_type);
|
|
403
|
-
rb_global_variable(&ar_pg_uuid_type);
|
|
404
|
-
rb_global_variable(&ar_pg_json_type);
|
|
405
|
-
rb_global_variable(&ar_pg_jsonb_type);
|
|
406
|
-
rb_global_variable(&ar_pg_array_type);
|
|
407
|
-
rb_global_variable(&ar_pg_date_time_type);
|
|
408
|
-
rb_global_variable(&ar_pg_timestamp_type);
|
|
409
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <ruby.h>
|
|
4
|
-
#include <stdbool.h>
|
|
5
|
-
|
|
6
|
-
/*
|
|
7
|
-
* Type Casting
|
|
8
|
-
*
|
|
9
|
-
* We do "special" type casting which is mix of two inspirations:
|
|
10
|
-
* *) light records gem
|
|
11
|
-
* *) pg TextDecoders
|
|
12
|
-
*
|
|
13
|
-
* The whole idea behind those type casts, are to do the minimum required
|
|
14
|
-
* type casting in the most performant manner and *allocation free*.
|
|
15
|
-
*
|
|
16
|
-
* For example, in `ActiveRecord::Type::String` the type_cast_from_database
|
|
17
|
-
* creates new string, for known reasons, but, in serialization flow we don't
|
|
18
|
-
* need to create new string becuase we afraid of mutations.
|
|
19
|
-
*
|
|
20
|
-
* Since we know before hand, that we are only reading from the database, and
|
|
21
|
-
* *not* writing and the end result if for JSON we can skip some "defenses".
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
typedef bool (*TypeMatchFunc)(VALUE type_klass);
|
|
25
|
-
|
|
26
|
-
/*
|
|
27
|
-
* TypeCastFunc
|
|
28
|
-
*
|
|
29
|
-
* @return VALUE casted value or Qundef if not casted
|
|
30
|
-
*/
|
|
31
|
-
typedef VALUE (*TypeCastFunc)(VALUE value);
|
|
32
|
-
|
|
33
|
-
typedef struct _TypeCast {
|
|
34
|
-
TypeMatchFunc canCast;
|
|
35
|
-
TypeCastFunc typeCast;
|
|
36
|
-
}* TypeCast;
|
|
37
|
-
|
|
38
|
-
// ActiveRecord::Type::String
|
|
39
|
-
// ActiveRecord::Type::Text
|
|
40
|
-
bool is_string_or_text_type(VALUE type_klass);
|
|
41
|
-
VALUE cast_string_or_text_type(VALUE value);
|
|
42
|
-
|
|
43
|
-
// ActiveRecord::Type::Float
|
|
44
|
-
bool is_float_type(VALUE type_klass);
|
|
45
|
-
VALUE cast_float_type(VALUE value);
|
|
46
|
-
|
|
47
|
-
// ActiveRecord::Type::Integer
|
|
48
|
-
bool is_integer_type(VALUE type_klass);
|
|
49
|
-
VALUE cast_integer_type(VALUE value);
|
|
50
|
-
|
|
51
|
-
// ActiveRecord::ConnectoinAdapters::PostgreSQL::Json
|
|
52
|
-
bool is_json_type(VALUE type_klass);
|
|
53
|
-
VALUE cast_json_type(VALUE value);
|
|
54
|
-
|
|
55
|
-
// ActiveRecord::Type::Boolean
|
|
56
|
-
bool is_boolean_type(VALUE type_klass);
|
|
57
|
-
VALUE cast_boolean_type(VALUE value);
|
|
58
|
-
|
|
59
|
-
// ActiveRecord::Type::DateTime
|
|
60
|
-
// ActiveRecord::ConnectionAdapters::PostgreSQL::OID::DateTime
|
|
61
|
-
// ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
|
|
62
|
-
bool is_date_time_type(VALUE type_klass);
|
|
63
|
-
VALUE cast_date_time_type(VALUE value);
|
|
64
|
-
|
|
65
|
-
static struct _TypeCast type_casts[] = {
|
|
66
|
-
{is_string_or_text_type, cast_string_or_text_type},
|
|
67
|
-
{is_integer_type, cast_integer_type},
|
|
68
|
-
{is_boolean_type, cast_boolean_type},
|
|
69
|
-
{is_date_time_type, cast_date_time_type},
|
|
70
|
-
{is_float_type, cast_float_type},
|
|
71
|
-
|
|
72
|
-
{NULL, NULL}};
|
|
73
|
-
|
|
74
|
-
extern VALUE type_cast(VALUE type_metadata, VALUE value,
|
|
75
|
-
volatile VALUE* isJson);
|
|
76
|
-
void panko_init_type_cast(VALUE mPanko);
|
|
77
|
-
|
|
78
|
-
// Introduced in ruby 2.4
|
|
79
|
-
#ifndef RB_INTEGER_TYPE_P
|
|
80
|
-
#define RB_INTEGER_TYPE_P(obj) (RB_FIXNUM_P(obj) || RB_TYPE_P(obj, T_BIGNUM))
|
|
81
|
-
#endif
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require "mkmf"
|
|
3
|
-
require "pathname"
|
|
4
|
-
|
|
5
|
-
$CPPFLAGS += " -Wall"
|
|
6
|
-
|
|
7
|
-
extension_name = "panko_serializer"
|
|
8
|
-
dir_config(extension_name)
|
|
9
|
-
|
|
10
|
-
RbConfig.expand(srcdir = "$(srcdir)".dup)
|
|
11
|
-
|
|
12
|
-
# enum all source files
|
|
13
|
-
$srcs = Dir[File.join(srcdir, "**/*.c")]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Get all source directories recursivley
|
|
17
|
-
directories = Dir[File.join(srcdir, "**/*")].select { |f| File.directory?(f) }
|
|
18
|
-
directories = directories.map { |d| Pathname.new(d).relative_path_from(Pathname.new(srcdir)) }
|
|
19
|
-
directories.each do |dir|
|
|
20
|
-
# add include path to the internal folder
|
|
21
|
-
# $(srcdir) is a root folder, where "extconf.rb" is stored
|
|
22
|
-
$INCFLAGS << " -I$(srcdir)/#{dir}"
|
|
23
|
-
|
|
24
|
-
# add folder, where compiler can search source files
|
|
25
|
-
$VPATH << "$(srcdir)/#{dir}"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
create_makefile("panko/panko_serializer")
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
#include "panko_serializer.h"
|
|
2
|
-
|
|
3
|
-
#include <ruby.h>
|
|
4
|
-
|
|
5
|
-
static ID push_value_id;
|
|
6
|
-
static ID push_array_id;
|
|
7
|
-
static ID push_object_id;
|
|
8
|
-
static ID push_json_id;
|
|
9
|
-
static ID pop_id;
|
|
10
|
-
|
|
11
|
-
static ID to_a_id;
|
|
12
|
-
|
|
13
|
-
static ID object_id;
|
|
14
|
-
static ID serialization_context_id;
|
|
15
|
-
|
|
16
|
-
static VALUE SKIP = Qundef;
|
|
17
|
-
|
|
18
|
-
void write_value(VALUE str_writer, VALUE key, VALUE value, VALUE isJson) {
|
|
19
|
-
if (isJson == Qtrue) {
|
|
20
|
-
rb_funcall(str_writer, push_json_id, 2, value, key);
|
|
21
|
-
} else {
|
|
22
|
-
rb_funcall(str_writer, push_value_id, 2, value, key);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
void serialize_method_fields(VALUE object, VALUE str_writer,
|
|
27
|
-
SerializationDescriptor descriptor) {
|
|
28
|
-
if (RARRAY_LEN(descriptor->method_fields) == 0) {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
volatile VALUE method_fields, serializer, key;
|
|
33
|
-
long i;
|
|
34
|
-
|
|
35
|
-
method_fields = descriptor->method_fields;
|
|
36
|
-
|
|
37
|
-
serializer = descriptor->serializer;
|
|
38
|
-
rb_ivar_set(serializer, object_id, object);
|
|
39
|
-
|
|
40
|
-
for (i = 0; i < RARRAY_LEN(method_fields); i++) {
|
|
41
|
-
volatile VALUE raw_attribute = RARRAY_AREF(method_fields, i);
|
|
42
|
-
Attribute attribute = PANKO_ATTRIBUTE_READ(raw_attribute);
|
|
43
|
-
|
|
44
|
-
volatile VALUE result = rb_funcall(serializer, attribute->name_id, 0);
|
|
45
|
-
if (result != SKIP) {
|
|
46
|
-
key = attr_name_for_serialization(attribute);
|
|
47
|
-
write_value(str_writer, key, result, Qfalse);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
rb_ivar_set(serializer, object_id, Qnil);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
void serialize_fields(VALUE object, VALUE str_writer,
|
|
55
|
-
SerializationDescriptor descriptor) {
|
|
56
|
-
descriptor->attributes_writer.write_attributes(object, descriptor->attributes,
|
|
57
|
-
write_value, str_writer);
|
|
58
|
-
|
|
59
|
-
serialize_method_fields(object, str_writer, descriptor);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
void serialize_has_one_associations(VALUE object, VALUE str_writer,
|
|
63
|
-
VALUE associations) {
|
|
64
|
-
long i;
|
|
65
|
-
for (i = 0; i < RARRAY_LEN(associations); i++) {
|
|
66
|
-
volatile VALUE association_el = RARRAY_AREF(associations, i);
|
|
67
|
-
Association association = association_read(association_el);
|
|
68
|
-
|
|
69
|
-
volatile VALUE value = rb_funcall(object, association->name_id, 0);
|
|
70
|
-
|
|
71
|
-
if (NIL_P(value)) {
|
|
72
|
-
write_value(str_writer, association->name_str, value, Qfalse);
|
|
73
|
-
} else {
|
|
74
|
-
serialize_object(association->name_str, value, str_writer,
|
|
75
|
-
association->descriptor);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
void serialize_has_many_associations(VALUE object, VALUE str_writer,
|
|
81
|
-
VALUE associations) {
|
|
82
|
-
long i;
|
|
83
|
-
for (i = 0; i < RARRAY_LEN(associations); i++) {
|
|
84
|
-
volatile VALUE association_el = RARRAY_AREF(associations, i);
|
|
85
|
-
Association association = association_read(association_el);
|
|
86
|
-
|
|
87
|
-
volatile VALUE value = rb_funcall(object, association->name_id, 0);
|
|
88
|
-
|
|
89
|
-
if (NIL_P(value)) {
|
|
90
|
-
write_value(str_writer, association->name_str, value, Qfalse);
|
|
91
|
-
} else {
|
|
92
|
-
serialize_objects(association->name_str, value, str_writer,
|
|
93
|
-
association->descriptor);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
VALUE serialize_object(VALUE key, VALUE object, VALUE str_writer,
|
|
99
|
-
SerializationDescriptor descriptor) {
|
|
100
|
-
sd_set_writer(descriptor, object);
|
|
101
|
-
|
|
102
|
-
rb_funcall(str_writer, push_object_id, 1, key);
|
|
103
|
-
|
|
104
|
-
serialize_fields(object, str_writer, descriptor);
|
|
105
|
-
|
|
106
|
-
if (RARRAY_LEN(descriptor->has_one_associations) > 0) {
|
|
107
|
-
serialize_has_one_associations(object, str_writer,
|
|
108
|
-
descriptor->has_one_associations);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (RARRAY_LEN(descriptor->has_many_associations) > 0) {
|
|
112
|
-
serialize_has_many_associations(object, str_writer,
|
|
113
|
-
descriptor->has_many_associations);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
rb_funcall(str_writer, pop_id, 0);
|
|
117
|
-
|
|
118
|
-
return Qnil;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
VALUE serialize_objects(VALUE key, VALUE objects, VALUE str_writer,
|
|
122
|
-
SerializationDescriptor descriptor) {
|
|
123
|
-
long i;
|
|
124
|
-
|
|
125
|
-
rb_funcall(str_writer, push_array_id, 1, key);
|
|
126
|
-
|
|
127
|
-
if (!RB_TYPE_P(objects, T_ARRAY)) {
|
|
128
|
-
objects = rb_funcall(objects, to_a_id, 0);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
for (i = 0; i < RARRAY_LEN(objects); i++) {
|
|
132
|
-
volatile VALUE object = RARRAY_AREF(objects, i);
|
|
133
|
-
serialize_object(Qnil, object, str_writer, descriptor);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
rb_funcall(str_writer, pop_id, 0);
|
|
137
|
-
|
|
138
|
-
return Qnil;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
VALUE serialize_object_api(VALUE klass, VALUE object, VALUE str_writer,
|
|
142
|
-
VALUE descriptor) {
|
|
143
|
-
SerializationDescriptor sd = sd_read(descriptor);
|
|
144
|
-
return serialize_object(Qnil, object, str_writer, sd);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
VALUE serialize_objects_api(VALUE klass, VALUE objects, VALUE str_writer,
|
|
148
|
-
VALUE descriptor) {
|
|
149
|
-
serialize_objects(Qnil, objects, str_writer, sd_read(descriptor));
|
|
150
|
-
|
|
151
|
-
return Qnil;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
void Init_panko_serializer() {
|
|
155
|
-
push_value_id = rb_intern("push_value");
|
|
156
|
-
push_array_id = rb_intern("push_array");
|
|
157
|
-
push_object_id = rb_intern("push_object");
|
|
158
|
-
push_json_id = rb_intern("push_json");
|
|
159
|
-
pop_id = rb_intern("pop");
|
|
160
|
-
to_a_id = rb_intern("to_a");
|
|
161
|
-
object_id = rb_intern("@object");
|
|
162
|
-
serialization_context_id = rb_intern("@serialization_context");
|
|
163
|
-
|
|
164
|
-
VALUE mPanko = rb_define_module("Panko");
|
|
165
|
-
|
|
166
|
-
rb_define_singleton_method(mPanko, "serialize_object", serialize_object_api,
|
|
167
|
-
3);
|
|
168
|
-
|
|
169
|
-
rb_define_singleton_method(mPanko, "serialize_objects", serialize_objects_api,
|
|
170
|
-
3);
|
|
171
|
-
|
|
172
|
-
VALUE mPankoSerializer = rb_const_get(mPanko, rb_intern("Serializer"));
|
|
173
|
-
SKIP = rb_const_get(mPankoSerializer, rb_intern("SKIP"));
|
|
174
|
-
rb_global_variable(&SKIP);
|
|
175
|
-
|
|
176
|
-
panko_init_serialization_descriptor(mPanko);
|
|
177
|
-
init_attributes_writer(mPanko);
|
|
178
|
-
panko_init_type_cast(mPanko);
|
|
179
|
-
panko_init_attribute(mPanko);
|
|
180
|
-
panko_init_association(mPanko);
|
|
181
|
-
}
|