graphoid 0.0.1
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 +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
|