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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +62 -0
  4. data/Rakefile +33 -0
  5. data/lib/graphoid/argument.rb +12 -0
  6. data/lib/graphoid/config.rb +19 -0
  7. data/lib/graphoid/definitions/filters.rb +57 -0
  8. data/lib/graphoid/definitions/inputs.rb +41 -0
  9. data/lib/graphoid/definitions/orders.rb +43 -0
  10. data/lib/graphoid/definitions/types.rb +119 -0
  11. data/lib/graphoid/drivers/active_record.rb +187 -0
  12. data/lib/graphoid/drivers/mongoid.rb +214 -0
  13. data/lib/graphoid/graphield.rb +32 -0
  14. data/lib/graphoid/grapho.rb +23 -0
  15. data/lib/graphoid/main.rb +21 -0
  16. data/lib/graphoid/mapper.rb +10 -0
  17. data/lib/graphoid/mutations/create.rb +49 -0
  18. data/lib/graphoid/mutations/delete.rb +49 -0
  19. data/lib/graphoid/mutations/processor.rb +31 -0
  20. data/lib/graphoid/mutations/structure.rb +9 -0
  21. data/lib/graphoid/mutations/update.rb +55 -0
  22. data/lib/graphoid/operators/attribute.rb +64 -0
  23. data/lib/graphoid/operators/inherited/belongs_to.rb +15 -0
  24. data/lib/graphoid/operators/inherited/embeds_many.rb +10 -0
  25. data/lib/graphoid/operators/inherited/embeds_one.rb +8 -0
  26. data/lib/graphoid/operators/inherited/has_many.rb +11 -0
  27. data/lib/graphoid/operators/inherited/has_one.rb +16 -0
  28. data/lib/graphoid/operators/inherited/many_to_many.rb +11 -0
  29. data/lib/graphoid/operators/relation.rb +70 -0
  30. data/lib/graphoid/queries/operation.rb +40 -0
  31. data/lib/graphoid/queries/processor.rb +45 -0
  32. data/lib/graphoid/queries/queries.rb +52 -0
  33. data/lib/graphoid/scalars.rb +87 -0
  34. data/lib/graphoid/utils.rb +39 -0
  35. data/lib/graphoid/version.rb +3 -0
  36. data/lib/graphoid.rb +36 -0
  37. 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
@@ -0,0 +1,3 @@
1
+ module Graphoid
2
+ VERSION = '0.0.1'
3
+ 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: []