Class: APIQL

Inherits:
Object
  • Object
show all
Extended by:
CRUD
Defined in:
lib/apiql.rb

Defined Under Namespace

Modules: CRUD, Rails Classes: CacheMissed, Context, Entity, Error, HashEntity

Constant Summary collapse

@@cache =
{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CRUD

model

Constructor Details

#initialize(binder, *fields) ⇒ APIQL

Returns a new instance of APIQL.



239
240
241
242
# File 'lib/apiql.rb', line 239

def initialize(binder, *fields)
  @context = ::APIQL::Context.new(binder, *fields)
  @context.inject_delegators(self)
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



83
84
85
# File 'lib/apiql.rb', line 83

def context
  @context
end

Class Method Details

.cache(params) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# 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 = {} if @@cache.count > 1000
    @@cache[request_id] = request
  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) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# 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) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
# 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

.simple_class?(value) ⇒ Boolean

Returns:

  • (Boolean)


121
122
123
124
125
126
127
# 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

Instance Method Details

#eager_loadObject



244
245
246
247
248
249
250
# File 'lib/apiql.rb', line 244

def eager_load
  result = @eager_load

  @eager_load = []

  result
end

#render(schema) ⇒ Object



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/apiql.rb', line 252

def render(schema)
  result = {}

  schema.map 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.eager_load(eager_load)
          elsif data.respond_to?(:id)
            data = data.class.eager_load(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