-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathinstance_query_shortcuts.cr
More file actions
112 lines (98 loc) · 3.58 KB
/
instance_query_shortcuts.cr
File metadata and controls
112 lines (98 loc) · 3.58 KB
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
require "./changes"
require "../query"
module Onyx::SQL::Model
# A shortcut method to genereate an insert `Query` pre-filled with actual `self` values.
# See `Query#insert`.
#
# NOTE: Will raise `NilAssertionError` in runtime if a field has `not_null: true` option and
# is actually `nil`. Conisder using `ClassQueryShortcuts#insert` instead.
#
# ```
# user = User.new(id: 42, name: "John")
# user.insert == Query(User).new.insert(id: 42, name: "John")
# ```
def insert : Query
before_insert
query = Query(self).new
{% for ivar in @type.instance_vars %}
# Skip foreign references. Because they are foreign, you know
{% unless ((a = ivar.annotation(Reference)) && !a[:key]) %}
{% ann = ivar.annotation(Field) || ivar.annotation(Reference) %}
{% if (ann && ann[:default]) || @type.annotation(Model::Options)[:primary_key].id == "@#{ivar.name}".id %}
unless @{{ivar.name}}.nil?
query.insert({{ivar.name}}: @{{ivar.name}}.not_nil!)
end
{% elsif ann && ann[:not_null] %}
if @{{ivar.name}}.nil?
raise NilAssertionError.new("{{@type}}@{{ivar.name}} must not be nil on {{@type}}#insert")
else
query.insert({{ivar.name}}: @{{ivar.name}}.not_nil!)
end
{% else %}
query.insert({{ivar.name}}: @{{ivar.name}})
{% end %}
{% end %}
{% end %}
query
end
# A shortcut method to genereate an update `Query` with *changeset* values.
# See `Query#update` and `Query#set`.
#
# ```
# user = User.new(id: 42, name: "John")
# changeset = user.changeset
# changeset.update(name: "Jake")
# user.update(changeset) == Query(User).new.update.set(name: "Jake").where(id: 42)
# ```
def update(changeset : Changeset(self, U)) : Query forall U
before_update
query = Query(self).new.update
{% begin %}
changeset.changes!.each do |key, value|
case key
{% for ivar in @type.instance_vars %}
{% unless (a = ivar.annotation(Reference)) && a[:foreign_key] %}
when {{ivar.name.stringify}}
{% if (a = ivar.annotation(Field) || ivar.annotation(Reference)) && a[:not_null] %}
if value.nil?
raise NilAssertionError.new("{{@type}}@{{ivar.name}} must not be nil on {{@type}}#update")
else
query.set({{ivar.name}}: value.as({{ivar.type}}).not_nil!)
end
{% else %}
query.set({{ivar.name}}: value.as({{ivar.type}}))
{% end %}
{% end %}
{% end %}
else
raise "BUG: Unrecognized Changeset({{@type}}) key :#{key}"
end
end
{% end %}
where_self(query)
end
# A shortcut method to genereate a delete `Query`.
# See `Query#delete`.
#
# ```
# user = User.new(id: 42)
# user.delete == Query(User).new.delete.where(id: 42)
# ```
def delete : Query
query = Query(self).new.delete
where_self(query)
end
protected def where_self(query : Query)
{% begin %}
{%
options = @type.annotation(Model::Options)
raise "Onyx::SQL::Model::Options annotation must be defined for #{@type}" unless options
pk = options[:primary_key]
raise "Onyx::SQL::Model::Options annotation is missing :primary_key option for #{@type}" unless pk
pk_ivar = @type.instance_vars.find { |iv| "@#{iv.name}".id == pk.id }
raise "Cannot find primary key field #{pk} for #{@type}" unless pk_ivar
%}
query.where({{pk_ivar.name}}: @{{pk_ivar.name}}.not_nil!)
{% end %}
end
end