Skip to content

vmeyet/priloo

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Priloo

Build Status Coverage Status Gem Downloads

Description

Priloo is a generalized preloader. It is inspired from ActiveRecord#preload(...), but it works for any object implementing its preloading protocol.

Property tree

Priloo accepts a collection and a tree of properties. The syntax is very similar to ActiveRecord#preload. The only difference is the special property __each__, used to visit items of a collection.

# ActiveRecord
collection.preload(user: { posts: :attachment })

# Priloo
collection.priload(user: { posts: { __each__: :attachment } })

ActiveRecord integration

Priloo integrates natively with ActiveRecord's preloader. The advantage if that you can traverse both AR and non-AR object, or have add custom preloadable properties to your ARs.

BABL integration

BABL can be configured to use Priloo by default.

::Babl.configure do |config|
    config.preloader = Priloo
end

BABL extracts the property tree from the template, and passes it to Priloo. No more N+1!

Preloading protocol

In order to have a preloadable property foo, an object must respond to the method foo__priloo__ and return a preloader.

All objects having the same preloader are loaded together using preloader.preload([...]).

If a property is not preloadable, Priloo fallbacks to calling the method (or access the property, for Hash). If the method doesn't exist, the error is ignored.

Custom preloadable properties

PreloadDependencies()

PreloadDependencies can be used to ensure properties are preloaded before the property is computed.

class Post
end

class User
    include Priloo::Preloadable

    has_many :posts

    # This decorator tells Priloo to load all posts, before
    # calling the method.
    PreloadDependencies(:posts)
    def number_of_likes
        posts.map(&:likes)
    end
end

# Usage
users.priload(:number_of_likes).each(&:number_of_likes) # No N+1, all posts are loaded at once.

PreloadBatch()

PreloadBatch is more general and makes it possible to write a completely custom preloading logic.

class Post
end

class User
    include Priloo::Preloadable

    has_many :posts

    # This decorator tells Priloo how to preload 'number_of_likes' for a collection of users.
    # For convenience, it also creates a similarly-named instance method.
    PreloadBatch()
    def self.number_of_likes(users)
        users.map { ... }
    end
end

# Usage
users.priload(:number_of_likes).each(&:number_of_likes) # No N+1

Install

gem 'priloo'

Limitations

This gem is a PoC and has certain limitations which makes it unsuitable for production, unless you know what you're doing.

  • The current implementation assumes that all objects at the same level have the same dependencies. If that's not the case, an exception is raised.

  • This gem is badly tested. Some parts are not even tested at all.

  • Error handling sucks. We should definitely adopt a "fail-fast" approach, instead of "ignore errors".

  • ActiveRecord integration relies on Rails internals, and the way we're calling native ActiveRecord::Preloader isn't safe (see rails/rails#32140).

License

Copyright (c) 2018 Bannerman, Frederic Terrazzoni

Licensed under the MIT license.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Ruby 100.0%