class SqlcachedClient::Entity

Attributes

attributes[R]

Public Class Methods

association_names() click to toggle source
# File lib/sqlcached_client/entity.rb, line 210
def association_names
  registered_associations.map(&:accessor_name)
end
build_query_tree() click to toggle source
# File lib/sqlcached_client/entity.rb, line 236
def build_query_tree
  # returns the subtrees (associated classes) of the given entity class
  get_associated_entities = -> (entity) {
    entity.registered_associations.map do |a|
      Module.const_get(a.class_name)
    end
  }

  # function to apply to each node while traversing the tree
  visit = -> (entity, parent, index) {
    entity.server.build_request_item(
      entity.query_id,
      entity.query,
      # query_params
      if parent
        Hash[
          parent.registered_associations[index].join_attributes.map do |j_attr|
            [ j_attr[0], {
              value: j_attr[1],
              type: begin
                if entity.join_constant_value?(j_attr[1])
                  'constant'
                else
                  'parent_attribute'
                end
              end
            } ]
          end
        ]
      else
        nil
      end,
      entity.cache
    ).merge(associations: entity.association_names)
  }

  # builds the result of a visit step
  result_builder = -> (root, subtrees) {
    { root: root, subtrees: subtrees }
  }

  # traverse the tree
  visit_in_preorder(get_associated_entities, visit, result_builder)
end
cache(seconds = nil) click to toggle source

Configures the caching timing if a parameter is provided, otherwise returns the value set in the current class or in a superclass. Default value is true.

# File lib/sqlcached_client/entity.rb, line 222
def cache(seconds = nil)
  if seconds.nil?
    @cache ||
      if superclass = ancestors_lookup(:cache)
        superclass.cache
      else
        true
      end
  else
    @cache = seconds
  end
end
entity_name(value) click to toggle source

Sets the name of this entity @param value [String]

# File lib/sqlcached_client/entity.rb, line 35
def entity_name(value)
  @query_id = value
end
entity_namespace(value = nil) click to toggle source

Sets a prefix for each entity name, or returns the value previously set if no parameter is given

# File lib/sqlcached_client/entity.rb, line 25
def entity_namespace(value = nil)
  if value.nil?
    @entity_namespace || try_ancestor(:entity_namespace)
  else
    @entity_namespace = value
  end
end
has_many(accessor_name, options) click to toggle source

Defines a 'has_many' relationship. Available options are

class_name

Specifies the class of the associated objects, if not given it's inferred from the accessor_name (singularized + camelized).

where

Specifies how to fill the query template for the associated objects. It's an hash where each key is a foreign parameter that will be set to the value provided. A special case occours when the value is a Symbol, in this case it represents the value of the attribute named as the symbol. For example, where: { id: :user_id } fills the parameter id of the foreign entity with the value of self.user_id.

# File lib/sqlcached_client/entity.rb, line 143
def has_many(accessor_name, options)
  foreign_class_name =
    if options[:class_name].present?
      options[:class_name]
    else
      accessor_name.to_s.singularize.camelize
    end
  # the query to run to get the data
  association = -> (this, foreign_entity, join_attributes, dry_run) {
    foreign_entity.where(Hash[ join_attributes.map do |attr_names|
      attr_value =
        if this.join_constant_value?(attr_names[1])
          attr_names[1]
        else
          this.send(attr_names[1])
        end
      [ attr_names[0], attr_value ]
    end ], dry_run)
  }
  # get the attributes to define the foreign scope
  join_attributes = (options[:where] || []).to_a
  # memoize the associated resultset
  memoize_var = "@has_many_#{accessor_name}"
  # define the accessor method
  define_method(accessor_name) do |dry_run = false|
    # get the associated entity class
    foreign_entity = Module.const_get(foreign_class_name)
    if dry_run
      association.(self, foreign_entity, join_attributes, true)
    else
      instance_variable_get(memoize_var) ||
        instance_variable_set(memoize_var,
          association.(self, foreign_entity, join_attributes, false))
    end
  end
  # define the setter method
  define_method("#{accessor_name}=") do |array|
    # get the associated entity class
    foreign_entity = Module.const_get(foreign_class_name)
    instance_variable_set(memoize_var,
      Resultset.new(foreign_entity, array))
  end
  # save the newly created association
  register_association(OpenStruct.new({
    accessor_name: accessor_name.to_sym,
    class_name: foreign_class_name,
    join_attributes: join_attributes
  }))
end
has_one(accessor_name, options) click to toggle source

Defines a 'has_one' relationship. See 'has_many' for the available options

# File lib/sqlcached_client/entity.rb, line 195
def has_one(accessor_name, options)
  plural_accessor_name = "s_#{accessor_name}".to_s.pluralize
  class_name = accessor_name.to_s.camelize
  has_many(plural_accessor_name, { class_name: class_name }.merge(options))
  define_method(accessor_name) do
    send(plural_accessor_name).first
  end
end
is_an_association?(name) click to toggle source
# File lib/sqlcached_client/entity.rb, line 215
def is_an_association?(name)
  association_names.include?(name.to_sym)
end
join_constant_value?(value) click to toggle source
# File lib/sqlcached_client/entity.rb, line 282
def join_constant_value?(value)
  !value.is_a?(Symbol)
end
load_tree(root_conditions, attachment_name = nil, attachment_conditions = nil) click to toggle source

Like 'where' but loads every associated entity recursively at any level,

with only one interaction with the server

@param root_conditions [Array]

# File lib/sqlcached_client/entity.rb, line 289
def load_tree(root_conditions, attachment_name = nil,
    attachment_conditions = nil)
  attachments =
    if attachment_name.present?
      build_attachments(attachment_name, attachment_conditions,
        root_conditions.size)
    else
      nil
    end
  server_session do |server, session|
    Resultset.new(
      self,
      server.run_query(
        session,
        server.build_tree_request(build_query_tree, root_conditions,
          attachments)
      ),
      attachments
    )
  end
end
new(attributes) click to toggle source

@param attributes [Hash]

# File lib/sqlcached_client/entity.rb, line 15
def initialize(attributes)
  @attributes = attributes
  define_readers(attributes.keys)
end
query(*args, &block) click to toggle source

Sets the query of this entity if a parameter is provided, otherwise returns the value previously set.

# File lib/sqlcached_client/entity.rb, line 51
def query(*args, &block)
  if args.empty?
    @query
  else
    if args[0].is_a?(String)
      @query = args[0].strip
    else
      @query = build_arel(
        args.inject({}) do |acc, param|
          acc.merge(
            param.is_a?(Hash) ? param : Hash[ [[param, nil]] ]
          )
        end,
        block).to_sql
    end
  end
end
query_id() click to toggle source

Returns the identifier of the query template of the current entity @return [String]

# File lib/sqlcached_client/entity.rb, line 41
def query_id
  if prefix = entity_namespace.presence
    "#{prefix}::#{@query_id}"
  else
    @query_id
  end
end
registered_associations() click to toggle source
# File lib/sqlcached_client/entity.rb, line 205
def registered_associations
  @registered_associations || []
end
server(config = nil) click to toggle source

Configures the server of this entity if a parameter is provided, otherwise returns the server object previously set.

# File lib/sqlcached_client/entity.rb, line 71
def server(config = nil)
  if config.nil?
    @server || try_ancestor(:server)
  else
    @server =
      if config.is_a?(Hash)
        Server.new(config)
      else
        config
      end
  end
end
server_session(&block) click to toggle source

Gets a session from the server and yields the passed block

# File lib/sqlcached_client/entity.rb, line 85
def server_session(&block)
  server.session(&block)
end
transaction(&block) click to toggle source
# File lib/sqlcached_client/entity.rb, line 90
def transaction(&block)
  proxy = ProxyObject.new(self)
  srv_local = server
  session = server.get_session
  proxy.plug_method(:server_session) do |server_session_block|
    instance_exec(srv_local, session, &server_session_block)
  end
  result = proxy.execute(srv_local, session, &block)
  session.finish
  result
end
where(params, dry_run = false) click to toggle source

Runs the entity query with the provided parameters @return [Resultset]

# File lib/sqlcached_client/entity.rb, line 104
def where(params, dry_run = false)
  request =
    begin
      paramIterator = -> (parameter) {
        server.build_request_item(query_id, query, parameter, cache)
      }
      if params.is_a?(Array)
        params.map { |p| instance_exec(p, &paramIterator) }
      else
        instance_exec(params, &paramIterator)
      end
    end
  if dry_run
    request
  else
    server_resp =
      server_session do |server, session|
        server.run_query(session, server.build_request(
          request.is_a?(Array) ? request : [request]
        ))
      end
    server_resp.flatten!(1) if server_resp.is_array?
    Resultset.new(self, server_resp)
  end
end

Private Class Methods

ancestors_lookup(method_name) click to toggle source

Finds the first ancestor that responds to the given method @param method_name [Symbol] the method to find @return [Class]

# File lib/sqlcached_client/entity.rb, line 321
def ancestors_lookup(method_name)
  ancestors[1..-1].detect { |a| a.respond_to?(method_name) }
end
register_association(association_struct) click to toggle source
# File lib/sqlcached_client/entity.rb, line 313
def register_association(association_struct)
  @registered_associations ||= []
  @registered_associations << association_struct
end
try_ancestor(method_name) click to toggle source

Calls the given method on the first ancestor that responds to the method @param method_name [Symbol] @return nil if no ancestor responds to the method, or the value

returned by 'method_name'
# File lib/sqlcached_client/entity.rb, line 330
def try_ancestor(method_name)
  ancestors_lookup(method_name).try(method_name)
end

Public Instance Methods

build_associations(max_depth = false) click to toggle source
# File lib/sqlcached_client/entity.rb, line 386
def build_associations(max_depth = false)
  Resultset.new(self.class, [self]).build_associations(max_depth)
end
define_readers(attr_names) click to toggle source

Define the readers for the attribute names specified @param attr_names [Array]

# File lib/sqlcached_client/entity.rb, line 337
def define_readers(attr_names)
  attr_names.each do |attr_name|
    if respond_to?(attr_name)
      if self.class.is_an_association?(attr_name)
        # lazy instantiate associated records
        association_writer = method("#{attr_name}=")
        association_reader = method(attr_name)
        define_singleton_method(attr_name) do
          association_writer.(attributes[attr_name])
          association_reader.()
        end
      else
        raise "Cannot define accessor: #{attr_name}"
      end
    else
      define_singleton_method(attr_name) do
        attributes[attr_name]
      end
    end
  end
end
get_association_requests() click to toggle source
# File lib/sqlcached_client/entity.rb, line 365
def get_association_requests
  self.class.association_names.map do |a_name|
    send(a_name, true)
  end
end
get_associations() click to toggle source
# File lib/sqlcached_client/entity.rb, line 379
def get_associations
  self.class.association_names.map do |a_name|
    send(a_name)
  end
end
join_constant_value?(value) click to toggle source
# File lib/sqlcached_client/entity.rb, line 360
def join_constant_value?(value)
  self.class.join_constant_value?(value)
end
set_associations_data(associations_data) click to toggle source
# File lib/sqlcached_client/entity.rb, line 372
def set_associations_data(associations_data)
  self.class.association_names.map.with_index do |a_name, i|
    send("#{a_name}=", associations_data[i])
  end
end
to_h() click to toggle source
# File lib/sqlcached_client/entity.rb, line 391
def to_h
  attributes
end