rails-graphql-generator 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3044f10456b35da92ca114424e35da2ba575993f
4
+ data.tar.gz: 5701cb9b7a8883bb6021375ea1a3fc41483ac689
5
+ SHA512:
6
+ metadata.gz: 561be3a2e560815a94912380105d57c214d379a01e37637a93b9e93b1449fa6b0a728108c7de81dfe153048c975648ec4121a570587b69817aed1259a3a7a00c
7
+ data.tar.gz: b0c9d5a698de7bdb68be0387379c261598b17c577619e46f12bbeceb5a30ac652c255c87d82b4f7f9704a93dfee0917caa5c26c7ab870b4f81c19b43827c03b1
@@ -0,0 +1,9 @@
1
+ Description:
2
+
3
+
4
+ Example:
5
+ rails generate graphql Model
6
+
7
+ This will create:
8
+ app/graphql/types/model_type.rb
9
+ app/graphql/mutations/model_.rb
@@ -0,0 +1,23 @@
1
+ require 'generators/graphql/graphql_helpers'
2
+
3
+ module Graphql
4
+ module Generators
5
+ class CreateAllGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ include Graphql::Generators::GraphqlHelpers
9
+
10
+ def create
11
+ models.each { |model| create_type(model) }
12
+ models.each { |model| add_fields(model) }
13
+ models.each { |model| add_methods(model) }
14
+ models.each { |model| add_connections(model) }
15
+ models.each { |model| add_connection_query(model) }
16
+ models.each { |model| create_mutation(model) }
17
+ models.each { |model| add_fields_to_mutation(model) }
18
+ models.each { |model| add_mutation_query(model) }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ require 'generators/graphql/graphql_helpers'
2
+
3
+ module Graphql
4
+ module Generators
5
+ class GraphqlGenerator < Rails::Generators::NamedBase
6
+ source_root File.expand_path('../templates', __FILE__)
7
+ namespace 'graphql'
8
+
9
+ include Graphql::Generators::GraphqlHelpers
10
+
11
+ def create
12
+ model = name.classify.constantize
13
+ create_type(model)
14
+ add_fields(model)
15
+ add_methods(model)
16
+ add_connections(model)
17
+ add_connection_query(model)
18
+ create_mutation(model)
19
+ add_fields_to_mutation(model)
20
+ add_mutation_query(model)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,256 @@
1
+ module Graphql
2
+ module Generators
3
+ module GraphqlHelpers
4
+ def models
5
+ @models ||= ActiveRecord::Base.connection.tables.map{ |x| x.classify.safe_constantize }.compact
6
+ end
7
+
8
+ def type_mapper
9
+ @type_mapper ||= {
10
+ integer: 'Int',
11
+ string: 'String',
12
+ datetime: 'String',
13
+ boolean: 'Boolean',
14
+ float: 'Float',
15
+ date: 'String',
16
+ json: 'String',
17
+ text: 'String',
18
+ decimal: 'Float',
19
+ '' => 'String',
20
+ }
21
+ end
22
+
23
+ def create_type(model)
24
+ create_file "app/graphql/types/#{ActiveModel::Naming.singular_route_key(model)}_type.rb", <<-FILE
25
+ #{model.to_s}Type = GraphQL::ObjectType.define do
26
+ name '#{model.to_s}'
27
+ description '#{model.to_s} type'
28
+
29
+ interfaces [NodeIdentification.interface]
30
+
31
+ field :id, field: GraphQL::Relay::GlobalIdField.new('#{model.to_s}')
32
+ # End of fields
33
+ end
34
+ FILE
35
+ add_fields(model)
36
+ end
37
+
38
+ def add_fields(model)
39
+ columns = model.columns_hash
40
+ columns.keys.each do |k|
41
+ next if columns[k].name == 'id'
42
+
43
+ if columns[k].type.present?
44
+ inject_into_file type_path(model), after: "field :id, field: GraphQL::Relay::GlobalIdField.new('#{model.to_s}')\n" do <<-FILE
45
+ field :#{columns[k].name}, types.#{type_mapper[columns[k].type]}
46
+ FILE
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def add_methods(model)
53
+ associations = model.reflect_on_all_associations(:belongs_to)
54
+
55
+ associations.map(&:name).each do |ast|
56
+ association_klass = model.reflect_on_association(ast).class_name
57
+
58
+ begin
59
+ if models.include? association_klass.classify.constantize
60
+ if circular_finder[model.to_s].include? association_klass || association_klass == model.to_s
61
+ inject_into_file type_path(model), before: "# End of fields\n" do <<-FILE
62
+ field :#{ast.to_s} do
63
+ type -> { #{model.reflect_on_association(ast).class_name}Type }
64
+
65
+ resolve -> (#{singular_route_key(model)}, args, ctx) {
66
+ #{singular_route_key(model)}.#{ast.to_s}
67
+ }
68
+ end
69
+
70
+ FILE
71
+ end
72
+ else
73
+ inject_into_file type_path(model), before: "# End of fields\n" do <<-FILE
74
+ field :#{ast.to_s} do
75
+ type -> #{model.reflect_on_association(ast).class_name}Type
76
+
77
+ resolve -> (#{singular_route_key(model)}, args, ctx) {
78
+ #{singular_route_key(model)}.#{ast.to_s}
79
+ }
80
+ end
81
+ FILE
82
+ end
83
+ end
84
+ end
85
+ rescue => ex
86
+ puts ex
87
+ end
88
+ end
89
+ end
90
+
91
+ def add_connections(model)
92
+ associations = model.reflect_on_all_associations(:has_many)
93
+ associations += model.reflect_on_all_associations(:has_and_belongs_to_many)
94
+
95
+ associations.map(&:name).each do |ast|
96
+ association_klass = model.reflect_on_association(ast).class_name
97
+ begin
98
+ if models.include? association_klass.classify.constantize
99
+ if circular_finder[model.to_s].include? association_klass || association_klass == model.to_s
100
+ inject_into_file type_path(model), before: "# End of fields\n" do <<-FILE
101
+ connection :#{ast.to_s}, -> { #{model.reflect_on_association(ast).class_name}Type.connection_type } do
102
+ resolve ->(#{singular_route_key(model)}, args, ctx) {
103
+ #{singular_route_key(model)}.#{ast}
104
+ }
105
+ end
106
+
107
+ FILE
108
+ end
109
+ else
110
+ inject_into_file type_path(model), before: "# End of fields\n" do <<-FILE
111
+ connection :#{ast.to_s}, #{model.reflect_on_association(ast).class_name}Type.connection_type do
112
+ resolve -> (#{singular_route_key(model)}, args, ctx) {
113
+ #{singular_route_key(model)}.#{ast}
114
+ }
115
+ end
116
+ FILE
117
+ end
118
+ end
119
+ end
120
+ rescue => ex
121
+ puts ex
122
+ end
123
+ end
124
+ end
125
+
126
+ def add_connection_query(model)
127
+ inject_into_file 'app/graphql/types/root_level_type.rb', after: "field :id, field: GraphQL::Relay::GlobalIdField.new('RootLevel')\n" do <<-FILE
128
+ connection :#{model.to_s.tableize}, #{model.to_s}Type.connection_type do
129
+ resolve ->(object, args, ctx){
130
+ #{model.to_s}.all
131
+ }
132
+ end
133
+ FILE
134
+ end
135
+ end
136
+
137
+ def create_mutation(model)
138
+ create_file mutation_path(model), <<-FILE
139
+ module #{model.to_s}Mutations
140
+
141
+ Create = GraphQL::Relay::Mutation.define do
142
+ name 'Create#{model.to_s}'
143
+
144
+ return_field :#{instance_name(model)}, #{model.to_s}Type
145
+
146
+ resolve -> (inputs, ctx) {
147
+ root = RootLevel::STATIC
148
+ attr = inputs.keys.inject({}) do |memo, key|
149
+ memo[key] = inputs[key] unless key == "clientMutationId"
150
+ memo
151
+ end
152
+
153
+ #{instance_name(model)} = #{model.to_s}.create(attr)
154
+
155
+ { #{instance_name(model)}: #{instance_name(model)} }
156
+ }
157
+ end
158
+
159
+ Update = GraphQL::Relay::Mutation.define do
160
+ name 'Update#{model.to_s}'
161
+
162
+ input_field :id, !types.ID
163
+
164
+ return_field :#{instance_name(model)}, #{model.to_s}Type
165
+
166
+ resolve -> (inputs, ctx) {
167
+ #{instance_name(model)} = NodeIdentification.object_from_id((inputs[:id]), ctx)
168
+ attr = inputs.keys.inject({}) do |memo, key|
169
+ memo[key] = inputs[key] unless key == "clientMutationId" || key == 'id'
170
+ memo
171
+ end
172
+
173
+ #{instance_name(model)}.update(attr)
174
+ { #{instance_name(model)}: #{instance_name(model)} }
175
+ }
176
+ end
177
+
178
+ Destroy = GraphQL::Relay::Mutation.define do
179
+ name "Destroy#{model.to_s}"
180
+
181
+ input_field :id, !types.ID
182
+
183
+ resolve -> (inputs, ctx) {
184
+ #{instance_name(model)} = NodeIdentification.object_from_id((inputs[:id]), ctx)
185
+ #{instance_name(model)}.destroy
186
+ { }
187
+ }
188
+ end
189
+ end
190
+ FILE
191
+ end
192
+
193
+ def add_fields_to_mutation(model)
194
+ columns = model.columns_hash
195
+ columns.keys.each do |k|
196
+ next if %w(id created_at updated_at).include? columns[k].name
197
+ if columns[k].type.present?
198
+ inject_into_file mutation_path(model), after: "name 'Update#{model.to_s}'\n" do <<-FILE
199
+ input_field :#{columns[k].name}, types.#{type_mapper[columns[k].type]}
200
+ FILE
201
+ end
202
+
203
+ inject_into_file mutation_path(model), after: "name 'Create#{model.to_s}'\n", :force => true do <<-FILE
204
+ input_field :#{columns[k].name}, !types.#{type_mapper[columns[k].type]}
205
+ FILE
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ def add_mutation_query(model)
212
+ inject_into_file "app/graphql/types/mutation_type.rb", after: "name 'MutationType'\n" do <<-FILE
213
+ field :create#{model.to_s}, field: #{model.to_s}Mutations::Create.field
214
+ field :update#{model.to_s}, field: #{model.to_s}Mutations::Update.field
215
+ field :destroy#{model.to_s}, field: #{model.to_s}Mutations::Destroy.field
216
+
217
+ FILE
218
+ end
219
+ end
220
+
221
+ def singular_route_key(model)
222
+ ActiveModel::Naming.singular_route_key(model)
223
+ end
224
+
225
+ def mutation_path(model)
226
+ "app/graphql/mutations/#{singular_route_key(model)}_mutations.rb"
227
+ end
228
+
229
+ def type_path(model)
230
+ "app/graphql/types/#{singular_route_key(model)}_type.rb"
231
+ end
232
+
233
+ def instance_name(model)
234
+ ActiveModel::Naming.singular_route_key(model)
235
+ end
236
+
237
+ def circular_finder
238
+ circular_finder = {}
239
+
240
+ models.each do |m|
241
+ associations = m.reflect_on_all_associations.map(&:name)
242
+ circular_finder[m.to_s] = [] unless circular_finder[m.to_s].present?
243
+
244
+ associations.each do |k|
245
+ association_klass = m.reflect_on_association(k).class_name
246
+ circular_finder[association_klass] = [] unless circular_finder[association_klass].present?
247
+
248
+ circular_finder[association_klass] << m.to_s
249
+ end
250
+ end
251
+
252
+ @circular_finder ||= circular_finder
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,39 @@
1
+ module Graphql
2
+ module Generators
3
+ class InitGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def add_gems
7
+ gem 'graphql'
8
+ gem 'graphql-relay'
9
+ gem 'graphiql-rails'
10
+ gem 'graphql-formatter'
11
+ end
12
+
13
+ def routes
14
+ route "post 'graphql' => 'graph_ql#execute'"
15
+ route "mount GraphiQL::Rails::Engine, at: '/graphiql', graphql_path: '/graphql'"
16
+ end
17
+
18
+ def autoload_paths
19
+ application do <<-'RUBY'
20
+ config.autoload_paths += Dir["#{config.root}/app/graphql/**/"]
21
+ RUBY
22
+ end
23
+ end
24
+
25
+ def copy_templates
26
+ copy_file 'controllers/graph_ql_controller.rb', 'app/controllers/graph_ql_controller.rb'
27
+ copy_file 'models/root_level.rb', 'app/models/root_level.rb'
28
+ copy_file 'graph/relay_schema.rb', 'app/graphql/relay_schema.rb'
29
+ copy_file 'graph/node_identification.rb', 'app/graphql/node_identification.rb'
30
+ copy_file 'graph/types/root_level_type.rb', 'app/graphql/types/root_level_type.rb'
31
+ copy_file 'graph/types/query_type.rb', 'app/graphql/types/query_type.rb'
32
+ copy_file 'graph/types/mutation_type.rb', 'app/graphql/types/mutation_type.rb'
33
+
34
+ copy_file 'config/graphiql.rb', 'config/initializers/graphiql.rb'
35
+ end
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1 @@
1
+ GraphiQL::Rails.config.query_params = true
@@ -0,0 +1,15 @@
1
+ class GraphQlController < ApplicationController
2
+ skip_before_filter :verify_authenticity_token
3
+
4
+ def execute
5
+ puts '-' * 100, GraphQLFormatter.new(params[:query]).to_s, '-' * 100
6
+ if params[:variables].present?
7
+ variables = JSON.parse(params[:variables])
8
+ else
9
+ variables = params[:variables]
10
+ end
11
+
12
+ render json: GraphQL::Query.new(RelaySchema, params[:query], variables: variables, debug: true).result
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ NodeIdentification = GraphQL::Relay::GlobalNodeIdentification.define do
2
+ # Given a UUID & the query context,
3
+ # return the corresponding application object
4
+ object_from_id -> (id, ctx) do
5
+ type_name, id = NodeIdentification.from_global_id(id)
6
+ # "Post" -> Post.find(id)
7
+ Object.const_get(type_name).find(id)
8
+ end
9
+
10
+ # Given an application object,
11
+ # return a GraphQL ObjectType to expose that object
12
+ type_from_object -> (object) do
13
+ (object.class.name + 'Type').constantize
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ RelaySchema = GraphQL::Schema.new(query: QueryType, mutation: MutationType)
2
+
3
+ module RelaySchemaHelpers
4
+ SCHEMA_DIR = Rails.root.join('app/assets/javascripts/relay/')
5
+ SCHEMA_PATH = File.join(SCHEMA_DIR, 'schema.json')
6
+
7
+ def explain
8
+ Rails.cache.fetch checksum do
9
+ RelaySchema.execute GraphQL::Introspection::INTROSPECTION_QUERY
10
+ end
11
+ end
12
+
13
+ def checksum
14
+ files = Dir["app/graph/**/*.rb"].reject { |f| File.directory?(f) }
15
+ content = files.map { |f| File.read(f) }.join
16
+ Digest::SHA256.hexdigest(content).to_s
17
+ end
18
+
19
+ def generate
20
+ FileUtils.mkdir_p SCHEMA_DIR
21
+ result = JSON.pretty_generate(RelaySchema.explain)
22
+ unless File.exists?(SCHEMA_PATH) && File.read(SCHEMA_PATH) == result
23
+ File.write(SCHEMA_PATH, result)
24
+ end
25
+ end
26
+
27
+ def remove
28
+ FileUtils.rm SCHEMA_PATH if File.exist? SCHEMA_PATH
29
+ end
30
+
31
+ end
32
+
33
+ RelaySchema.extend RelaySchemaHelpers
@@ -0,0 +1,3 @@
1
+ MutationType = GraphQL::ObjectType.define do
2
+ name 'MutationType'
3
+ end
@@ -0,0 +1,13 @@
1
+ # ...and a query root
2
+ QueryType = GraphQL::ObjectType.define do
3
+ name "Query"
4
+ description "The query root of this schema"
5
+
6
+ field :node, field: NodeIdentification.field
7
+
8
+ field :root, RootLevelType do
9
+ resolve -> (obj, args, ctx) { RootLevel::STATIC }
10
+ end
11
+
12
+ # End Of Queries
13
+ end
@@ -0,0 +1,8 @@
1
+ RootLevelType = GraphQL::ObjectType.define do
2
+ name 'RootLevel'
3
+ description 'Unassociated root object queries'
4
+
5
+ interfaces [NodeIdentification.interface]
6
+
7
+ field :id, field: GraphQL::Relay::GlobalIdField.new('RootLevel')
8
+ end
@@ -0,0 +1,7 @@
1
+ class RootLevel < Struct.new :id
2
+ STATIC = new(id: 'root').freeze
3
+
4
+ def self.find(_)
5
+ STATIC
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-graphql-generator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Muhammet
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-12 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: '3.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ description: This generator will put the graphql files input your app folder
28
+ email:
29
+ - dilekmuhammet@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/generators/graphql/USAGE
35
+ - lib/generators/graphql/create_all_generator.rb
36
+ - lib/generators/graphql/graphql_generator.rb
37
+ - lib/generators/graphql/graphql_helpers.rb
38
+ - lib/generators/graphql/init_generator.rb
39
+ - lib/generators/graphql/templates/config/graphiql.rb
40
+ - lib/generators/graphql/templates/controllers/graph_ql_controller.rb
41
+ - lib/generators/graphql/templates/graph/node_identification.rb
42
+ - lib/generators/graphql/templates/graph/relay_schema.rb
43
+ - lib/generators/graphql/templates/graph/types/mutation_type.rb
44
+ - lib/generators/graphql/templates/graph/types/query_type.rb
45
+ - lib/generators/graphql/templates/graph/types/root_level_type.rb
46
+ - lib/generators/graphql/templates/models/root_level.rb
47
+ homepage: https://github.com/movielala/rails-graphql-generator
48
+ licenses:
49
+ - MIT
50
+ metadata: {}
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ requirements: []
66
+ rubyforge_project:
67
+ rubygems_version: 2.5.1
68
+ signing_key:
69
+ specification_version: 4
70
+ summary: A rails generator for GrapphQL.
71
+ test_files: []