groonga-schema 1.0.0

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.
@@ -0,0 +1,40 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "groonga/command"
18
+
19
+ module GroongaSchema
20
+ class Plugin
21
+ attr_reader :name
22
+ def initialize(name)
23
+ @name = name
24
+ end
25
+
26
+ def ==(other)
27
+ return false unless other.is_a?(self.class)
28
+
29
+ @name == other.name
30
+ end
31
+
32
+ def to_register_groonga_command
33
+ Groonga::Command::PluginRegister.new(:name => @name)
34
+ end
35
+
36
+ def to_unregister_groonga_command
37
+ Groonga::Command::PluginUnregister.new(:name => @name)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "groonga-schema/column"
18
+ require "groonga-schema/plugin"
19
+ require "groonga-schema/table"
20
+
21
+ module GroongaSchema
22
+ class Schema
23
+ attr_reader :plugins
24
+ attr_reader :tables
25
+ attr_reader :columns
26
+ def initialize
27
+ @plugins = []
28
+ @tables = {}
29
+ @columns = {}
30
+ end
31
+
32
+ def apply_command(command)
33
+ case command.command_name
34
+ when "register"
35
+ plugin = Plugin.new(command.path)
36
+ @plugins << plugin
37
+ when "plugin_register"
38
+ plugin = Plugin.new(command.name)
39
+ @plugins << plugin
40
+ when "table_create"
41
+ apply_command_table_create(command)
42
+ when "column_create"
43
+ apply_command_column_create(command)
44
+ end
45
+ end
46
+
47
+ private
48
+ def apply_command_table_create(command)
49
+ table = Table.new(command.name)
50
+ table.apply_command(command)
51
+ refered_table = @tables[table.key_type]
52
+ if refered_table
53
+ table.reference_key_type = true
54
+ refered_table.related_tables << table
55
+ end
56
+ @tables[table.name] = table
57
+ @columns[table.name] ||= {}
58
+ end
59
+
60
+ def apply_command_column_create(command)
61
+ column = Column.new(command.table, command.name)
62
+ column.apply_command(command)
63
+
64
+ table = @tables[column.table_name]
65
+ if table
66
+ table.columns << column
67
+ end
68
+
69
+ refered_table = @tables[column.value_type]
70
+ if refered_table
71
+ column.reference_value_type = true
72
+ refered_table.related_columns << column
73
+ refered_columns = @columns[column.value_type] || {}
74
+ column.sources.each do |source|
75
+ next if source == "_key"
76
+ source_column = refered_columns[source]
77
+ if source_column
78
+ source_column.related_columns << column
79
+ end
80
+ end
81
+ end
82
+
83
+ @columns[column.table_name] ||= {}
84
+ @columns[column.table_name][column.name] = column
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,258 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module GroongaSchema
18
+ class Table
19
+ attr_reader :name
20
+ attr_accessor :type
21
+ attr_accessor :flags
22
+ attr_accessor :key_type
23
+ attr_accessor :value_type
24
+ attr_accessor :default_tokenizer
25
+ attr_accessor :normalizer
26
+ attr_accessor :token_filters
27
+ attr_writer :reference_key_type
28
+ attr_accessor :columns
29
+ attr_accessor :related_tables
30
+ attr_accessor :related_columns
31
+ def initialize(name)
32
+ @name = name
33
+ @type = :no_key
34
+ @flags = []
35
+ @key_type = nil
36
+ @value_type = nil
37
+ @default_tokenizer = nil
38
+ @normalizer = nil
39
+ @token_filters = []
40
+ @reference_key_type = false
41
+ @columns = []
42
+ @related_tables = []
43
+ @related_columns = []
44
+ end
45
+
46
+ def reference_key_type?
47
+ @reference_key_type
48
+ end
49
+
50
+ def apply_command(command)
51
+ applier = CommandApplier.new(self, command)
52
+ applier.apply
53
+ end
54
+
55
+ def ==(other)
56
+ return false unless other.is_a?(self.class)
57
+
58
+ @name == other.name and
59
+ @type == other.type and
60
+ @flags.sort == other.flags.sort and
61
+ @key_type == other.key_type and
62
+ @value_type == other.value_type and
63
+ @default_tokenizer == other.default_tokenizer and
64
+ @normalizer == other.normalizer and
65
+ @token_filters == other.token_filters
66
+ end
67
+
68
+ def to_create_groonga_command
69
+ table_create_command(@name)
70
+ end
71
+
72
+ def to_remove_groonga_command
73
+ table_remove_command(@name)
74
+ end
75
+
76
+ def to_migrate_start_groonga_commands
77
+ commands = []
78
+ commands << table_create_command(new_name)
79
+ if @columns.empty?
80
+ commands << table_copy_command(@name, new_name)
81
+ else
82
+ sorted_columns = @columns.sort_by(&:name)
83
+ sorted_columns.each do |column|
84
+ next if column.type == :index
85
+ new_column = Column.new(new_name, column.name)
86
+ new_column.apply_column(column)
87
+ commands << new_column.to_create_groonga_command
88
+ commands << column.to_copy_groonga_command(new_name, column.name)
89
+ end
90
+ end
91
+ commands << table_rename_command(@name, old_name)
92
+ commands << table_rename_command(new_name, @name)
93
+ commands
94
+ end
95
+
96
+ def to_migrate_finish_groonga_commands
97
+ commands = []
98
+ sorted_columns = @columns.sort_by(&:name)
99
+ sorted_columns.each do |column|
100
+ next unless column.type == :index
101
+ commands << column.to_create_groonga_command
102
+ end
103
+ commands << table_remove_command(old_name)
104
+ commands
105
+ end
106
+
107
+ private
108
+ def old_name
109
+ "#{@name}_old"
110
+ end
111
+
112
+ def new_name
113
+ "#{@name}_new"
114
+ end
115
+
116
+ def table_create_command(name)
117
+ flags_value = [type_flag, *flags].join("|")
118
+ token_filters_value = @token_filters.join("|")
119
+ token_filters_value = nil if token_filters_value.empty?
120
+ arguments = {
121
+ "name" => name,
122
+ "flags" => flags_value,
123
+ "key_type" => @key_type,
124
+ "value_type" => @value_type,
125
+ "default_tokenizer" => @default_tokenizer,
126
+ "normalizer" => @normalizer,
127
+ "token_filters" => token_filters_value,
128
+ }
129
+ Groonga::Command::TableCreate.new(arguments)
130
+ end
131
+
132
+ def table_remove_command(name)
133
+ arguments = {
134
+ "name" => name,
135
+ }
136
+ Groonga::Command::TableRemove.new(arguments)
137
+ end
138
+
139
+ def table_copy_command(from_name, to_name)
140
+ arguments = {
141
+ "from_name" => from_name,
142
+ "to_name" => to_name,
143
+ }
144
+ Groonga::Command::TableCopy.new(arguments)
145
+ end
146
+
147
+ def table_rename_command(name, new_name)
148
+ arguments = {
149
+ "name" => name,
150
+ "new_name" => new_name,
151
+ }
152
+ Groonga::Command::TableRename.new(arguments)
153
+ end
154
+
155
+ def type_flag
156
+ case @type
157
+ when :no_key
158
+ "TABLE_NO_KEY"
159
+ when :hash_key
160
+ "TABLE_HASH_KEY"
161
+ when :pat_key
162
+ "TABLE_PAT_KEY"
163
+ when :dat_key
164
+ "TABLE_DAT_KEY"
165
+ else
166
+ "TABLE_HASH_KEY"
167
+ end
168
+ end
169
+
170
+ class CommandApplier
171
+ def initialize(table, command)
172
+ @table = table
173
+ @command = command
174
+ end
175
+
176
+ def apply
177
+ apply_flags
178
+ apply_key_type
179
+ apply_value_type
180
+ apply_default_tokenizer
181
+ apply_normalizer
182
+ apply_token_filters
183
+ end
184
+
185
+ private
186
+ def apply_flags
187
+ @type = :no_key
188
+ @flags = []
189
+ @command.flags.each do |flag|
190
+ parse_flag(flag)
191
+ end
192
+
193
+ @table.type = @type
194
+ @table.flags = @flags
195
+ end
196
+
197
+ def parse_flag(flag)
198
+ case flag
199
+ when "TABLE_NO_KEY"
200
+ @type = :no_key
201
+ when "TABLE_HASH_KEY"
202
+ @type = :hash_key
203
+ when "TABLE_PAT_KEY"
204
+ @type = :pat_key
205
+ when "TABLE_DAT_KEY"
206
+ @type = :dat_key
207
+ else
208
+ @flags << flag
209
+ end
210
+ end
211
+
212
+ def apply_key_type
213
+ case @type
214
+ when :no_key
215
+ @table.key_type = nil
216
+ else
217
+ @table.key_type = @command.key_type || "ShortText"
218
+ end
219
+ end
220
+
221
+ def apply_value_type
222
+ case @type
223
+ when :dat_key
224
+ @table.value_type = nil
225
+ else
226
+ @table.value_type = @command.value_type
227
+ end
228
+ end
229
+
230
+ def apply_default_tokenizer
231
+ case @type
232
+ when :no_key
233
+ @table.default_tokenizer = nil
234
+ else
235
+ @table.default_tokenizer = @command.default_tokenizer
236
+ end
237
+ end
238
+
239
+ def apply_normalizer
240
+ case @type
241
+ when :no_key
242
+ @table.normalizer = nil
243
+ else
244
+ @table.normalizer = @command.normalizer
245
+ end
246
+ end
247
+
248
+ def apply_token_filters
249
+ case @type
250
+ when :no_key
251
+ @table.token_filters = []
252
+ else
253
+ @table.token_filters = @command.token_filters
254
+ end
255
+ end
256
+ end
257
+ end
258
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module GroongaSchema
18
+ VERSION = "1.0.0"
19
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "groonga-schema/command-line/groonga-schema-diff"
18
+ require "groonga-schema/differ"
19
+ require "groonga-schema/schema"
20
+ require "groonga-schema/version"
data/test/run-test.rb ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2016 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 as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ $VERBOSE = true
20
+
21
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
22
+ lib_dir = File.join(base_dir, "lib")
23
+ test_dir = File.join(base_dir, "test")
24
+
25
+ $LOAD_PATH.unshift(lib_dir)
26
+
27
+ require "test-unit"
28
+
29
+ require "groonga-schema"
30
+ require "groonga/command"
31
+
32
+ exit(Test::Unit::AutoRunner.run(true, test_dir))
@@ -0,0 +1,52 @@
1
+ # Copyright (C) 2016 Kouhei Sutou <kou@clear-code.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ class ColumnTest < Test::Unit::TestCase
18
+ def column_create(arguments)
19
+ Groonga::Command::ColumnCreate.new(arguments)
20
+ end
21
+
22
+ sub_test_case "#apply_command" do
23
+ test "index" do
24
+ arguments = {
25
+ "table" => "Words",
26
+ "name" => "entries_text",
27
+ "flags" => "COLUMN_INDEX|WITH_POSITION|WITH_SECTION|INDEX_TINY",
28
+ "type" => "Entries",
29
+ "source" => "title, content",
30
+ }
31
+ command = column_create(arguments)
32
+ column = GroongaSchema::Column.new("Words", "entries_text")
33
+ column.apply_command(command)
34
+ assert_equal({
35
+ :table_name => "Words",
36
+ :name => "entries_text",
37
+ :type => :index,
38
+ :flags => ["WITH_POSITION", "WITH_SECTION", "INDEX_TINY"],
39
+ :value_type => "Entries",
40
+ :sources => ["title", "content"],
41
+ },
42
+ {
43
+ :table_name => column.table_name,
44
+ :name => column.name,
45
+ :type => column.type,
46
+ :flags => column.flags,
47
+ :value_type => column.value_type,
48
+ :sources => column.sources,
49
+ })
50
+ end
51
+ end
52
+ end