groonga-schema 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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