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.
- data/NEWS.ja.rdoc +18 -3
- data/NEWS.rdoc +18 -3
- data/README.ja.rdoc +2 -0
- data/README.rdoc +2 -0
- data/Rakefile +14 -5
- data/TUTORIAL.ja.rdoc +82 -16
- data/benchmark/{read-write-small-many-items.rb → read-write-many-small-items.rb} +26 -23
- data/benchmark/{write-small-many-items.rb → write-many-small-items.rb} +26 -23
- data/example/bookmark.rb +49 -5
- data/ext/rb-grn-array.c +11 -1
- data/ext/rb-grn-column.c +132 -5
- data/ext/rb-grn-context.c +85 -80
- data/ext/rb-grn-database.c +182 -9
- data/ext/rb-grn-expression-builder.c +69 -0
- data/ext/rb-grn-expression.c +314 -0
- data/ext/rb-grn-fix-size-column.c +68 -89
- data/ext/rb-grn-hash.c +14 -5
- data/ext/rb-grn-index-column.c +14 -55
- data/ext/rb-grn-object.c +206 -75
- data/ext/rb-grn-operation.c +92 -0
- data/ext/rb-grn-patricia-trie.c +10 -32
- data/ext/rb-grn-query.c +9 -9
- data/ext/rb-grn-table-cursor.c +19 -80
- data/ext/rb-grn-table-key-support.c +33 -39
- data/ext/rb-grn-table.c +436 -79
- data/ext/rb-grn-type.c +10 -3
- data/ext/rb-grn-utils.c +131 -4
- data/ext/rb-grn-variable-size-column.c +36 -0
- data/ext/rb-grn-variable.c +90 -0
- data/ext/rb-grn.h +109 -56
- data/ext/rb-groonga.c +4 -0
- data/extconf.rb +39 -13
- data/html/index.html +2 -2
- data/lib/groonga.rb +22 -0
- data/lib/groonga/expression-builder.rb +141 -0
- data/lib/groonga/record.rb +25 -1
- data/lib/groonga/schema.rb +418 -0
- data/test/test-column.rb +11 -23
- data/test/test-context.rb +1 -1
- data/test/test-database.rb +60 -19
- data/test/test-expression-builder.rb +114 -0
- data/test/test-expression.rb +55 -0
- data/test/test-fix-size-column.rb +53 -0
- data/test/test-hash.rb +10 -3
- data/test/test-index-column.rb +24 -0
- data/test/test-patricia-trie.rb +9 -0
- data/test/test-procedure.rb +5 -5
- data/test/test-record.rb +71 -4
- data/test/test-schema.rb +207 -0
- data/test/test-table.rb +94 -12
- data/test/test-type.rb +18 -11
- data/test/test-variable-size-column.rb +53 -0
- data/test/test-variable.rb +28 -0
- 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,
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
106
|
-
|
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
|
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-
|
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
|
data/lib/groonga/record.rb
CHANGED
@@ -34,7 +34,7 @@ module Groonga
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def [](column_name)
|
37
|
-
|
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
|