#!/usr/bin/env ruby # require 'active_record' require 'active_support' require 'benchmark' require 'oj' require 'standalone_migrations' require 'surikat/types' require 'surikat/routes' require 'surikat/scaffold' require 'surikat/new_app' include Scaffold include NewApp def generate arguments available_targets = %w(scaffold model aaa migration) if arguments.to_a.empty? puts "Syntax: surikat generate target [options]\nAvailable targets: #{available_targets.join(', ')}" return end target = arguments.shift case target when 'scaffold' generate_scaffold arguments when 'model' generate_model arguments.shift, arguments when 'aaa' generate_aaa when 'migration' StandaloneMigrations::Generator.migration arguments.shift, arguments else puts "Sorry, I don' t know how to generate '#{target}'. Available targets are: #{available_targets.join(', ')}" end end def list_routes all_queries = Routes.new.all %w(queries mutations).each do |group, queries| puts "\n#{group.capitalize}:\n----------\n" all_queries[group].keys.sort.each do |key| input_s = (all_queries[group][key]['arguments'].to_a.map {|t_name, t_type| "#{t_name}: #{t_type}"}).join(', ') puts "Name: #{key}, resolves in #{all_queries[group][key]['class']}##{all_queries[group][key]['method']}, result returned as #{all_queries[group][key]['output_type']}, input arguments: " + (input_s.empty? ? 'None' : "{#{input_s}}") end end end def list_types all_types = Types.new.all {'Output' => 'fields', 'Input' => 'arguments'}.each do |type_direction, enums| puts "\n#{type_direction} types:\n-----------------------" all_types.keys.select {|t_name| all_types[t_name]['type'] == type_direction}.sort.each do |type_key| puts "\nName: #{type_key}" all_types[type_key][enums].to_a.each do |t_name, t_type| puts "\t#{t_name}: #{t_type}" end end end end def output_type_selectors(fields, all_types, stack) depth = stack.count + 2 return '' if fields&.empty? || depth > 100 spaces = ' ' * depth fewer_spaces = ' ' * (depth - 1) " {\n" + fields.map do |f, t| t_singular = t.gsub(/[\[\]\!]/, '') if Types::BASIC.include?(t_singular) "#{spaces}#{f}" else sub_type = all_types[t_singular] stack.include?(f) ? nil : "#{fewer_spaces} #{f}#{output_type_selectors(sub_type['fields'], all_types, stack + [f])}" end end.compact.join("\n") + "\n#{fewer_spaces}}" end def exemplify_queries(query_name, route) unless (r_args = route['arguments']).blank? arguments = '(' + r_args.map {|k, v| "#{k}: #{random_values(v)}"}.join(', ') + ')' else arguments = '' end output_type_singular = route['output_type'].gsub(/[\[\]\!]/, '') all_types = Types.new.all output_type = all_types[output_type_singular] if Types::BASIC.include?(output_type_singular) selectors = '' else selectors = output_type_selectors(output_type['fields'], all_types, []) end query_text = "{\n #{query_name}#{arguments}#{selectors}\n}" puts "Query:\n#{query_text}" puts "\n\ncurl command:\ncurl 0:3000 -X POST -d 'query=#{CGI::escape(query_text)}'" end def exemplify_mutations(query_name, route) unless (r_args = route['arguments']).blank? arguments_types = '(' + r_args.map do |k, v| kk = ActiveSupport::Inflector.singularize(k.underscore) "$#{kk}: #{v}" end.join(', ') + ')' arguments_vars = '(' + r_args.map do |k, v| kk = ActiveSupport::Inflector.singularize(k.underscore) "#{kk}: $#{kk}" end.join(', ') + ')' else arguments_types = '' arguments_vars = '' end output_type_singular = route['output_type'].gsub(/[\[\]\!]/, '') all_types = Types.new.all output_type = all_types[output_type_singular] if Types::BASIC.include?(output_type_singular) selectors = '' else selectors = output_type_selectors(output_type['fields'], all_types, []) end query_text = "mutation #{query_name}#{arguments_types} {\n #{query_name}#{arguments_vars}#{selectors}\n}" variables = {} r_args.each.each do |var_name, var_type| k_var_name = ActiveSupport::Inflector.singularize(var_name.underscore) variables[k_var_name] = {} all_types[var_type]['arguments'].each do |a, t| next if a == 'id' && route['method'] == 'create' # yes, someone may make create queries with other names if Types::BASIC.include?(t) variables[k_var_name][a] = random_values(t) else variables[k_var_name][a] = "vars for #{t}" # TODO - recurse to generate variables for custom type t end end end puts "Query:\n#{query_text}\n\nVariables:\n#{JSON.pretty_generate(variables)}" puts "\n\ncurl command:\ncurl 0:3000 -X POST -d 'query=#{CGI::escape(query_text)}' -d 'variables=#{CGI::escape(Oj.dump(variables))}'" end # build example queries for a specific query # Works with two arguments (class name and method name, for example 'BookQueries get') def exemplify(arguments) all_routes = Routes.new.all class_n, method_n = arguments[0], arguments[1] route, collection = nil, nil %w(queries mutations).each do |col| fr = all_routes[col].keys.detect do |r| qr = all_routes[col][r] [qr['class'], qr['method']] == [class_n, method_n] end (route, collection = fr, col) if fr end unless route puts "No route found for given class and method.\nUsage: surikat exemplify query_class_name method_name\nExample: surikat exemplify AuthorQueries get" return end send "exemplify_#{collection}", route, all_routes[collection][route] end def list(arguments) available_targets = %w(types) target = arguments.to_a.shift case target when 'types' list_types when 'routes' list_routes else puts "Usage: surikat list #{available_targets.join('|')}" end end def random_values(type) { 'ID' => 1, 'Int' => 100, 'Float' => 3.14, 'Boolean' => true, 'String' => '"something"' }[type] end ######################### command = ARGV.shift available_commands = %w(new generate destroy list exemplify) if command.nil? puts "Usage: surikat command arguments\nAvailable commands: #{available_commands.join(', ')}" exit end case command when 'new' new_app ARGV when 'generate' generate ARGV when 'list' list ARGV when 'exemplify' exemplify ARGV when 'help' #help ARGV else puts "Sorry, I don't know how to '#{command}'. Available commands are: #{available_commands.join(', ')}" end