[groonga-commit:4248] ranguba/rroonga [master] add Groonga::Command::Builder.escape_value.
null+ranguba at clear-code.com
null+ranguba at clear-code.com
Mon Jan 30 02:16:38 EST 2012
Kouhei Sutou 2012-01-30 16:16:38 +0900 (Mon, 30 Jan 2012)
New Revision: 234dc4512b9492572d8a6fe6d8c86c371dc7ae29
Log:
add Groonga::Command::Builder.escape_value.
Added files:
lib/groonga/command.rb
Modified files:
lib/groonga/context.rb
Renamed files:
test/test-command-select.rb
(from test/test-context-select.rb)
Added: lib/groonga/command.rb (+169 -0) 100644
===================================================================
--- /dev/null
+++ lib/groonga/command.rb 2012-01-30 16:16:38 +0900 (430a974)
@@ -0,0 +1,169 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Kouhei Sutou <kou at clear-code.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+module Groonga
+ module Command
+ class Builder
+ class << self
+ def escape_value(value)
+ escaped_value = value.to_s.gsub(/"/, '\\"')
+ "\"#{escaped_value}\""
+ end
+ end
+
+ attr_reader :command, :arguments
+ def initialize(command, arguments={})
+ @command = command
+ @arguments = arguments
+ end
+
+ def [](key)
+ @arguments[key]
+ end
+
+ def []=(key, value)
+ @arguments[key] = value
+ end
+
+ def build
+ query = "#{@command} "
+ @arguments.each do |key, value|
+ value = value.join(", ") if value.is_a?(::Array)
+ escaped_value = self.class.escape_value(value)
+ query << " --#{key} #{escaped_value}"
+ end
+ query
+ end
+ end
+
+ class Select
+ def initialize(context, table, options)
+ @context = context
+ @table = table
+ @options = normalize_options(options)
+ end
+
+ def exec
+ request_id = @context.send(query)
+ loop do
+ response_id, result = @context.receive
+ if request_id == response_id
+ drill_down_keys = @options["drilldown"]
+ if drill_down_keys.is_a?(String)
+ drill_down_keys = drill_down_keys.split(/(?:\s+|\s*,\s*)/)
+ end
+ return Result.parse(result, drill_down_keys)
+ end
+ # raise if request_id < response_id
+ end
+ end
+
+ private
+ def normalize_options(options)
+ normalized_options = {}
+ options.each do |key, value|
+ normalized_options[normalize_option_name(key)] = value
+ end
+ normalized_options
+ end
+
+ def normalize_option_name(name)
+ name = name.to_s.gsub(/-/, "_").gsub(/drill_down/, "drilldown")
+ name.gsub(/sort_by/, 'sortby')
+ end
+
+ def query
+ if @table.is_a?(String)
+ table_name = @table
+ else
+ table_name = @table.name
+ end
+ builder = Builder.new("select", @options.merge(:table => table_name))
+ builder.build
+ end
+
+ class Result < Struct.new(:n_hits, :columns, :values, :drill_down)
+ class << self
+ def parse(json, drill_down_keys)
+ select_result, *drill_down_results = JSON.parse(json)
+ result = new
+ n_hits, columns, values = extract_result(select_result)
+ result.n_hits = n_hits
+ result.columns = columns
+ result.values = values
+ if drill_down_results
+ result.drill_down = parse_drill_down_results(drill_down_results,
+ drill_down_keys)
+ end
+ result
+ end
+
+ def create_records(columns, values)
+ records = []
+ values.each do |value|
+ record = {}
+ columns.each_with_index do |(name, type), i|
+ record[name] = convert_value(value[i], type)
+ end
+ records << record
+ end
+ records
+ end
+
+ private
+ def parse_drill_down_results(results, keys)
+ named_results = {}
+ results.each_with_index do |drill_down, i|
+ n_hits, columns, values = extract_result(drill_down)
+ drill_down_result = DrillDownResult.new
+ drill_down_result.n_hits = n_hits
+ drill_down_result.columns = columns
+ drill_down_result.values = values
+ named_results[keys[i]] = drill_down_result
+ end
+ named_results
+ end
+
+ def extract_result(result)
+ meta_data, columns, *values = result
+ n_hits, = meta_data
+ [n_hits, columns, values]
+ end
+
+ def convert_value(value, type)
+ case type
+ when "Time"
+ Time.at(value)
+ else
+ value
+ end
+ end
+ end
+
+ def records
+ @records ||= self.class.create_records(columns, values)
+ end
+
+ class DrillDownResult < Struct.new(:n_hits, :columns, :values)
+ def records
+ @records ||= Result.create_records(columns, values)
+ end
+ end
+ end
+ end
+ end
+end
Modified: lib/groonga/context.rb (+4 -124)
===================================================================
--- lib/groonga/context.rb 2012-01-26 15:25:41 +0900 (ac00b83)
+++ lib/groonga/context.rb 2012-01-30 16:16:38 +0900 (896fca1)
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#
-# Copyright (C) 2010-2011 Kouhei Sutou <kou at clear-code.com>
+# Copyright (C) 2010-2012 Kouhei Sutou <kou at clear-code.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -15,6 +15,8 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+require "groonga/command"
+
module Groonga
class Context
# _path_ にある既存のデータベースを開く。ブロックを指定した場
@@ -70,130 +72,8 @@ module Groonga
# @option options [Array] XXX TODO
# TODO
def select(table, options={})
- select = SelectCommand.new(self, table, options)
+ select = Command::Select.new(self, table, options)
select.exec
end
-
- class SelectResult < Struct.new(:n_hits, :columns, :values,
- :drill_down)
- class << self
- def parse(json, drill_down_keys)
- select_result, *drill_down_results = JSON.parse(json)
- result = new
- n_hits, columns, values = extract_result(select_result)
- result.n_hits = n_hits
- result.columns = columns
- result.values = values
- if drill_down_results
- result.drill_down = parse_drill_down_results(drill_down_results,
- drill_down_keys)
- end
- result
- end
-
- def create_records(columns, values)
- records = []
- values.each do |value|
- record = {}
- columns.each_with_index do |(name, type), i|
- record[name] = convert_value(value[i], type)
- end
- records << record
- end
- records
- end
-
- private
- def parse_drill_down_results(results, keys)
- named_results = {}
- results.each_with_index do |drill_down, i|
- n_hits, columns, values = extract_result(drill_down)
- drill_down_result = DrillDownResult.new
- drill_down_result.n_hits = n_hits
- drill_down_result.columns = columns
- drill_down_result.values = values
- named_results[keys[i]] = drill_down_result
- end
- named_results
- end
-
- def extract_result(result)
- meta_data, columns, *values = result
- n_hits, = meta_data
- [n_hits, columns, values]
- end
-
- def convert_value(value, type)
- case type
- when "Time"
- Time.at(value)
- else
- value
- end
- end
- end
-
- def records
- @records ||= self.class.create_records(columns, values)
- end
-
- class DrillDownResult < Struct.new(:n_hits, :columns, :values)
- def records
- @records ||= SelectResult.create_records(columns, values)
- end
- end
- end
-
- class SelectCommand
- def initialize(context, table, options)
- @context = context
- @table = table
- @options = normalize_options(options)
- end
-
- def exec
- request_id = @context.send(query)
- loop do
- response_id, result = @context.receive
- if request_id == response_id
- drill_down_keys = @options["drilldown"]
- if drill_down_keys.is_a?(String)
- drill_down_keys = drill_down_keys.split(/(?:\s+|\s*,\s*)/)
- end
- return SelectResult.parse(result, drill_down_keys)
- end
- # raise if request_id < response_id
- end
- end
-
- private
- def normalize_options(options)
- normalized_options = {}
- options.each do |key, value|
- normalized_options[normalize_option_name(key)] = value
- end
- normalized_options
- end
-
- def normalize_option_name(name)
- name = name.to_s.gsub(/-/, "_").gsub(/drill_down/, "drilldown")
- name.gsub(/sort_by/, 'sortby')
- end
-
- def query
- if @table.is_a?(String)
- table_name = @table
- else
- table_name = @table.name
- end
- _query = "select #{table_name}"
- @options.each do |key, value|
- value = value.join(", ") if value.is_a?(::Array)
- escaped_value = value.to_s.gsub(/"/, '\\"')
- _query << " --#{key} \"#{escaped_value}\""
- end
- _query
- end
- end
end
end
Renamed: test/test-command-select.rb (+3 -3) 96%
===================================================================
--- test/test-context-select.rb 2012-01-26 15:25:41 +0900 (f2b713b)
+++ test/test-command-select.rb 2012-01-30 16:16:38 +0900 (5383a08)
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Kouhei Sutou <kou at clear-code.com>
+# Copyright (C) 2010-2012 Kouhei Sutou <kou at clear-code.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -13,7 +13,7 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-class ContextSelectTest < Test::Unit::TestCase
+class CommandSelectTest < Test::Unit::TestCase
include GroongaTestUtils
setup :setup_database
@@ -100,7 +100,7 @@ class ContextSelectTest < Test::Unit::TestCase
def test_drill_down_with_no_hit
result = context.select(@users,
- :filter => "_key == \"no hit\"",
+ :filter => "_key == \"no\\ hit\"",
:output_columns => ["_key"],
:drill_down => ["_key", "book"],
:drill_down_output_columns => "_key",
More information about the groonga-commit
mailing list