groonga 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/NEWS.ja.rdoc +18 -3
  2. data/NEWS.rdoc +18 -3
  3. data/README.ja.rdoc +2 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +14 -5
  6. data/TUTORIAL.ja.rdoc +82 -16
  7. data/benchmark/{read-write-small-many-items.rb → read-write-many-small-items.rb} +26 -23
  8. data/benchmark/{write-small-many-items.rb → write-many-small-items.rb} +26 -23
  9. data/example/bookmark.rb +49 -5
  10. data/ext/rb-grn-array.c +11 -1
  11. data/ext/rb-grn-column.c +132 -5
  12. data/ext/rb-grn-context.c +85 -80
  13. data/ext/rb-grn-database.c +182 -9
  14. data/ext/rb-grn-expression-builder.c +69 -0
  15. data/ext/rb-grn-expression.c +314 -0
  16. data/ext/rb-grn-fix-size-column.c +68 -89
  17. data/ext/rb-grn-hash.c +14 -5
  18. data/ext/rb-grn-index-column.c +14 -55
  19. data/ext/rb-grn-object.c +206 -75
  20. data/ext/rb-grn-operation.c +92 -0
  21. data/ext/rb-grn-patricia-trie.c +10 -32
  22. data/ext/rb-grn-query.c +9 -9
  23. data/ext/rb-grn-table-cursor.c +19 -80
  24. data/ext/rb-grn-table-key-support.c +33 -39
  25. data/ext/rb-grn-table.c +436 -79
  26. data/ext/rb-grn-type.c +10 -3
  27. data/ext/rb-grn-utils.c +131 -4
  28. data/ext/rb-grn-variable-size-column.c +36 -0
  29. data/ext/rb-grn-variable.c +90 -0
  30. data/ext/rb-grn.h +109 -56
  31. data/ext/rb-groonga.c +4 -0
  32. data/extconf.rb +39 -13
  33. data/html/index.html +2 -2
  34. data/lib/groonga.rb +22 -0
  35. data/lib/groonga/expression-builder.rb +141 -0
  36. data/lib/groonga/record.rb +25 -1
  37. data/lib/groonga/schema.rb +418 -0
  38. data/test/test-column.rb +11 -23
  39. data/test/test-context.rb +1 -1
  40. data/test/test-database.rb +60 -19
  41. data/test/test-expression-builder.rb +114 -0
  42. data/test/test-expression.rb +55 -0
  43. data/test/test-fix-size-column.rb +53 -0
  44. data/test/test-hash.rb +10 -3
  45. data/test/test-index-column.rb +24 -0
  46. data/test/test-patricia-trie.rb +9 -0
  47. data/test/test-procedure.rb +5 -5
  48. data/test/test-record.rb +71 -4
  49. data/test/test-schema.rb +207 -0
  50. data/test/test-table.rb +94 -12
  51. data/test/test-type.rb +18 -11
  52. data/test/test-variable-size-column.rb +53 -0
  53. data/test/test-variable.rb +28 -0
  54. metadata +18 -5
data/ext/rb-groonga.c CHANGED
@@ -84,6 +84,10 @@ Init_groonga (void)
84
84
  rb_grn_init_accessor(mGrn);
85
85
  rb_grn_init_record(mGrn);
86
86
  rb_grn_init_query(mGrn);
87
+ rb_grn_init_variable(mGrn);
88
+ rb_grn_init_operation(mGrn);
89
+ rb_grn_init_expression(mGrn);
90
+ rb_grn_init_expression_builder(mGrn);
87
91
  rb_grn_init_logger(mGrn);
88
92
  rb_grn_init_snippet(mGrn);
89
93
  }
data/extconf.rb CHANGED
@@ -21,6 +21,7 @@ require 'English'
21
21
  require 'mkmf'
22
22
  require 'pkg-config'
23
23
  require 'fileutils'
24
+ require 'shellwords'
24
25
 
25
26
  checking_for(checking_message("GCC")) do
26
27
  if macro_defined?("__GNUC__", "")
@@ -35,18 +36,45 @@ package_name = "groonga"
35
36
  module_name = "groonga"
36
37
  ext_dir_name = "ext"
37
38
  src_dir = File.join(File.expand_path(File.dirname(__FILE__)), ext_dir_name)
38
- major, minor, micro = 0, 0, 8
39
+ major, minor, micro = 0, 1, 0
40
+
41
+ def local_groonga_base_dir
42
+ File.join(File.dirname(__FILE__), "vendor")
43
+ end
44
+
45
+ def local_groonga_install_dir
46
+ File.expand_path(File.join(local_groonga_base_dir, "local"))
47
+ end
48
+
49
+ def have_local_groonga?(package_name, major, minor, micro)
50
+ return false unless File.exist?(File.join(local_groonga_install_dir, "lib"))
51
+
52
+ prepend_pkg_config_path_for_local_groonga
53
+ PKGConfig.have_package(package_name, major, minor, micro)
54
+ end
55
+
56
+ def prepend_pkg_config_path_for_local_groonga
57
+ pkg_config_dir = File.join(local_groonga_install_dir, "lib", "pkgconfig")
58
+ PackageConfig.prepend_default_path(pkg_config_dir)
59
+
60
+ lib_dir = File.join(local_groonga_install_dir, "lib")
61
+ original_LDFLAGS = $LDFLAGS
62
+ checking_for(checking_message("-Wl,-rpath is available")) do
63
+ $LDFLAGS += " -Wl,-rpath,#{Shellwords.escape(lib_dir)}"
64
+ available = try_compile("int main() {return 0;}")
65
+ $LDFLAGS = original_LDFLAGS unless available
66
+ available
67
+ end
68
+ end
39
69
 
40
70
  def install_groonga_locally(major, minor, micro)
41
71
  require 'open-uri'
42
72
  require 'shellwords'
43
73
 
44
74
  tar_gz = "groonga-#{major}.#{minor}.#{micro}.tar.gz"
45
- base_dir = File.join(File.dirname(__FILE__), "vendor")
46
- install_dir = File.expand_path(File.join(base_dir, "local"))
47
- FileUtils.mkdir_p(base_dir)
75
+ FileUtils.mkdir_p(local_groonga_base_dir)
48
76
 
49
- Dir.chdir(base_dir) do
77
+ Dir.chdir(local_groonga_base_dir) do
50
78
  url = "http://groonga.org/files/groonga/#{tar_gz}"
51
79
  message("downloading %s...", url)
52
80
  open(url, "rb") do |input|
@@ -69,7 +97,7 @@ def install_groonga_locally(major, minor, micro)
69
97
  groonga_source_dir = "groonga-#{major}.#{minor}.#{micro}"
70
98
  Dir.chdir(groonga_source_dir) do
71
99
  message("configuring...")
72
- if xsystem("./configure --prefix=#{Shellwords.escape(install_dir)}")
100
+ if xsystem("./configure CFLAGS='-g -O0' --prefix=#{Shellwords.escape(install_dir)}")
73
101
  message(" done\n")
74
102
  else
75
103
  message(" failed\n")
@@ -94,16 +122,14 @@ def install_groonga_locally(major, minor, micro)
94
122
  end
95
123
  end
96
124
 
97
- pkg_config_dir = File.join(install_dir, "lib", "pkgconfig")
98
- PackageConfig.prepend_default_path(pkg_config_dir)
99
-
100
- lib_dir = File.join(install_dir, "lib")
101
- $LDFLAGS += " -Wl,-rpath,#{Shellwords.escape(lib_dir)}"
125
+ prepend_pkg_config_path_for_local_groonga
102
126
  end
103
127
 
104
128
  unless PKGConfig.have_package(package_name, major, minor, micro)
105
- install_groonga_locally(major, minor, micro)
106
- PKGConfig.have_package(package_name, major, minor, micro) or exit 1
129
+ unless have_local_groonga?(package_name, major, minor, micro)
130
+ install_groonga_locally(major, minor, micro)
131
+ PKGConfig.have_package(package_name, major, minor, micro) or exit 1
132
+ end
107
133
  end
108
134
 
109
135
  real_version = PKGConfig.modversion(package_name)
data/html/index.html CHANGED
@@ -42,7 +42,7 @@
42
42
 
43
43
  <h3>Ruby/groongaの最新リリース</h3>
44
44
  <p>
45
- 2009-04-30にリリースされた0.0.1が最新です。
45
+ 2009-06-04にリリースされた0.0.2が最新です。
46
46
  </p>
47
47
 
48
48
  <h3 id="install-ruby-groonga">Ruby/groongaのインストール</h3>
@@ -79,7 +79,7 @@
79
79
 
80
80
  <h3>ActiveGroongaの最新リリース</h3>
81
81
  <p>
82
- 2009-04-30にリリースされた0.0.1が最新です。
82
+ 2009-06-05にリリースされた0.0.2が最新です。
83
83
  </p>
84
84
 
85
85
  <h3 id="install-active-groonga">ActiveGroongaのインストール</h3>
data/lib/groonga.rb CHANGED
@@ -15,7 +15,27 @@
15
15
  # License along with this library; if not, write to the Free Software
16
16
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
 
18
+ require 'pathname'
19
+
20
+ base_dir = Pathname.new(__FILE__).dirname.dirname
21
+ local_groonga_library_dir = base_dir + "vendor" + "local" + "lib"
22
+ if local_groonga_library_dir.exist?
23
+ prepend_path = Proc.new do |environment_name, separator|
24
+ paths = (ENV[environment_name] || '').split(/#{separator}/)
25
+ unless paths.include?(local_groonga_library_dir.to_s)
26
+ paths = [local_groonga_library_dir.to_s] + paths
27
+ ENV[environment_name] = paths.join(separator)
28
+ end
29
+ end
30
+
31
+ case RUBY_PLATFORM
32
+ when /mingw|mswin/
33
+ prepend_path.call("PATH", ";")
34
+ end
35
+ end
36
+
18
37
  require 'groonga/record'
38
+ require 'groonga/expression-builder'
19
39
  require 'groonga.so'
20
40
 
21
41
  ##
@@ -48,3 +68,5 @@ module Groonga
48
68
  end
49
69
  end
50
70
  end
71
+
72
+ require 'groonga/schema'
@@ -0,0 +1,141 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Groonga
19
+ module ExpressionBuildable
20
+ attr_accessor :builder, :expression, :variable
21
+ def initialize(*args)
22
+ @builder = self
23
+ @expression = nil
24
+ @variable = nil
25
+ @table = nil
26
+ @name = nil
27
+ @query = nil
28
+ @default_column = nil
29
+ end
30
+
31
+ def build
32
+ @expression = Expression.new(:table => @table,
33
+ :name => @name,
34
+ :query => @query,
35
+ :default_column => @default_column)
36
+ if block_given?
37
+ @variable = @expression.define_variable(:domain => @table)
38
+ @expression.append_object(@variable)
39
+ yield(self)
40
+ @expression.compile
41
+ end
42
+ @expression
43
+ end
44
+ end
45
+
46
+ class RecordExpressionBuilder
47
+ include ExpressionBuildable
48
+
49
+ def initialize(table, name)
50
+ super
51
+ @table = table
52
+ @name = name
53
+ end
54
+
55
+ def [](name)
56
+ column = @table.column(name)
57
+ if column.nil?
58
+ message = "unknown column <#{name.inspect}> " +
59
+ "for table <#{@table.inspect}>"
60
+ raise ArgumentError, message
61
+ end
62
+ builder = ColumnExpressionBuilder.new(column, nil, nil)
63
+ builder.builder = @builder
64
+ builder.expression = @expression
65
+ builder.variable = @variable
66
+ builder
67
+ end
68
+
69
+ def &(other)
70
+ @expression.append_operation(Groonga::Operation::AND, 2)
71
+ @builder
72
+ end
73
+ end
74
+
75
+ class ColumnExpressionBuilder
76
+ include ExpressionBuildable
77
+
78
+ def initialize(column, name, query)
79
+ super
80
+ @table = column.table
81
+ @column = column
82
+ @default_column = column.local_name
83
+ @name = name
84
+ @query = query
85
+ end
86
+
87
+ def ==(other)
88
+ @expression.append_object(@variable)
89
+ @expression.append_constant(@column.local_name)
90
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
91
+ @expression.append_constant(other)
92
+ @expression.append_operation(Groonga::Operation::EQUAL, 2)
93
+ @builder
94
+ end
95
+
96
+ def =~(other)
97
+ @expression.append_object(@variable)
98
+ @expression.append_constant(@column.local_name)
99
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
100
+ @expression.append_constant(other)
101
+ @expression.append_operation(Groonga::Operation::MATCH, 2)
102
+ @builder
103
+ end
104
+
105
+ def <(other)
106
+ @expression.append_object(@variable)
107
+ @expression.append_constant(@column.local_name)
108
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
109
+ @expression.append_constant(other)
110
+ @expression.append_operation(Groonga::Operation::LESS, 2)
111
+ @builder
112
+ end
113
+
114
+ def <=(other)
115
+ @expression.append_object(@variable)
116
+ @expression.append_constant(@column.local_name)
117
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
118
+ @expression.append_constant(other)
119
+ @expression.append_operation(Groonga::Operation::LESS_EQUAL, 2)
120
+ @builder
121
+ end
122
+
123
+ def >(other)
124
+ @expression.append_object(@variable)
125
+ @expression.append_constant(@column.local_name)
126
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
127
+ @expression.append_constant(other)
128
+ @expression.append_operation(Groonga::Operation::GREATER, 2)
129
+ @builder
130
+ end
131
+
132
+ def >=(other)
133
+ @expression.append_object(@variable)
134
+ @expression.append_constant(@column.local_name)
135
+ @expression.append_operation(Groonga::Operation::OBJECT_GET_VALUE, 2)
136
+ @expression.append_constant(other)
137
+ @expression.append_operation(Groonga::Operation::GREATER_EQUAL, 2)
138
+ @builder
139
+ end
140
+ end
141
+ end
@@ -34,7 +34,7 @@ module Groonga
34
34
  end
35
35
 
36
36
  def [](column_name)
37
- (column(column_name) || {})[@id]
37
+ column(column_name, true)[@id]
38
38
  end
39
39
 
40
40
  def []=(column_name, value)
@@ -73,6 +73,14 @@ module Groonga
73
73
  @table[@id] = value
74
74
  end
75
75
 
76
+ def increment!(name, delta=nil)
77
+ column(name, true).increment!(@id, delta)
78
+ end
79
+
80
+ def decrement!(name, delta=nil)
81
+ column(name, true).decrement!(@id, delta)
82
+ end
83
+
76
84
  def columns
77
85
  @table.columns
78
86
  end
@@ -91,6 +99,22 @@ module Groonga
91
99
  @table.delete(@id)
92
100
  end
93
101
 
102
+ def lock(options={}, &block)
103
+ @table.lock(options.merge(:id => @id), &block)
104
+ end
105
+
106
+ def unlock(options={})
107
+ @table.unlock(options.merge(:id => @id))
108
+ end
109
+
110
+ def clear_lock(options={})
111
+ @table.clear_lock(options.merge(:id => @id))
112
+ end
113
+
114
+ def locked?(options={})
115
+ @table.locked?(options.merge(:id => @id))
116
+ end
117
+
94
118
  private
95
119
  def column(name, required=false)
96
120
  _column = @table.column(name.to_s)
@@ -0,0 +1,418 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+
19
+ module Groonga
20
+
21
+ # groongaのスキーマ(データ構造)を管理するクラス。
22
+ class Schema
23
+ class << self
24
+
25
+ # call-seq:
26
+ # Groonga::Schema.define(options={}) {|schema| ...}
27
+ #
28
+ # スキーマを定義する。ブロックにはGroonga::Schemaオブ
29
+ # ジェクトがわたるので、そのオブジェクトを利用してスキー
30
+ # マを定義する。
31
+ #
32
+ # _options_に指定可能な値は以下の通り。
33
+ #
34
+ # [+:context+]
35
+ # スキーマ定義時に使用するGroonga::Contextを指定する。
36
+ # 省略した場合はGroonga::Context.defaultを使用する。
37
+ def define(options={})
38
+ schema = new(options)
39
+ yield(schema)
40
+ schema.define
41
+ end
42
+
43
+ # call-seq:
44
+ # Groonga::Schema.create_table(name, options={}) {|table| ...}
45
+ #
46
+ # 名前が_name_のテーブルを作成する。以下の省略形。
47
+ #
48
+ # Groonga::Schema.define do |schema|
49
+ # schema.create_table(name, options) do |table|
50
+ # ...
51
+ # end
52
+ # end
53
+ #
54
+ # ブロックにはGroonga::Schema::TableDefinitionオブジェ
55
+ # クトがわたるので、そのオブジェクトを利用してテーブル
56
+ # の詳細を定義する。
57
+ #
58
+ # _options_に指定可能な値は以下の通り。
59
+ #
60
+ # [+:context+]
61
+ # スキーマ定義時に使用するGroonga::Contextを指定する。
62
+ # 省略した場合はGroonga::Context.defaultを使用する。
63
+ #
64
+ # [+:path+]
65
+ # テーブルを保存するパスを指定する。パスを指定すると
66
+ # 永続テーブルになる。
67
+ #
68
+ # [+:persistent+]
69
+ # テーブルを永続テーブルとする。+:path:+を省略した場
70
+ # 合はパス名は自動的に作成される。デフォルトでは永続
71
+ # テーブルとなる。
72
+ #
73
+ # [+:value_size+]
74
+ # 値のサイズを指定する。デフォルトは0。
75
+ def create_table(name, options={}, &block)
76
+ define do |schema|
77
+ schema.create_table(name, options, &block)
78
+ end
79
+ end
80
+
81
+ # スキーマの内容を文字列で返す。返された値は
82
+ # Groonga::Schema#restoreすることによりスキーマ内に組
83
+ # み込むことができる。
84
+ #
85
+ # dump.rb:
86
+ # File.open("/tmp/groonga-schema.rb", "w") do |schema|
87
+ # dumped_text = Groonga::Schema.dump
88
+ # end
89
+ #
90
+ # restore.rb:
91
+ # dumped_text = Groonga::Schema.dump
92
+ # Groonga::Database.create(:path => "/tmp/new-db.grn")
93
+ # Groonga::Schema.define do |schema|
94
+ # schema.restore(dumped_text)
95
+ # end
96
+ #
97
+ # _options_に指定可能な値は以下の通り。
98
+ #
99
+ # [+:context+]
100
+ # スキーマ定義時に使用するGroonga::Contextを指定する。
101
+ # 省略した場合はGroonga::Context.defaultを使用する。
102
+ def dump(options={})
103
+ Dumper.new(options).dump
104
+ end
105
+
106
+ def normalize_type(type) # :nodoc:
107
+ return type if type.nil?
108
+ return type if type.is_a?(Groonga::Object)
109
+ case type.to_s
110
+ when "string"
111
+ "ShortText"
112
+ when "text"
113
+ "Text"
114
+ when "int", "integer"
115
+ "Int32"
116
+ when "float"
117
+ "Float"
118
+ when "decimal"
119
+ "Int64"
120
+ when "datetime", "timestamp", "time", "date"
121
+ "Time"
122
+ when "binary"
123
+ "LongText"
124
+ when "boolean"
125
+ "Bool"
126
+ else
127
+ type
128
+ end
129
+ end
130
+ end
131
+
132
+ # スキーマ定義を開始する。
133
+ #
134
+ # _options_に指定可能な値は以下の通り。
135
+ #
136
+ # [+:context+]
137
+ # スキーマ定義時に使用するGroonga::Contextを指定する。
138
+ # 省略した場合はGroonga::Context.defaultを使用する。
139
+ def initialize(options={})
140
+ @options = (options || {}).dup
141
+ @definitions = []
142
+ end
143
+
144
+ # 定義されたスキーマ定義を実際に実行する。
145
+ def define
146
+ @definitions.each do |definition|
147
+ definition.define
148
+ end
149
+ end
150
+
151
+ # Groonga::Schema.dumpで返されたスキーマの内容を読み込む。
152
+ #
153
+ # 読み込まれた内容は#defineを呼び出すまでは実行されない
154
+ # ことに注意すること。
155
+ def restore(dumped_text)
156
+ instance_eval(dumped_text)
157
+ end
158
+
159
+ # 名前が_name_のテーブルを作成する。
160
+ #
161
+ # 作成したテーブルは#defineを呼び出すまでは実行されない
162
+ # ことに注意すること。
163
+ #
164
+ # _options_に指定可能な値は以下の通り。
165
+ #
166
+ # [+:context+]
167
+ # スキーマ定義時に使用するGroonga::Contextを指定する。
168
+ # 省略した場合はGroonga::Schema.newで指定した
169
+ # Groonga::Contextを使用する。Groonga::Schema.newで指
170
+ # 定していない場合はGroonga::Context.defaultを使用する。
171
+ #
172
+ # [+:path+]
173
+ # テーブルを保存するパスを指定する。パスを指定すると
174
+ # 永続テーブルになる。
175
+ #
176
+ # [+:persistent+]
177
+ # テーブルを永続テーブルとする。+:path:+を省略した場
178
+ # 合はパス名は自動的に作成される。デフォルトでは永続
179
+ # テーブルとなる。
180
+ #
181
+ # [+:value_size+]
182
+ # 値のサイズを指定する。デフォルトは0。
183
+ def create_table(name, options={})
184
+ definition = TableDefinition.new(name, @options.merge(options || {}))
185
+ yield(definition)
186
+ @definitions << definition
187
+ end
188
+
189
+ class TableDefinition
190
+ def initialize(name, options)
191
+ @name = name
192
+ @name = @name.to_s if @name.is_a?(Symbol)
193
+ @columns = []
194
+ @options = options
195
+ @table_type = table_type
196
+ end
197
+
198
+ def define
199
+ table = @table_type.create(create_options)
200
+ @columns.each do |column|
201
+ column.define(table)
202
+ end
203
+ table
204
+ end
205
+
206
+ def column(name, type, options={})
207
+ column = self[name] || ColumnDefinition.new(name, options)
208
+ column.type = type
209
+ column.options.merge!(options)
210
+ @columns << column unless @columns.include?(column)
211
+ self
212
+ end
213
+
214
+ def integer32(name, options={})
215
+ column(name, "Int32", options)
216
+ end
217
+ alias_method :integer, :integer32
218
+ alias_method :int32, :integer32
219
+
220
+ def integer64(name, options={})
221
+ column(name, "Int64", options)
222
+ end
223
+ alias_method :int64, :integer64
224
+
225
+ def unsigned_integer32(name, options={})
226
+ column(name, "UInt32", options)
227
+ end
228
+ alias_method :unsigned_integer, :unsigned_integer32
229
+ alias_method :uint32, :unsigned_integer32
230
+
231
+ def unsigned_integer64(name, options={})
232
+ column(name, "UInt64", options)
233
+ end
234
+ alias_method :uint64, :unsigned_integer64
235
+
236
+ def float(name, options={})
237
+ column(name, "Float", options)
238
+ end
239
+
240
+ def time(name, options={})
241
+ column(name, "Time", options)
242
+ end
243
+
244
+ def short_text(name, options={})
245
+ column(name, "ShortText", options)
246
+ end
247
+ alias_method :string, :short_text
248
+
249
+ def text(name, options={})
250
+ column(name, "Text", options)
251
+ end
252
+
253
+ def long_text(name, options={})
254
+ column(name, "LongText", options)
255
+ end
256
+
257
+ def index(name, target_column, options={})
258
+ column = self[name] || IndexColumnDefinition.new(name, options)
259
+ column.target = target_column
260
+ column.options.merge!(options)
261
+ @columns << column unless @columns.include?(column)
262
+ self
263
+ end
264
+
265
+ def [](name)
266
+ @columns.find {|column| column.name == name}
267
+ end
268
+
269
+ private
270
+ def table_type
271
+ type = @options[:type]
272
+ case type
273
+ when :array, nil
274
+ Groonga::Array
275
+ when :hash
276
+ Groonga::Hash
277
+ when :patricia_trie
278
+ Groonga::PatriciaTrie
279
+ else
280
+ raise ArgumentError, "unknown table type: #{type.inspect}"
281
+ end
282
+ end
283
+
284
+ def create_options
285
+ common = {
286
+ :name => @name,
287
+ :path => @options[:path],
288
+ :persistent => persistent?,
289
+ :value_size => @options[:value_size],
290
+ :context => context,
291
+ }
292
+ key_support_table_common = {
293
+ :key_type => Schema.normalize_type(@options[:key_type]),
294
+ :default_tokenizer => @options[:default_tokenizer],
295
+ }
296
+
297
+ if @table_type == Groonga::Array
298
+ common
299
+ elsif @table_type == Groonga::Hash
300
+ common.merge(key_support_table_common)
301
+ elsif @table_type == Groonga::PatriciaTrie
302
+ options = {
303
+ :key_normalize => @options[:key_normalize],
304
+ :key_with_sis => @options[:key_with_sis],
305
+ }
306
+ common.merge(key_support_table_common).merge(options)
307
+ else
308
+ raise ArgumentError, "unknown table type: #{@table_type.inspect}"
309
+ end
310
+ end
311
+
312
+ def persistent?
313
+ @options[:persistent].nil? ? true : @options[:persistent]
314
+ end
315
+
316
+ def context
317
+ @options[:context] || Groonga::Context.default
318
+ end
319
+ end
320
+
321
+ class ColumnDefinition
322
+ attr_accessor :name, :type
323
+ attr_reader :options
324
+
325
+ def initialize(name, options={})
326
+ @name = name
327
+ @name = @name.to_s if @name.is_a?(Symbol)
328
+ @options = (options || {}).dup
329
+ @type = nil
330
+ end
331
+
332
+ def define(table)
333
+ table.define_column(@name,
334
+ Schema.normalize_type(@type),
335
+ @options)
336
+ end
337
+ end
338
+
339
+ class IndexColumnDefinition
340
+ attr_accessor :name, :target
341
+ attr_reader :options
342
+
343
+ def initialize(name, options={})
344
+ @name = name
345
+ @name = @name.to_s if @name.is_a?(Symbol)
346
+ @options = (options || {}).dup
347
+ @target = nil
348
+ end
349
+
350
+ def define(table)
351
+ target = @target
352
+ target = context[target] unless target.is_a?(Groonga::Object)
353
+ index = table.define_index_column(@name,
354
+ target.table,
355
+ @options)
356
+ index.source = target
357
+ index
358
+ end
359
+
360
+ private
361
+ def context
362
+ @options[:context] || Groonga::Context.default
363
+ end
364
+ end
365
+
366
+ class Dumper
367
+ def initialize(options={})
368
+ @options = (options || {}).dup
369
+ end
370
+
371
+ def dump
372
+ context = @options[:context] || Groonga::Context.default
373
+ database = context.database
374
+ return nil if database.nil?
375
+
376
+ schema = ""
377
+ database.each do |object|
378
+ next unless object.is_a?(Groonga::Table)
379
+ next if object.name == "<ranguba:objects>"
380
+ schema << "create_table(#{object.name.inspect}) do |table|\n"
381
+ object.columns.each do |column|
382
+ type = column_method(column)
383
+ name = column.local_name
384
+ schema << " table.#{type}(#{name.inspect})\n"
385
+ end
386
+ schema << "end\n"
387
+ end
388
+ schema
389
+ end
390
+
391
+ private
392
+ def column_method(column)
393
+ case column.range.name
394
+ when "Int32"
395
+ "integer32"
396
+ when "Int64"
397
+ "integer64"
398
+ when "UInt32"
399
+ "unsigned_integer32"
400
+ when "UInt64"
401
+ "unsigned_integer64"
402
+ when "Float"
403
+ "float"
404
+ when "Time"
405
+ "time"
406
+ when "ShortText"
407
+ "short_text"
408
+ when "Text"
409
+ "text"
410
+ when "LongText"
411
+ "long_text"
412
+ else
413
+ raise ArgumentError, "unsupported column: #{column.inspect}"
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end