class APIQL
Attributes
context[R]
Public Class Methods
cache(params)
click to toggle source
# File lib/apiql.rb, line 103 def cache(params) request_id = params[:apiql] request = params[:apiql_request] if request.present? request = compile(request) redis&.set("api-ql-cache-#{request_id}", request.to_json) @@cache[request_id] = request @@cache = {} if(@@cache.count > 1000) else request = @@cache[request_id] request ||= JSON.parse(redis.get("api-ql-cache-#{request_id}")) rescue nil raise CacheMissed unless request.present? && request.is_a?(::Array) end request end
eager_loads(schema)
click to toggle source
# File lib/apiql.rb, line 129 def eager_loads(schema) result = [] schema&.each do |call| if call.is_a? Hash call.each do |function, sub_schema| next if function.include? '(' function = function.split(':').last.strip if function.include? ':' function = function.split('.').first if function.include? '.' sub = eager_loads(sub_schema) if sub.present? result.push(function => sub) else result.push function end end end end result end
mount(klass, as: nil)
click to toggle source
# File lib/apiql.rb, line 89 def mount(klass, as: nil) as ||= klass.name.split('::').last.underscore as += '.' if as.present? klass.instance_methods(false).each do |method| klass.alias_method("#{as}#{method}", method) klass.remove_method(method) if as.present? end include klass end
new(binder, *fields)
click to toggle source
# File lib/apiql.rb, line 239 def initialize(binder, *fields) @context = ::APIQL::Context.new(binder, *fields) @context.inject_delegators(self) end
simple_class?(value)
click to toggle source
# File lib/apiql.rb, line 121 def simple_class?(value) value.nil? || value.is_a?(TrueClass) || value.is_a?(FalseClass) || value.is_a?(Symbol) || value.is_a?(String) || value.is_a?(Integer) || value.is_a?(Float) || value.is_a?(BigDecimal) || value.is_a?(Hash) end
Private Class Methods
compile(schema)
click to toggle source
# File lib/apiql.rb, line 163 def compile(schema) result = [] ptr = result pool = [] push_key = lambda do |key, subtree = false| ptr.each_with_index do |e, index| if e.is_a?(::Hash) return e[key] if e[key] elsif e == key if subtree ptr[index] = { key => (p = []) } return p end return end end if subtree ptr.push(key => (p = [])) return p else ptr.push(key) end end last_key = nil while schema.present? do if reg = schema.match(/\A\s*\{(?<rest>.*)\z/m) # { schema = reg[:rest] pool.push(ptr) ptr = push_key.call(last_key, true) elsif reg = schema.match(/\A\s*\}(?<rest>.*)\z/m) # } schema = reg[:rest] ptr = pool.pop elsif pool.any? if reg = schema.match(/\A\s*((?<alias>[\w\.]+):\s*)?(?<name>[\w\.]+)(\((?<params>.*?)\))?(?<rest>.*)\z/m) schema = reg[:rest] key = reg[:alias].present? ? "#{reg[:alias]}: #{reg[:name]}" : reg[:name] key += "(#{reg[:params]})" unless reg[:params].nil? push_key.call(key) last_key = key else raise Error, schema end elsif reg = schema.match(/\A\s*((?<alias>[\w\.]+):\s*)?(?<name>[\w\.]+)(\((?<params>((\w+)(\s*\,\s*\w+)*))?\))?\s*\{(?<rest>.*)\z/m) schema = reg[:rest] key = "#{reg[:alias] || reg[:name]}: #{reg[:name]}(#{reg[:params]})" pool.push(ptr) ptr = push_key.call(key, true) elsif reg = schema.match(/\A\s*((?<alias>[\w\.]+):\s*)?(?<name>[\w\.]+)(\((?<params>((\w+)(\s*\,\s*\w+)*))?\))?\s*\n?(?<rest>.*)\z/m) schema = reg[:rest] key = "#{reg[:alias] || reg[:name]}: #{reg[:name]}(#{reg[:params]})" push_key.call(key) else raise Error, schema end end result end
redis()
click to toggle source
# File lib/apiql.rb, line 154 def redis @redis ||= begin ::Redis.new(host: 'localhost') rescue nil end end
Public Instance Methods
eager_load()
click to toggle source
# File lib/apiql.rb, line 244 def eager_load result = @eager_load @eager_load = [] result end
render(schema)
click to toggle source
# File lib/apiql.rb, line 252 def render(schema) result = {} schema.each do |call| if call.is_a? ::Hash call.each do |function, sub_schema| reg = function.match(/\A((?<alias>[\w\.\!]+):\s*)?(?<name>[\w\.\!]+)(\((?<params>.*?)\))?\z/) raise Error, function unless reg.present? name = reg[:alias] || reg[:name] function = reg[:name] params = @context.parse_params(reg[:params].presence) @eager_load = APIQL::eager_loads(sub_schema) data = public_send(function, *params) if @eager_load.present? && !data.is_a?(::Hash) && !data.is_a?(::Array) if data.respond_to?(:eager_load) data = data.includes(eager_load) elsif data.respond_to?(:id) data = data.class.includes(eager_load).find(data.id) end end if result[name].is_a? ::Hash result = result.deep_merge({ name => @context.render_value(data, sub_schema) }) else result[name] = @context.render_value(data, sub_schema) end end else reg = call.match(/\A((?<alias>[\w\.\!]+):\s*)?(?<name>[\w\.\!]+)(\((?<params>.*?)\))?\z/) raise Error, call unless reg.present? name = reg[:alias] || reg[:name] function = reg[:name] params = @context.parse_params(reg[:params].presence) @eager_load = [] data = public_send(function, *params) if data.is_a? Array if data.any? { |item| !APIQL::simple_class?(item) } data = nil end elsif !APIQL::simple_class?(data) data = nil end if result[name].is_a? ::Hash result = result.deep_merge({ name => data }) else result[name] = data end end end result end