class GroongaClientModel::Record

Public Class Methods

all() click to toggle source
# File lib/groonga_client_model/record.rb, line 71
def all
  select.limit(-1)
end
clear_cache() click to toggle source
# File lib/groonga_client_model/record.rb, line 37
def clear_cache
  @@schema = nil
end
columns() click to toggle source
# File lib/groonga_client_model/record.rb, line 45
def columns
  schema.tables[table_name].columns
end
count() click to toggle source
# File lib/groonga_client_model/record.rb, line 67
def count
  select.limit(0).output_columns("_id").response.n_hits
end
create(attributes=nil, &block) click to toggle source
# File lib/groonga_client_model/record.rb, line 116
def create(attributes=nil, &block)
  if attributes.is_a?(Array)
    attributes.collect do |attrs|
      create(attrs, &block)
    end
  else
    record = new(attributes, &block)
    record.save
    record
  end
end
create!(attributes=nil, &block) click to toggle source
# File lib/groonga_client_model/record.rb, line 128
def create!(attributes=nil, &block)
  if attributes.is_a?(Array)
    attributes.collect do |attrs|
      create!(attrs, &block)
    end
  else
    record = new(attributes, &block)
    record.save!
    record
  end
end
define_attributes() click to toggle source
# File lib/groonga_client_model/record.rb, line 53
def define_attributes
  return if defined?(@defined)
  @defined = true

  columns.each do |name, column|
    type = normalize_type((column["value_type"] || {})["name"])
    attribute(name, type)
    if type == :boolean
      attribute_method_suffix("?")
      define_attribute_methods(name)
    end
  end
end
find(id) click to toggle source
# File lib/groonga_client_model/record.rb, line 75
def find(id)
  if id.respond_to?(:id)
    id = id.id
  end
  record = select.filter("_id == %{id}", id: id).limit(1).first
  if record.nil?
    raise RecordNotFound.new("Record not found: _id: <#{id}>")
  end
  record
end
first() click to toggle source
# File lib/groonga_client_model/record.rb, line 86
def first
  select.sort_keys("_id").limit(1).first
end
have_key?() click to toggle source
# File lib/groonga_client_model/record.rb, line 49
def have_key?
  columns.exist?("_key")
end
i18n_scope() click to toggle source
# File lib/groonga_client_model/record.rb, line 29
def i18n_scope
  :groonga_client_model
end
last() click to toggle source
# File lib/groonga_client_model/record.rb, line 90
def last
  select.sort_keys("-_id").limit(1).first
end
new(attributes=nil) { |self| ... } click to toggle source
Calls superclass method
# File lib/groonga_client_model/record.rb, line 169
def initialize(attributes=nil)
  self.class.define_attributes

  super()
  assign_attributes(attributes) if attributes

  if attribute("_id")
    @new_record = false
    clear_changes_information
  else
    @new_record = true
  end
  @destroyed = false

  yield self if block_given?
end
schema() click to toggle source
# File lib/groonga_client_model/record.rb, line 33
def schema
  @@schema ||= Schema.new
end
select() click to toggle source
# File lib/groonga_client_model/record.rb, line 94
def select
  full_text_searchable_column_names = []
  columns.each do |name, column|
    if column.have_full_text_search_index?
      full_text_searchable_column_names << name
    end
  end
  model_class = self
  model_class_module = Module.new do
    define_method :model_class do
      model_class
    end
  end
  extensions = [
    ClientOpener,
    Modelizable,
    model_class_module,
  ]
  Groonga::Client::Request::Select.new(table_name, extensions).
    match_columns(full_text_searchable_column_names)
end
table_name() click to toggle source
# File lib/groonga_client_model/record.rb, line 41
def table_name
  name.to_s.demodulize.underscore.pluralize
end

Private Class Methods

normalize_type(groonga_type) click to toggle source
# File lib/groonga_client_model/record.rb, line 141
def normalize_type(groonga_type)
  case groonga_type
  when "Bool"
    :boolean
  when "ShortText", "Text", "LongText"
    :string
  when /\AU?Int\d+\z/
    :integer
  when "Float", "Float32"
    :float
  when "Time"
    :datetime
  else
    ActiveModel::Type::Value.new
  end
end

Public Instance Methods

assign_dynamic_attribute(name, value) click to toggle source
# File lib/groonga_client_model/record.rb, line 244
def assign_dynamic_attribute(name, value)
  if respond_to?(name)
    singleton_class.__send__(:undef_method, name)
  end
  singleton_class.__send__(:define_method, name) do
    value
  end
end
assign_dynamic_attributes(dynamic_attributes) click to toggle source
# File lib/groonga_client_model/record.rb, line 236
def assign_dynamic_attributes(dynamic_attributes)
  return if dynamic_attributes.blank?

  dynamic_attributes.each do |name, value|
    assign_dynamic_attribute(name, value)
  end
end
delete() click to toggle source
# File lib/groonga_client_model/record.rb, line 203
def delete
  destroy_raw
end
destroy() click to toggle source
# File lib/groonga_client_model/record.rb, line 207
def destroy
  run_callbacks(:destroy) do
    destroy_raw
  end
end
destroyed?() click to toggle source
# File lib/groonga_client_model/record.rb, line 226
def destroyed?
  @destroyed
end
id() click to toggle source
# File lib/groonga_client_model/record.rb, line 218
def id
  _id
end
new_record?() click to toggle source
# File lib/groonga_client_model/record.rb, line 222
def new_record?
  @new_record
end
persisted?() click to toggle source
# File lib/groonga_client_model/record.rb, line 230
def persisted?
  return false if @new_record
  return false if @destroyed
  true
end
read_attribute_for_validation(attribute) click to toggle source
# File lib/groonga_client_model/record.rb, line 186
def read_attribute_for_validation(attribute)
  @attributes[attribute.to_s].value_before_type_cast
end
save(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 190
def save(validate: true)
  run_callbacks(:save) do
    save_raw(validate: validate)
  end
end
save!(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 196
def save!(validate: true)
  unless save(validate: validate)
    message = "Failed to save the record"
    raise RecordNotSaved.new(message, self)
  end
end
update(attributes) click to toggle source
# File lib/groonga_client_model/record.rb, line 213
def update(attributes)
  assign_attributes(attributes)
  save
end

Private Instance Methods

attribute?(attribute) click to toggle source
# File lib/groonga_client_model/record.rb, line 254
def attribute?(attribute)
  __send__(attribute)
end
build_sub_record(name, value) click to toggle source
# File lib/groonga_client_model/record.rb, line 375
def build_sub_record(name, value)
  column = self.class.columns[name]
  return value unless column

  return value unless column.value_type.type == "reference"

  class_name = name.classify
  begin
    if self.class.const_defined?(class_name)
      sub_record_class = self.class.const_get(class_name)
    else
      sub_record_class = class_name.constantize
    end
  rescue NameError
    return value
  end

  is_vector = (column.type == "vector")
  if is_vector
    sub_record_values = []
    value.each do |sub_name, sub_values|
      sub_values.each_with_index do |sub_value, i|
        sub_record_value = (sub_record_values[i] ||= {})
        sub_record_value[sub_name] = sub_value
      end
    end
    sub_record_values.collect do |sub_record_value|
      sub_record_class.new(sub_record_value)
    end
  else
    return nil if value["_key"].blank?
    sub_record_class.new(value)
  end
end
destroy_raw() click to toggle source
# File lib/groonga_client_model/record.rb, line 270
def destroy_raw
  if persisted?
    Client.open do |client|
      table = self.class.schema.tables[self.class.table_name]
      response = client.delete(table: table.name,
                               filter: "_id == #{_id}")
      unless response.success?
        message = "Failed to delete the record: "
        message << "#{response.return_code}: #{response.error_message}"
        raise Error.new(message, self)
      end
    end
  end
  @destroyed = true
  freeze
end
save_raw(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 258
def save_raw(validate: true)
  if validate
    if valid?
      upsert(validate: true)
    else
      false
    end
  else
    upsert(validate: false)
  end
end
update_timestamps() click to toggle source
# File lib/groonga_client_model/record.rb, line 410
def update_timestamps
  now = Time.now

  if new_record?
    [:created_at, :created_on].each do |attribute|
      __send__("#{attribute}=", now) if respond_to?("#{attribute}=")
    end
  end

  [:updated_at, :updated_on].each do |attribute|
    __send__("#{attribute}=", now) if respond_to?("#{attribute}=")
  end
end
upsert(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 287
def upsert(validate: true)
  if new_record?
    run_callbacks(:create) do
      upsert_raw(validate: validate)
    end
  else
    run_callbacks(:update) do
      upsert_raw(validate: validate)
    end
  end
end
upsert_raw(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 299
def upsert_raw(validate: true)
  return false unless upsert_sub_records(validate: validate)

  update_timestamps

  Client.open do |client|
    table = self.class.schema.tables[self.class.table_name]
    load_value_generator = LoadValueGenerator.new(self)
    value = load_value_generator.generate
    response = client.load(table: table.name,
                           values: [value],
                           output_ids: "yes",
                           output_errors: "yes",
                           command_version: "3")
    unless response.success?
      message = "Failed to save: "
      message << "#{response.return_code}: #{response.error_message}"
      raise RecordNotSaved.new(message, self)
    end
    if response.n_loaded_records.zero?
      message = "Failed to save"
      error = response.errors[0]
      if error and !error.return_code.zero?
        message << ": #{error.return_code}: #{error.message}: "
      end
      message << ": #{value.inspect}"
      raise RecordNotSaved.new(message, self)
    end
    if @new_record
      id = response.loaded_ids.first
      if id.nil?
        select_request = self.class.select.limit(1).output_columns("_id")
        if @attributes.key?("_key")
          select_request = select_request.filter("_key == %{key}",
                                                 key: _key)
        else
          # TODO: may return not newly added record
          select_request = select_request.sort_keys("-_id")
        end
        id = select_request.first._id
      end
      self._id = id
    end
    @new_record = false
    changes_applied
    true
  end
end
upsert_sub_record(sub_record, validate) click to toggle source
# File lib/groonga_client_model/record.rb, line 355
def upsert_sub_record(sub_record, validate)
  case sub_record
  when Record
    if sub_record.changed?
      sub_record.save(validate: validate)
    else
      true
    end
  when Array
    sub_record.each do |sub_element|
      unless upsert_sub_record(sub_element, validate)
        return false
      end
    end
    true
  else
    true
  end
end
upsert_sub_records(validate: true) click to toggle source
# File lib/groonga_client_model/record.rb, line 348
def upsert_sub_records(validate: true)
  attributes.each do |name, value|
    return false unless upsert_sub_record(value, validate)
  end
  true
end