module Epiphy::Repository::ClassMethods
Public Instance Methods
Assigns an adapter.
Epiphy::Repository
is shipped with an adapters:
* Rethinkdb
@param adapter [Object] an object that implements
`Epiphy::Model::Adapters::Abstract` interface
@since 0.1.0
@see Epiphy::Adapter::Rethinkdb
@example
class UserRepository include Epiphy::Repository end # Adapter is set by a shared adapter by default. Unless you want to change, you shoul not need this adapter = Epiphy::Adapter::Rethinkdb.new aconnection, adb UserRepository.adapter = adapter
# File lib/epiphy/repository.rb, line 261 def adapter=(adapter) @adapter = adapter end
Returns all the persisted entities.
@return [Array<Object>] the result of the query
@since 0.1.0
@example
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.all # => [ #<Article:0x007f9b19a60098> ]
# File lib/epiphy/repository.rb, line 463 def all all_row = @adapter.all(collection) cursor = Epiphy::Repository::Cursor.new all_row do |item| to_entity(item) end cursor.to_a end
Deletes all the records from the current collection.
Execute a ‘r.table().delete()` on RethinkDB level.
@since 0.1.0
@example
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.clear # deletes all the records
# File lib/epiphy/repository.rb, line 593 def clear @adapter.clear(collection) end
Count the entity in this collection
@param void @return Interget @api public @since 0.2.0
# File lib/epiphy/repository.rb, line 603 def count @adapter.count(collection) end
Creates a record in the database for the given entity. It assigns the ‘id` attribute, in case of success.
If already persisted (‘id` present), it will try to insert use that id and will raise an error if the `id` is already exist
@param entity [#id,#id=] the entity to create
@return [Object] the entity
@since 0.1.0
@see Epiphy::Repository#persist
@example
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end article = Article.new(title: 'Introducing Epiphy::Model') article.id # => nil ArticleRepository.create(article) # creates a record article.id # => 23 ArticleRepository.create(article) # no-op
# File lib/epiphy/repository.rb, line 336 def create(entity) #unless entity.id begin result = @adapter.create(collection, to_document(entity)) entity.id = result rescue Epiphy::Model::EntityExisted => e raise e rescue RethinkDB::RqlRuntimeError => e raise Epiphy::Model::RuntimeError, e.message end #end end
Deletes a record in the database corresponding to the given entity.
If not already persisted (‘id` present) it raises an exception.
@param entity [#id] the entity to delete
@return [Object] the entity
@raise [Epiphy::Model::NonPersistedEntityError] if the given entity
wasn't already persisted.
@since 0.1.0
@see Epiphy::Model::NonPersistedEntityError
@example With a persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end article = ArticleRepository.find(23) article.id # => 23 ArticleRepository.delete(article) # deletes the record
@example With a non persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end article = Article.new(title: 'Introducing Epiphy::Model') article.id # => nil ArticleRepository.delete(article) # raises Epiphy::Model::NonPersistedEntityError
# File lib/epiphy/repository.rb, line 439 def delete(entity) if entity.id @adapter.delete(collection, entity.id) else raise Epiphy::Model::NonPersistedEntityError end entity end
Finds an entity by its identity.
If used with a SQL database, it corresponds to the primary key.
@param id [Object] the identity of the entity
@return [Object] the result of the query
@raise [Epiphy::Model::EntityNotFound] if the entity cannot be found.
@since 0.1.0
@see Epiphy::Model::EntityNotFound
@example With a persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.find(9) # => raises Epiphy::Model::EntityNotFound
# File lib/epiphy/repository.rb, line 493 def find(id) entity_id = nil if id.is_a? Epiphy::Entity raise TypeError, "Expecting an string, primitve value" end if id.is_a?(String) || id.is_a?(Integer) entity_id = id else entity_id = id.id if id.respond_to? :id end raise Epiphy::Model::EntityIdNotFound, "Missing entity id" if entity_id.nil? result = @adapter.find(collection, entity_id).tap do |record| raise Epiphy::Model::EntityNotFound.new unless record end to_entity(result) end
Returns the first entity in the database.
@return [Object,nil] the result of the query
@since 0.1.0
@see Epiphy::Repository#last
@example With at least one persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.first # => #<Article:0x007f8c71d98a28>
@example With an empty collection
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.first # => nil
# File lib/epiphy/repository.rb, line 537 def first(order_by=:id) result = @adapter.first(collection, order_by: order_by) if result to_entity result else result end end
Returns the last entity in the database.
@return [Object,nil] the result of the query
@since 0.1.0
@see Epiphy::Repository#last
@example With at least one persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.last # => #<Article:0x007f8c71d98a28>
@example With an empty collection
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end ArticleRepository.last # => nil
# File lib/epiphy/repository.rb, line 571 def last(order_by=:id) if result = @adapter.last(collection, order_by: order_by) to_entity result else nil end end
Creates or updates a record in the database for the given entity.
@param entity [#id, id=] the entity to persist
@return [Object] the entity
@since 0.1.0
@see Epiphy::Repository#create @see Epiphy::Repository#update
@example With a non persisted entity
require 'epiphy' class ArticleRepository include Epiphy::Repository end article = Article.new(title: 'Introducing Epiphy::Model') article.id # => nil ArticleRepository.persist(article) # creates a record article.id # => 23
@example With a persisted entity
require 'epiphy' class ArticleRepository include Epiphy::Repository end article = ArticleRepository.find(23) article.id # => 23 article.title = 'Launching Epiphy::Model' ArticleRepository.persist(article) # updates the record article = ArticleRepository.find(23) article.title # => "Launching Epiphy::Model"
# File lib/epiphy/repository.rb, line 304 def persist(entity) @adapter.persist(collection, to_document(entity)) end
Updates a record in the database corresponding to the given entity.
If not already persisted (‘id` present) it raises an exception.
@param entity [#id] the entity to update
@return [Object] the entity
@raise [Epiphy::Model::NonPersistedEntityError] if the given entity
wasn't already persisted.
@since 0.1.0
@see Epiphy::Repository#persist @see Epiphy::Model::NonPersistedEntityError
@example With a persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end article = ArticleRepository.find(23) article.id # => 23 article.title = 'Launching Epiphy::Model' ArticleRepository.update(article) # updates the record
@example With a non persisted entity
require 'epiphy/model' class ArticleRepository include Epiphy::Repository end article = Article.new(title: 'Introducing Epiphy::Model') article.id # => nil ArticleRepository.update(article) # raises Epiphy::Model::NonPersistedEntityError
# File lib/epiphy/repository.rb, line 391 def update(entity) if entity.id @adapter.update(collection, to_document(entity)) else raise Epiphy::Model::NonPersistedEntityError end end
Private Instance Methods
Determine entity name for this repository @return [String] entity name
@api public @since 0.1.0
@see self#get_name
# File lib/epiphy/repository.rb, line 736 def entity_name name = self.to_s.split('::').last if name.nil? return nil end name[0..-11] end
Determine colleciton/table name of this repository. Note that the repository name has to be the model name, appending Repository
@return [Symbol] collection name
@api public @since 0.1.0
@see Epiphy::Adapter::Rethinkdb#get_table
# File lib/epiphy/repository.rb, line 720 def get_name name = self.to_s.split('::').last #end = Repository.length + 1 if name.nil? return nil end name = name[0..-11].downcase.to_sym end
Fabricates a query and yields the given block to access the low level APIs exposed by the query itself.
This is a Ruby private method, because we wanted to prevent outside objects to query directly the database. However, this is a public API method, and this is the only way to filter entities.
The returned query SHOULD be lazy: the entities should be fetched by the database only when needed.
The returned query SHOULD refer to the entire collection by default.
Queries can be reused and combined together. See the example below.
A repository is storage independent. All the queries are delegated to the current adapter, which is responsible to implement a querying API.
Epiphy::Model
is shipped with adapter:
* RethinkDB: which yields a RethinkDB::ReQL class.
By default, all return items will be convert into its entity. The behavious can change by alter ‘to_entity` parameter
@param to_entity
[Boolean] to convert the result back to a entity class or not.
@param blk [Proc] a block of code that is executed in the context of a
query. The block will be passed two parameters. First parameter is the `reql` which is building. the second parameter is th `r` top name space of RethinkDB. By doing this, Repository doesn't have to include RethinkDB::Shortcuts
@return a query, the type depends on the current adapter
@api public @since 0.1.0
@see Epiphy::Adapters::Rethinkdb
@example
require 'epiphy/model' class ArticleRepository include Epiphy::Repository def self.most_recent_by_author(author, limit = 8) query do |r| where(author_id: author.id). desc(:published_at). limit(limit) end end def self.most_recent_published_by_author(author, limit = 8) # combine .most_recent_published_by_author and .published queries most_recent_by_author(author, limit).published end def self.published query do where(published: true) end end def self.rank # reuse .published, which returns a query that respond to #desc published.desc(:comments_count) end def self.best_article_ever # reuse .published, which returns a query that respond to #limit rank.limit(1) end def self.comments_average query.average(:comments_count) end end
# File lib/epiphy/repository.rb, line 689 def query(to_entity: true, &blk) result = @adapter.query(table: collection, &blk) require 'pp' if result.is_a? RethinkDB::Cursor return Epiphy::Repository::Cursor.new result do |item| to_entity(item) end end if result.is_a? Array result.map! do |item| to_entity(item) end end if result.is_a? Hash return to_entity(result) end result end
Convert all value of the entity into a document
@param [Epiphy::Entity] Entity
@return [Hash] hash object of entity value, except the nil value
@api public @since 0.1.0
# File lib/epiphy/repository.rb, line 774 def to_document entity document = {} entity.instance_variables.each {|var| document[var.to_s.delete("@")] = entity.instance_variable_get(var) unless entity.instance_variable_get(var).nil? } document end
Convert a hash into the entity object.
Note that we require a Entity
class same name with Repository
class, only different is the suffix Repository
.
@param [Hash] value object
@return [Epiphy::Entity] Entity
@api public @since 0.1.0
# File lib/epiphy/repository.rb, line 753 def to_entity ahash begin name = entity_name e = Object.const_get(name).new ahash.each do |k,v| e.send("#{k}=", v) end rescue raise Epiphy::Model::EntityClassNotFound end e end