Skip to content

Lazily-evaluated relationships #29

@mwpastore

Description

@mwpastore

I'm performance tuning some of my endpoints and I've noticed that JSONAPI::Serializers is triggering database calls on relationships even when those relationships are not given in the included option (i.e. included is nil). The results of these database calls are not being included in the output. Is this intentional, and if so, is there a way to tell JSONAPI::Serializers to lazily-evaluate relationships? If not intentional, is it possible there is some some class instantiation logic that is inspecting or otherwise poking the relationships that is causing the upstream Sequel::Model to fire off queries?

require 'sequel'
require 'jsonapi-serializers'
require 'logger'
require 'pp'

DB = Sequel.sqlite nil, 
  :loggers => [Logger.new($stdout)]

DB.create_table :foos do
  primary_key :id
  foreign_key :bar_id, :bars
  String :name
end

DB.create_table :bars do
  primary_key :id
end

DB.run "INSERT INTO bars (id) VALUES (1)"
DB.run "INSERT INTO foos (id, bar_id, name) VALUES (1, 1, 'myfoo')"

class Foo < Sequel::Model
  many_to_one :bar
end

class Bar < Sequel::Model
  one_to_many :foos
end

class FooSerializer
  include JSONAPI::Serializer

  attribute :name

  has_one :bar
end

class BarSerializer
  include JSONAPI::Serializer

  has_many :foos
end

pp JSONAPI::Serializer.serialize(Foo.first, {
  :is_collection => false,
  :skip_collection_check => true
})

And the output:

$ bundle show jsonapi-serializers
/home/mwp/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/jsonapi-serializers-0.3.0
$ bundle show sequel
/home/mwp/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/sequel-4.25.0
$ ruby --version
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]
$ ruby main.rb 
I, [2015-10-13T15:01:17.021499 #24657]  INFO -- : (0.000207s) PRAGMA foreign_keys = 1
I, [2015-10-13T15:01:17.021745 #24657]  INFO -- : (0.000031s) PRAGMA case_sensitive_like = 1
I, [2015-10-13T15:01:17.022125 #24657]  INFO -- : (0.000270s) CREATE TABLE `foos` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT, `bar_id` integer REFERENCES `bars`, `name` varchar(255))
I, [2015-10-13T15:01:17.022445 #24657]  INFO -- : (0.000118s) CREATE TABLE `bars` (`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT)
I, [2015-10-13T15:01:17.022600 #24657]  INFO -- : (0.000053s) INSERT INTO bars (id) VALUES (1)
I, [2015-10-13T15:01:17.022759 #24657]  INFO -- : (0.000053s) INSERT INTO foos (id, bar_id, name) VALUES (1, 1, 'myfoo')
I, [2015-10-13T15:01:17.023645 #24657]  INFO -- : (0.000307s) PRAGMA table_info('foos')
I, [2015-10-13T15:01:17.024828 #24657]  INFO -- : (0.000089s) PRAGMA table_info('bars')
I, [2015-10-13T15:01:17.025724 #24657]  INFO -- : (0.000076s) SELECT sqlite_version()
I, [2015-10-13T15:01:17.026072 #24657]  INFO -- : (0.000168s) SELECT * FROM `foos` LIMIT 1
I, [2015-10-13T15:01:17.026730 #24657]  INFO -- : (0.000078s) SELECT * FROM `bars` WHERE `id` = 1
{"data"=>
  {"id"=>"1",
   "type"=>"foos",
   "attributes"=>{"name"=>"myfoo"},
   "links"=>{"self"=>"/foos/1"},
   "relationships"=>
    {"bar"=>
      {"links"=>
        {"self"=>"/foos/1/relationships/bar", "related"=>"/foos/1/bar"}}}}}

The last INFO line (SELECT * FROM barsWHEREid = 1) is what I'm trying to eliminate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions