/
field.cr
89 lines (76 loc) · 2.64 KB
/
field.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
require "./field/base"
require "./field/bool"
require "./field/date"
require "./field/date_time"
require "./field/email"
require "./field/file"
require "./field/float"
require "./field/int"
require "./field/string"
require "./field/uuid"
module Marten
abstract class Schema
module Field
annotation Registration
end
@@registry = {} of ::String => Base.class
# :nodoc:
def self.registry
@@registry
end
# Allows to register a new schema field implementation.
macro register(id, field_klass)
{% klass = field_klass.resolve %}
{% defining_type_method_name = "deserialize" %}
{% exposed_type = nil %}
{% method = klass.methods.find { |m| m.name == defining_type_method_name } %}
{% unless method %}
{% for ancestor_klass in klass.ancestors %}
{% method = ancestor_klass.methods.find { |m| m.name == defining_type_method_name } unless method %}
{% end %}
{% end %}
{% exposed_type = method.return_type %}
{% for method in klass.methods %}
{% if method.name == defining_type_method_name %}
{% exposed_type = method.return_type %}
{% end %}
{% end %}
{% unless exposed_type %}
{% for parent_klass in klass.ancestors %}
{% for method in parent_klass.methods %}
{% if !exposed_type && method.name == defining_type_method_name %}
{% exposed_type = method.return_type %}
{% end %}
{% end %}
{% end %}
{% end %}
@[Marten::Schema::Field::Registration(id: {{ id }}, exposed_type: {{ exposed_type }})]
class ::{{klass.id}}; end
Marten::Schema::Field.add_field_to_registry({{ id }}, {{ klass }})
end
# :nodoc:
def self.add_field_to_registry(id : ::String | Symbol, field_klass : Base.class)
@@registry[id.to_s] = field_klass
end
macro finished
{% field_types = [] of ::String %}
{% for k in Marten::Schema::Field::Base.all_subclasses %}
{% ann = k.annotation(Marten::Schema::Field::Registration) %}
{% if ann %}
{% field_types << ann[:exposed_type] %}
{% end %}
{% end %}
alias Any = {% for t, i in field_types %}{{ t }}{% if i + 1 < field_types.size %} | {% end %}{% end %}
end
register "bool", Bool
register "date", Date
register "date_time", DateTime
register "email", Email
register "file", File
register "float", Float
register "int", Int
register "string", String
register "uuid", UUID
end
end
end