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,70 @@
|
|
1
|
+
module Graphoid
|
2
|
+
|
3
|
+
class Relation
|
4
|
+
attr_reader :name, :klass, :type, :inverse_name
|
5
|
+
|
6
|
+
def initialize(relation)
|
7
|
+
@name = relation.name.to_s
|
8
|
+
@camel_name = Utils.camelize(@name)
|
9
|
+
@inverse_name = Graphoid.driver.inverse_name_of(relation)
|
10
|
+
@klass = relation.class_name.constantize
|
11
|
+
@type = Graphoid.driver.relation_type(relation)
|
12
|
+
end
|
13
|
+
|
14
|
+
[:has_and_belongs_to_many, :through, :has_many, :belongs_to, :has_one, :embeds_one, :embeds_many, :embedded_in].each do |type|
|
15
|
+
type = :"#{type}?"
|
16
|
+
define_method type do
|
17
|
+
Graphoid.driver.send(type, @type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def relation?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def one?
|
26
|
+
belongs_to? || has_one? || embeds_one?
|
27
|
+
end
|
28
|
+
|
29
|
+
def many?
|
30
|
+
# TODO: "through" can be one or many, we only support many at the moment.
|
31
|
+
has_many? || has_and_belongs_to_many? || through? || embeds_many?
|
32
|
+
end
|
33
|
+
|
34
|
+
def belongs?
|
35
|
+
belongs_to? || embedded_in?
|
36
|
+
end
|
37
|
+
|
38
|
+
def many_to_many?
|
39
|
+
has_and_belongs_to_many? || through?
|
40
|
+
end
|
41
|
+
|
42
|
+
def embedded?
|
43
|
+
embeds_one? || embeds_many? || embedded_in?
|
44
|
+
end
|
45
|
+
|
46
|
+
def precreate(_)
|
47
|
+
end
|
48
|
+
|
49
|
+
def create(_,_,_)
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolve(operation)
|
53
|
+
if one?
|
54
|
+
return operation.operand.exec(operation.scope, operation.value)
|
55
|
+
end
|
56
|
+
|
57
|
+
if many?
|
58
|
+
return Graphoid.driver.relate_many(o.scope, o.operand, o.value, o.operator)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class << self
|
63
|
+
def relations_of(model)
|
64
|
+
# return a list of relation objects
|
65
|
+
# Graphoid.driver.relations_of(model).map { |_, relation| Relation.new(relation) }
|
66
|
+
Graphoid.driver.relations_of(model)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Graphoid
|
2
|
+
class Operation
|
3
|
+
attr_reader :scope, :operand, :operator, :value
|
4
|
+
|
5
|
+
def initialize(scope, key, value)
|
6
|
+
@scope = scope
|
7
|
+
@operator = nil
|
8
|
+
@operand = key
|
9
|
+
@value = value
|
10
|
+
|
11
|
+
match = key.match(/^(.+)_(.+)$/)
|
12
|
+
@operand, @operator = match[1..2] if match
|
13
|
+
@operand = build_operand(@scope, @operand) || @operand
|
14
|
+
end
|
15
|
+
|
16
|
+
def resolve
|
17
|
+
@operand.resolve(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def build_operand(model, key)
|
23
|
+
fields = Attribute.fields_of(model)
|
24
|
+
|
25
|
+
field = fields.find { |f| f.name == key }
|
26
|
+
return Attribute.new(name: key, type: field.type) if field
|
27
|
+
|
28
|
+
field = fields.find { |f| f.name == key.underscore }
|
29
|
+
return Attribute.new(name: key.underscore, type: field.type) if field
|
30
|
+
|
31
|
+
relations = model.reflect_on_all_associations
|
32
|
+
|
33
|
+
relation = relations.find { |r| r.name == key.to_sym }
|
34
|
+
return Graphoid.driver.class_of(relation).new(relation) if relation
|
35
|
+
|
36
|
+
relation = relations.find { |r| r.name == key.underscore.to_sym }
|
37
|
+
return Graphoid.driver.class_of(relation).new(relation) if relation
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Queries
|
3
|
+
module Processor
|
4
|
+
class << self
|
5
|
+
def execute(scope, object)
|
6
|
+
object.each { |key, value| scope = process(scope, value, key) }
|
7
|
+
scope
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute_array(scope, list, action)
|
11
|
+
if action == "OR"
|
12
|
+
scope = Graphoid.driver.execute_or(scope, list)
|
13
|
+
else
|
14
|
+
list.each { |object| scope = execute(scope, object) }
|
15
|
+
end
|
16
|
+
scope
|
17
|
+
end
|
18
|
+
|
19
|
+
def process(scope, value, key = nil)
|
20
|
+
if key && ["OR", "AND"].exclude?(key)
|
21
|
+
operation = Operation.new(scope, key, value)
|
22
|
+
filter = operation.resolve
|
23
|
+
return Graphoid.driver.execute_and(scope, filter)
|
24
|
+
end
|
25
|
+
|
26
|
+
if operation.nil? || operation.type == :attribute
|
27
|
+
return execute(scope, value) if value.is_a?(Hash)
|
28
|
+
if value.is_a?(Array) && ["in", "nin"].exclude?(operation&.operator)
|
29
|
+
return execute_array(scope, value, key)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def children_of(selection)
|
35
|
+
selection.scoped_children.values[0]
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_order(scope, order)
|
39
|
+
fields = Attribute.fieldnames_of(scope)
|
40
|
+
Utils.underscore(order, fields)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Queries
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
Graphoid.initialize
|
7
|
+
model = self
|
8
|
+
grapho = Graphoid.build(model)
|
9
|
+
query_type = ::Types::QueryType
|
10
|
+
|
11
|
+
query_type.field name: grapho.name, type: grapho.type, null: true do
|
12
|
+
argument :id, GraphQL::Types::ID, required: false
|
13
|
+
argument :where, grapho.filter, required: false
|
14
|
+
end
|
15
|
+
|
16
|
+
query_type.field name: grapho.plural, type: [grapho.type], null: true do
|
17
|
+
Graphoid::Argument.query_many(self, grapho.filter, grapho.order, { required: false })
|
18
|
+
end
|
19
|
+
|
20
|
+
query_type.field name: "_#{grapho.plural}_meta", type: Graphoid::Types::Meta, null: true do
|
21
|
+
Graphoid::Argument.query_many(self, grapho.filter, grapho.order, { required: false })
|
22
|
+
end
|
23
|
+
|
24
|
+
query_type.class_eval do
|
25
|
+
define_method :"#{grapho.name}" do |id: nil, where: nil|
|
26
|
+
begin
|
27
|
+
return model.find(id) if id
|
28
|
+
Processor.execute(model, where.to_h).first
|
29
|
+
rescue Exception => ex
|
30
|
+
GraphQL::ExecutionError.new(ex.message)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
query_type.class_eval do
|
36
|
+
define_method :"#{grapho.plural}" do |where: nil, order: nil, limit: nil, skip: nil|
|
37
|
+
begin
|
38
|
+
model = Graphoid.driver.eager_load(context.irep_node, model)
|
39
|
+
result = Processor.execute(model, where.to_h)
|
40
|
+
order = Processor.parse_order(model, order.to_h)
|
41
|
+
result = result.order(order).limit(limit)
|
42
|
+
Graphoid.driver.skip(result, skip)
|
43
|
+
rescue Exception => ex
|
44
|
+
GraphQL::ExecutionError.new(ex.message)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
alias_method :"_#{grapho.plural}_meta", :"#{grapho.plural}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Upload
|
3
|
+
end
|
4
|
+
|
5
|
+
module Scalars
|
6
|
+
class << self
|
7
|
+
def generate
|
8
|
+
Graphoid::Scalars::DateTime ||= GraphQL::ScalarType.define do
|
9
|
+
name "DateTime"
|
10
|
+
description "DateTime ISO8601 formated"
|
11
|
+
|
12
|
+
coerce_input -> (value, _) do
|
13
|
+
begin
|
14
|
+
::DateTime.iso8601(value)
|
15
|
+
rescue Exception => ex
|
16
|
+
GraphQL::ExecutionError.new(ex)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Graphoid::Scalars::Date ||= GraphQL::ScalarType.define do
|
22
|
+
name "Date"
|
23
|
+
description "Date ISO8601 formated"
|
24
|
+
|
25
|
+
coerce_input -> (value, _) do
|
26
|
+
begin
|
27
|
+
::DateTime.iso8601(value)
|
28
|
+
rescue Exception => ex
|
29
|
+
GraphQL::ExecutionError.new(ex)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Graphoid::Scalars::Time ||= GraphQL::ScalarType.define do
|
35
|
+
name "Time"
|
36
|
+
description "Time ISO8601 formated"
|
37
|
+
|
38
|
+
coerce_input -> (value, _) do
|
39
|
+
begin
|
40
|
+
::DateTime.iso8601(value)
|
41
|
+
rescue Exception => ex
|
42
|
+
GraphQL::ExecutionError.new(ex)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Graphoid::Scalars::Timestamp ||= GraphQL::ScalarType.define do
|
48
|
+
name "Timestamp"
|
49
|
+
description "Second elapsed since 1970-01-01"
|
50
|
+
|
51
|
+
coerce_input -> (value, _) do
|
52
|
+
begin
|
53
|
+
::DateTime.iso8601(value)
|
54
|
+
rescue Exception => ex
|
55
|
+
GraphQL::ExecutionError.new(ex)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Graphoid::Scalars::Text ||= GraphQL::ScalarType.define do
|
61
|
+
name "Text"
|
62
|
+
description "Should be string? explain this please."
|
63
|
+
end
|
64
|
+
|
65
|
+
Graphoid::Scalars::BigInt ||= GraphQL::ScalarType.define do
|
66
|
+
name "BigInt"
|
67
|
+
description "WTF ??"
|
68
|
+
end
|
69
|
+
|
70
|
+
Graphoid::Scalars::Decimal ||= GraphQL::ScalarType.define do
|
71
|
+
name "Decimal"
|
72
|
+
description "Define pliiiizzzzzzz"
|
73
|
+
end
|
74
|
+
|
75
|
+
Graphoid::Scalars::Hash ||= GraphQL::ScalarType.define do
|
76
|
+
name "Hash"
|
77
|
+
description "Hash scalar"
|
78
|
+
end
|
79
|
+
|
80
|
+
Graphoid::Scalars::Array ||= GraphQL::ScalarType.define do
|
81
|
+
name "Array"
|
82
|
+
description "Array scalar"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Graphoid
|
2
|
+
module Utils
|
3
|
+
class << self
|
4
|
+
def modelize text
|
5
|
+
graphqlize text.to_s.capitalize.camelize
|
6
|
+
end
|
7
|
+
|
8
|
+
def camelize text
|
9
|
+
# we are doing it twice because _id gets translated to Id the first time and to id the second time.
|
10
|
+
graphqlize text.to_s.camelize(:lower).camelize(:lower)
|
11
|
+
end
|
12
|
+
|
13
|
+
def graphqlize text
|
14
|
+
text.to_s.gsub(/::/, '_')
|
15
|
+
end
|
16
|
+
|
17
|
+
def symbolize(fields)
|
18
|
+
fields.keys.map(&:underscore).map(&:to_sym)
|
19
|
+
end
|
20
|
+
|
21
|
+
def underscore props, fields = []
|
22
|
+
attrs = {}
|
23
|
+
props.each do |key, value|
|
24
|
+
key = key.underscore if fields.exclude?(key)
|
25
|
+
attrs[key] = value
|
26
|
+
end
|
27
|
+
attrs
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_update_attributes(data, model, context)
|
31
|
+
user = context[:current_user]
|
32
|
+
fields = Graphoid::Attribute.fieldnames_of(model)
|
33
|
+
attrs = underscore(data, fields)
|
34
|
+
attrs['updated_by_id'] = user.id if user && fields.include?('updated_by_id')
|
35
|
+
attrs
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/graphoid.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'graphoid/utils'
|
2
|
+
require 'graphoid/grapho'
|
3
|
+
require 'graphoid/mapper'
|
4
|
+
require 'graphoid/config'
|
5
|
+
require 'graphoid/scalars'
|
6
|
+
require 'graphoid/argument'
|
7
|
+
require 'graphoid/graphield'
|
8
|
+
|
9
|
+
require 'graphoid/operators/attribute'
|
10
|
+
require 'graphoid/operators/relation'
|
11
|
+
require 'graphoid/operators/inherited/belongs_to'
|
12
|
+
require 'graphoid/operators/inherited/embeds_one'
|
13
|
+
require 'graphoid/operators/inherited/embeds_many'
|
14
|
+
require 'graphoid/operators/inherited/has_many'
|
15
|
+
require 'graphoid/operators/inherited/has_one'
|
16
|
+
require 'graphoid/operators/inherited/many_to_many'
|
17
|
+
|
18
|
+
require 'graphoid/queries/queries'
|
19
|
+
require 'graphoid/queries/processor'
|
20
|
+
require 'graphoid/queries/operation'
|
21
|
+
|
22
|
+
require 'graphoid/mutations/create'
|
23
|
+
require 'graphoid/mutations/update'
|
24
|
+
require 'graphoid/mutations/delete'
|
25
|
+
require 'graphoid/mutations/processor'
|
26
|
+
require 'graphoid/mutations/structure'
|
27
|
+
|
28
|
+
require 'graphoid/drivers/mongoid'
|
29
|
+
require 'graphoid/drivers/active_record'
|
30
|
+
|
31
|
+
require 'graphoid/definitions/types'
|
32
|
+
require 'graphoid/definitions/orders'
|
33
|
+
require 'graphoid/definitions/filters'
|
34
|
+
require 'graphoid/definitions/inputs'
|
35
|
+
|
36
|
+
require 'graphoid/main'
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graphoid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Maximiliano Perez Coto
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-04-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-collection_matchers
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A gem that helps you autogenerate a GraphQL api from MongoId models.
|
56
|
+
email:
|
57
|
+
- maxiperezc@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- MIT-LICENSE
|
63
|
+
- README.md
|
64
|
+
- Rakefile
|
65
|
+
- lib/graphoid.rb
|
66
|
+
- lib/graphoid/argument.rb
|
67
|
+
- lib/graphoid/config.rb
|
68
|
+
- lib/graphoid/definitions/filters.rb
|
69
|
+
- lib/graphoid/definitions/inputs.rb
|
70
|
+
- lib/graphoid/definitions/orders.rb
|
71
|
+
- lib/graphoid/definitions/types.rb
|
72
|
+
- lib/graphoid/drivers/active_record.rb
|
73
|
+
- lib/graphoid/drivers/mongoid.rb
|
74
|
+
- lib/graphoid/graphield.rb
|
75
|
+
- lib/graphoid/grapho.rb
|
76
|
+
- lib/graphoid/main.rb
|
77
|
+
- lib/graphoid/mapper.rb
|
78
|
+
- lib/graphoid/mutations/create.rb
|
79
|
+
- lib/graphoid/mutations/delete.rb
|
80
|
+
- lib/graphoid/mutations/processor.rb
|
81
|
+
- lib/graphoid/mutations/structure.rb
|
82
|
+
- lib/graphoid/mutations/update.rb
|
83
|
+
- lib/graphoid/operators/attribute.rb
|
84
|
+
- lib/graphoid/operators/inherited/belongs_to.rb
|
85
|
+
- lib/graphoid/operators/inherited/embeds_many.rb
|
86
|
+
- lib/graphoid/operators/inherited/embeds_one.rb
|
87
|
+
- lib/graphoid/operators/inherited/has_many.rb
|
88
|
+
- lib/graphoid/operators/inherited/has_one.rb
|
89
|
+
- lib/graphoid/operators/inherited/many_to_many.rb
|
90
|
+
- lib/graphoid/operators/relation.rb
|
91
|
+
- lib/graphoid/queries/operation.rb
|
92
|
+
- lib/graphoid/queries/processor.rb
|
93
|
+
- lib/graphoid/queries/queries.rb
|
94
|
+
- lib/graphoid/scalars.rb
|
95
|
+
- lib/graphoid/utils.rb
|
96
|
+
- lib/graphoid/version.rb
|
97
|
+
homepage: http://www.github.com/maxiperezc/graphoid
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubygems_version: 3.0.3
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Generate GraphQL from ActiveRecord or Mongoid
|
120
|
+
test_files: []
|