graphoid 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +62 -0
- data/Rakefile +33 -0
- data/lib/graphoid/argument.rb +12 -0
- data/lib/graphoid/config.rb +19 -0
- data/lib/graphoid/definitions/filters.rb +57 -0
- data/lib/graphoid/definitions/inputs.rb +41 -0
- data/lib/graphoid/definitions/orders.rb +43 -0
- data/lib/graphoid/definitions/types.rb +119 -0
- data/lib/graphoid/drivers/active_record.rb +187 -0
- data/lib/graphoid/drivers/mongoid.rb +214 -0
- data/lib/graphoid/graphield.rb +32 -0
- data/lib/graphoid/grapho.rb +23 -0
- data/lib/graphoid/main.rb +21 -0
- data/lib/graphoid/mapper.rb +10 -0
- data/lib/graphoid/mutations/create.rb +49 -0
- data/lib/graphoid/mutations/delete.rb +49 -0
- data/lib/graphoid/mutations/processor.rb +31 -0
- data/lib/graphoid/mutations/structure.rb +9 -0
- data/lib/graphoid/mutations/update.rb +55 -0
- data/lib/graphoid/operators/attribute.rb +64 -0
- data/lib/graphoid/operators/inherited/belongs_to.rb +15 -0
- data/lib/graphoid/operators/inherited/embeds_many.rb +10 -0
- data/lib/graphoid/operators/inherited/embeds_one.rb +8 -0
- data/lib/graphoid/operators/inherited/has_many.rb +11 -0
- data/lib/graphoid/operators/inherited/has_one.rb +16 -0
- data/lib/graphoid/operators/inherited/many_to_many.rb +11 -0
- data/lib/graphoid/operators/relation.rb +70 -0
- data/lib/graphoid/queries/operation.rb +40 -0
- data/lib/graphoid/queries/processor.rb +45 -0
- data/lib/graphoid/queries/queries.rb +52 -0
- data/lib/graphoid/scalars.rb +87 -0
- data/lib/graphoid/utils.rb +39 -0
- data/lib/graphoid/version.rb +3 -0
- data/lib/graphoid.rb +36 -0
- metadata +120 -0
@@ -0,0 +1,214 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module MongoidDriver
|
3
|
+
class << self
|
4
|
+
def through?(type)
|
5
|
+
false
|
6
|
+
end
|
7
|
+
|
8
|
+
def has_and_belongs_to_many?(type)
|
9
|
+
type == Mongoid::Association::Referenced::HasAndBelongsToMany
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_many?(type)
|
13
|
+
type == Mongoid::Association::Referenced::HasMany
|
14
|
+
end
|
15
|
+
|
16
|
+
def belongs_to?(type)
|
17
|
+
type == Mongoid::Association::Referenced::BelongsTo
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_one?(type)
|
21
|
+
type == Mongoid::Association::Referenced::HasOne
|
22
|
+
end
|
23
|
+
|
24
|
+
def embeds_one?(type)
|
25
|
+
type == Mongoid::Association::Embedded::EmbedsOne
|
26
|
+
end
|
27
|
+
|
28
|
+
def embeds_many?(type)
|
29
|
+
type == Mongoid::Association::Embedded::EmbedsMany
|
30
|
+
end
|
31
|
+
|
32
|
+
def embedded_in?(type)
|
33
|
+
type == Mongoid::Association::Embedded::EmbeddedIn
|
34
|
+
end
|
35
|
+
|
36
|
+
def types_map
|
37
|
+
{
|
38
|
+
BSON::ObjectId => GraphQL::Types::ID,
|
39
|
+
Mongoid::Boolean => GraphQL::Types::Boolean,
|
40
|
+
#Graphoid::Upload => ApolloUploadServer::Upload,
|
41
|
+
|
42
|
+
Boolean => GraphQL::Types::Boolean,
|
43
|
+
Float => GraphQL::Types::Float,
|
44
|
+
Integer => GraphQL::Types::Int,
|
45
|
+
String => GraphQL::Types::String,
|
46
|
+
Object => GraphQL::Types::String,
|
47
|
+
Symbol => GraphQL::Types::String,
|
48
|
+
|
49
|
+
DateTime => Graphoid::Scalars::DateTime,
|
50
|
+
Time => Graphoid::Scalars::DateTime,
|
51
|
+
Date => Graphoid::Scalars::DateTime,
|
52
|
+
Array => Graphoid::Scalars::Array,
|
53
|
+
Hash => Graphoid::Scalars::Hash
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def class_of(relation)
|
58
|
+
{
|
59
|
+
Mongoid::Relations::Referenced::ManyToMany => ManyToMany,
|
60
|
+
Mongoid::Relations::Referenced::Many => HasMany,
|
61
|
+
Mongoid::Relations::Referenced::One => HasOne,
|
62
|
+
Mongoid::Relations::Referenced::In => BelongsTo,
|
63
|
+
Mongoid::Relations::Embedded::Many => EmbedsMany,
|
64
|
+
Mongoid::Relations::Embedded::One => EmbedsOne,
|
65
|
+
Mongoid::Relations::Embedded::In => Relation
|
66
|
+
}[relation.relation] || Relation
|
67
|
+
end
|
68
|
+
|
69
|
+
def inverse_name_of(relation)
|
70
|
+
relation.inverse_of
|
71
|
+
end
|
72
|
+
|
73
|
+
def fields_of(model)
|
74
|
+
model.respond_to?(:fields) ? model.fields.values : []
|
75
|
+
end
|
76
|
+
|
77
|
+
def relations_of(model)
|
78
|
+
model.relations
|
79
|
+
end
|
80
|
+
|
81
|
+
def skip(result, skip)
|
82
|
+
result.skip(skip)
|
83
|
+
end
|
84
|
+
|
85
|
+
def relation_type(relation)
|
86
|
+
relation.relation
|
87
|
+
end
|
88
|
+
|
89
|
+
def eager_load(selection, model)
|
90
|
+
referenced_relations = [
|
91
|
+
Mongoid::Relations::Referenced::ManyToMany,
|
92
|
+
Mongoid::Relations::Referenced::Many,
|
93
|
+
Mongoid::Relations::Referenced::One,
|
94
|
+
Mongoid::Relations::Referenced::In
|
95
|
+
]
|
96
|
+
|
97
|
+
properties = Graphoid::Queries::Processor.children_of(selection)
|
98
|
+
inclusions = Utils.symbolize(properties)
|
99
|
+
|
100
|
+
Relation.relations_of(model).each do |name, relation|
|
101
|
+
name = relation.name
|
102
|
+
next if inclusions.exclude?(name) || referenced_relations.exclude?(association.relation)
|
103
|
+
|
104
|
+
subselection = properties[name.to_s.camelize(:lower)]
|
105
|
+
children = Utils.symbolize(Graphoid::Queries::Processor.children_of(subselection))
|
106
|
+
relations = relation.class_name.constantize.reflections.values.map(&:name)
|
107
|
+
|
108
|
+
if (relations & children).empty?
|
109
|
+
model = model.includes(name)
|
110
|
+
else
|
111
|
+
model = model.includes(name, with: -> (instance) { Graphoid::Queries::Processor.eager_load(subselection, instance) })
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
model
|
116
|
+
end
|
117
|
+
|
118
|
+
def execute_and(scope, parsed)
|
119
|
+
scope.and(parsed)
|
120
|
+
end
|
121
|
+
|
122
|
+
def execute_or(scope, list)
|
123
|
+
list.map! do |object|
|
124
|
+
Graphoid::Queries::Processor.execute(scope, object).selector
|
125
|
+
end
|
126
|
+
scope.any_of(list)
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse(attribute, value, operator)
|
130
|
+
field = attribute.name
|
131
|
+
parsed = {}
|
132
|
+
case operator
|
133
|
+
when "gt", "gte", "lt", "lte", "in", "nin"
|
134
|
+
parsed[field.to_sym.send(operator)] = value
|
135
|
+
when "regex"
|
136
|
+
parsed[field.to_sym] = Regexp.new(value.to_s, Regexp::IGNORECASE)
|
137
|
+
when "contains"
|
138
|
+
parsed[field.to_sym] = Regexp.new(Regexp.quote(value.to_s), Regexp::IGNORECASE)
|
139
|
+
when "not"
|
140
|
+
if value.present? && !value.is_a?(Numeric)
|
141
|
+
parsed[field.to_sym.send(operator)] = Regexp.new(Regexp.quote(value.to_s), Regexp::IGNORECASE)
|
142
|
+
else
|
143
|
+
parsed[field.to_sym.send(:nin)] = [value]
|
144
|
+
end
|
145
|
+
else
|
146
|
+
parsed[field.to_sym] = value
|
147
|
+
end
|
148
|
+
parsed
|
149
|
+
end
|
150
|
+
|
151
|
+
def relate_embedded(scope, relation, filters)
|
152
|
+
# TODO: this way of fetching this is not recursive as the regular fields
|
153
|
+
# because the structure of the query is embeeded.field = value
|
154
|
+
# we need more brain cells on this problem because it does not allow
|
155
|
+
# to filter things using OR/AND
|
156
|
+
parsed = {}
|
157
|
+
filters.each do |key, value|
|
158
|
+
operation = Operation.new(scope, key, value)
|
159
|
+
attribute = OpenStruct.new(name: "#{relation.name}.#{operation.operand}")
|
160
|
+
obj = parse(attribute, value, operation.operator).first
|
161
|
+
parsed[obj[0]] = obj[1]
|
162
|
+
end
|
163
|
+
parsed
|
164
|
+
end
|
165
|
+
|
166
|
+
def relate_one(scope, relation, value)
|
167
|
+
field = relation.name
|
168
|
+
parsed = {}
|
169
|
+
|
170
|
+
if relation.embeds_one?
|
171
|
+
parsed = relate_embedded(scope, relation, value)
|
172
|
+
end
|
173
|
+
|
174
|
+
if relation.belongs_to?
|
175
|
+
parsed = relation.exec(scope, value)
|
176
|
+
end
|
177
|
+
|
178
|
+
if relation.has_one?
|
179
|
+
parsed = relation.exec(scope, value)
|
180
|
+
end
|
181
|
+
|
182
|
+
parsed
|
183
|
+
end
|
184
|
+
|
185
|
+
def relate_many(scope, relation, value, operator)
|
186
|
+
field_name = relation.inverse_name || scope.name.underscore
|
187
|
+
target = Graphoid::Queries::Processor.execute(relation.klass, value).to_a
|
188
|
+
|
189
|
+
if relation.embeds_many?
|
190
|
+
# TODO: not implemented at all.
|
191
|
+
end
|
192
|
+
|
193
|
+
if relation.many_to_many?
|
194
|
+
field_name = field_name.to_s.singularize + "_ids"
|
195
|
+
ids = target.map(&(field_name.to_sym))
|
196
|
+
ids.flatten!.uniq!
|
197
|
+
else
|
198
|
+
field_name = field_name.to_s + "_id"
|
199
|
+
ids = target.map(&(field_name.to_sym))
|
200
|
+
end
|
201
|
+
|
202
|
+
parsed = {}
|
203
|
+
if operator == "none"
|
204
|
+
parsed[:id.nin] = ids
|
205
|
+
elsif operator == "some"
|
206
|
+
parsed[:id.in] = ids
|
207
|
+
elsif operator == "every"
|
208
|
+
# missing implementation
|
209
|
+
end
|
210
|
+
parsed
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Graphield
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
@graphields = []
|
7
|
+
@forbidden = {}
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def graphield name, type
|
11
|
+
@graphields << Graphoid::Attribute.new(name: name.to_s, type: type)
|
12
|
+
end
|
13
|
+
|
14
|
+
def graphorbid field, *actions
|
15
|
+
@forbidden[field] = actions
|
16
|
+
end
|
17
|
+
|
18
|
+
def graphields
|
19
|
+
@graphields
|
20
|
+
end
|
21
|
+
|
22
|
+
def graphfiles
|
23
|
+
@graphields.select{ |field| field.type == Graphoid::Upload }
|
24
|
+
end
|
25
|
+
|
26
|
+
def forbidden_fields
|
27
|
+
@forbidden
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class Grapho
|
3
|
+
attr_reader :name, :plural, :camel_name
|
4
|
+
attr_reader :type, :filter, :order, :input
|
5
|
+
|
6
|
+
def initialize(model)
|
7
|
+
build_naming(model)
|
8
|
+
|
9
|
+
@type = Graphoid::Types.generate(model)
|
10
|
+
@order = Graphoid::Orders.generate(model)
|
11
|
+
@input = Graphoid::Inputs.generate(model)
|
12
|
+
@filter = Graphoid::Filters.generate(model)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def build_naming(model)
|
18
|
+
@camel_name = Utils.graphqlize(model.name)
|
19
|
+
@name = @camel_name.underscore
|
20
|
+
@plural = @name.pluralize
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Graphoid
|
2
|
+
@@graphs = {}
|
3
|
+
|
4
|
+
class << self
|
5
|
+
attr_accessor :driver
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
Graphoid.driver = configuration&.driver
|
9
|
+
Rails.application.eager_load!
|
10
|
+
Graphoid::Scalars.generate
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(model, action = nil)
|
14
|
+
@@graphs[model] ||= Graphoid::Grapho.new(model)
|
15
|
+
end
|
16
|
+
|
17
|
+
def driver=(driver)
|
18
|
+
@driver = driver == :active_record ? ActiveRecordDriver : MongoidDriver
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Mutations
|
3
|
+
module Create
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
Graphoid.initialize
|
8
|
+
model = self
|
9
|
+
grapho = Graphoid.build(model)
|
10
|
+
type = ::Types::MutationType
|
11
|
+
|
12
|
+
name = "create_#{grapho.name}"
|
13
|
+
plural_name = name.pluralize
|
14
|
+
|
15
|
+
type.field(name: name, type: grapho.type, null: true) do
|
16
|
+
argument(:data, grapho.input, required: false)
|
17
|
+
end
|
18
|
+
|
19
|
+
type.field(name: plural_name, type: [grapho.type], null: true) do
|
20
|
+
argument(:data, [grapho.input], required: false)
|
21
|
+
end
|
22
|
+
|
23
|
+
type.class_eval do
|
24
|
+
define_method :"#{name}" do |data: {}|
|
25
|
+
begin
|
26
|
+
user = context[:current_user]
|
27
|
+
Graphoid::Mutations::Processor.execute(model, grapho, data, user)
|
28
|
+
rescue Exception => ex
|
29
|
+
GraphQL::ExecutionError.new(ex.message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
type.class_eval do
|
35
|
+
define_method :"#{plural_name}" do |data: []|
|
36
|
+
begin
|
37
|
+
user = context[:current_user]
|
38
|
+
result = []
|
39
|
+
data.each { |d| result << Graphoid::Mutations::Processor.execute(model, grapho, d, user) }
|
40
|
+
result
|
41
|
+
rescue Exception => ex
|
42
|
+
GraphQL::ExecutionError.new(ex.message)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Mutations
|
3
|
+
module Delete
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
Graphoid.initialize
|
8
|
+
model = self
|
9
|
+
grapho = Graphoid.build(model)
|
10
|
+
type = ::Types::MutationType
|
11
|
+
|
12
|
+
name = "delete_#{grapho.name}"
|
13
|
+
plural = "delete_many_#{grapho.plural}"
|
14
|
+
|
15
|
+
type.field(name: name, type: grapho.type, null: true) do
|
16
|
+
argument :id, GraphQL::Types::ID, required: true
|
17
|
+
end
|
18
|
+
|
19
|
+
type.field(name: plural, type: [grapho.type], null: true) do
|
20
|
+
argument :where, grapho.filter, required: false
|
21
|
+
end
|
22
|
+
|
23
|
+
type.class_eval do
|
24
|
+
define_method :"#{name}" do |id:|
|
25
|
+
begin
|
26
|
+
result = model.find(id)
|
27
|
+
result.destroy!
|
28
|
+
result
|
29
|
+
rescue Exception => ex
|
30
|
+
GraphQL::ExecutionError.new(ex.message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
type.class_eval do
|
36
|
+
define_method :"#{plural}" do |where: {}|
|
37
|
+
begin
|
38
|
+
objects = Graphoid::Queries::Processor.execute(model, where.to_h)
|
39
|
+
objects.destroy_all
|
40
|
+
objects.all.to_a
|
41
|
+
rescue Exception => ex
|
42
|
+
GraphQL::ExecutionError.new(ex.message)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Mutations
|
3
|
+
module Processor
|
4
|
+
def self.execute(model, grapho, data, user)
|
5
|
+
root_object = []
|
6
|
+
operations = []
|
7
|
+
data.each { |key, value| operations << Operation.new(model, key, value) }
|
8
|
+
|
9
|
+
operations.each do |operation|
|
10
|
+
item = operation.operand.precreate(operation.value)
|
11
|
+
root_object << item if item.present?
|
12
|
+
end
|
13
|
+
|
14
|
+
root_object = root_object.reduce(Hash.new, :merge)
|
15
|
+
|
16
|
+
fieldnames = Attribute.fieldnames_of(model)
|
17
|
+
root_object['created_by_id'] = user.id if fieldnames.include?('created_by_id')
|
18
|
+
root_object['updated_by_id'] = user.id if fieldnames.include?('updated_by_id')
|
19
|
+
|
20
|
+
sanitized = Attribute.correct(model, root_object)
|
21
|
+
root = model.create!(sanitized)
|
22
|
+
|
23
|
+
operations.each do |operation|
|
24
|
+
operation.operand.create(root, operation.value, grapho)
|
25
|
+
end
|
26
|
+
|
27
|
+
root.reload
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Mutations
|
3
|
+
module Update
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
Graphoid.initialize
|
8
|
+
model = self
|
9
|
+
grapho = Graphoid.build(model)
|
10
|
+
type = ::Types::MutationType
|
11
|
+
|
12
|
+
name = "update_#{grapho.name}"
|
13
|
+
plural = "update_many_#{grapho.plural}"
|
14
|
+
|
15
|
+
type.field name: name, type: grapho.type, null: true do
|
16
|
+
argument :id, GraphQL::Types::ID, required: true
|
17
|
+
argument :data, grapho.input, required: false
|
18
|
+
end
|
19
|
+
|
20
|
+
type.field name: plural, type: [grapho.type], null: true do
|
21
|
+
argument :where, grapho.filter, required: false
|
22
|
+
argument :data, grapho.input, required: false
|
23
|
+
end
|
24
|
+
|
25
|
+
type.class_eval do
|
26
|
+
define_method :"#{name}" do |id:, data: {}|
|
27
|
+
attrs = Utils.build_update_attributes(data, model, context)
|
28
|
+
|
29
|
+
begin
|
30
|
+
object = model.find(id)
|
31
|
+
object.update!(attrs)
|
32
|
+
object.reload
|
33
|
+
rescue Exception => ex
|
34
|
+
GraphQL::ExecutionError.new(ex.message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
type.class_eval do
|
40
|
+
define_method :"#{plural}" do |where: {}, data: {}|
|
41
|
+
attrs = Utils.build_update_attributes(data, model, context)
|
42
|
+
|
43
|
+
begin
|
44
|
+
objects = Graphoid::Queries::Processor.execute(model, where.to_h)
|
45
|
+
objects.update_all(attrs)
|
46
|
+
objects.all.to_a
|
47
|
+
rescue Exception => ex
|
48
|
+
GraphQL::ExecutionError.new(ex.message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class Attribute
|
3
|
+
attr_reader :name, :type
|
4
|
+
|
5
|
+
PERMS = [:read, :create, :update, :delete]
|
6
|
+
|
7
|
+
def initialize(name:, type:)
|
8
|
+
@name = name.to_s
|
9
|
+
@camel_name = Utils.camelize(@name)
|
10
|
+
@type = type
|
11
|
+
end
|
12
|
+
|
13
|
+
def resolve(o)
|
14
|
+
Graphoid.driver.parse(o.operand, o.value, o.operator)
|
15
|
+
end
|
16
|
+
|
17
|
+
def embedded?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def relation?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def precreate(value)
|
26
|
+
{ self.name.to_sym => value }
|
27
|
+
end
|
28
|
+
|
29
|
+
def create(_,_,_)
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def fields_of(model, action = :read)
|
34
|
+
fields = Graphoid.driver.fields_of(model) + graphields_of(model)
|
35
|
+
fields.select { |field| forbidden_fields_of(model, action).exclude?(field.name) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def fieldnames_of(model, action = :read)
|
39
|
+
fields_of(model, action).map(&:name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def graphields_of(model)
|
43
|
+
model.respond_to?(:graphields) ? model.send(:graphields) : []
|
44
|
+
end
|
45
|
+
|
46
|
+
def forbidden_fields_of(model, action)
|
47
|
+
skips = model.respond_to?(:forbidden_fields) ? model.send(:forbidden_fields) : []
|
48
|
+
skips.map do |field, actions|
|
49
|
+
field.to_s if actions.empty? || actions.include?(action)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def correct(model, attributes)
|
54
|
+
result = {}
|
55
|
+
fieldnames = fieldnames_of(model)
|
56
|
+
attributes.each do |key, value|
|
57
|
+
key = key.to_s.underscore if fieldnames.exclude?(key.to_s)
|
58
|
+
result[key] = value
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class BelongsTo < Relation
|
3
|
+
def precreate(value)
|
4
|
+
sanitized = Attribute.correct(self.klass, value)
|
5
|
+
foreign_id = self.klass.create!(sanitized).id
|
6
|
+
{ :"#{self.name}_id" => foreign_id }
|
7
|
+
end
|
8
|
+
|
9
|
+
def exec(_, value)
|
10
|
+
ids = Graphoid::Queries::Processor.execute(self.klass, value).to_a.map(&:id)
|
11
|
+
attribute = Attribute.new(name: "#{self.name.underscore}_id", type: nil)
|
12
|
+
Graphoid.driver.parse(attribute, ids, "in")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class HasMany < Relation
|
3
|
+
def create(parent, values, grapho)
|
4
|
+
values.each do |value|
|
5
|
+
attributes = Attribute.correct(self.klass, value)
|
6
|
+
attributes[:"#{grapho.name}_id"] = parent.id
|
7
|
+
self.klass.create!(attributes)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class HasOne < Relation
|
3
|
+
def create(parent, value, grapho)
|
4
|
+
attributes = Attribute.correct(self.klass, value)
|
5
|
+
attributes[:"#{grapho.name}_id"] = parent.id
|
6
|
+
self.klass.create!(attributes)
|
7
|
+
end
|
8
|
+
|
9
|
+
def exec(scope, value)
|
10
|
+
field_name = self.inverse_name || scope.name.underscore
|
11
|
+
ids = Graphoid::Queries::Processor.execute(self.klass, value).to_a.map(&("#{field_name}_id".to_sym))
|
12
|
+
attribute = Attribute.new(name: "id", type: nil)
|
13
|
+
Graphoid.driver.parse(attribute, ids, "in")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class ManyToMany < Relation
|
3
|
+
def create(parent, values, grapho)
|
4
|
+
values.each do |value|
|
5
|
+
attributes = Attribute.correct(self.klass, value)
|
6
|
+
attributes[:"#{grapho.name}_ids"] = [parent.id]
|
7
|
+
self.klass.create!(attributes)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|