activegroonga 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/AUTHORS +1 -0
  2. data/NEWS.ja.rdoc +5 -0
  3. data/NEWS.rdoc +5 -0
  4. data/README.ja.rdoc +49 -0
  5. data/README.rdoc +49 -0
  6. data/Rakefile +175 -0
  7. data/lib/active_groonga.rb +75 -0
  8. data/lib/active_groonga/aggregations.rb +30 -0
  9. data/lib/active_groonga/associations.rb +93 -0
  10. data/lib/active_groonga/associations/belongs_to_association.rb +25 -0
  11. data/lib/active_groonga/attribute_methods.rb +36 -0
  12. data/lib/active_groonga/base.rb +1579 -0
  13. data/lib/active_groonga/column.rb +107 -0
  14. data/lib/active_groonga/dirty.rb +30 -0
  15. data/lib/active_groonga/fixtures.rb +92 -0
  16. data/lib/active_groonga/migration.rb +150 -0
  17. data/lib/active_groonga/rails_support.rb +31 -0
  18. data/lib/active_groonga/reflection.rb +30 -0
  19. data/lib/active_groonga/schema.rb +314 -0
  20. data/lib/active_groonga/schema_dumper.rb +147 -0
  21. data/lib/active_groonga/tasks.rb +16 -0
  22. data/lib/active_groonga/tasks/groonga.rake +162 -0
  23. data/lib/active_groonga/test_case.rb +21 -0
  24. data/lib/active_groonga/test_help.rb +21 -0
  25. data/lib/active_groonga/timestamp.rb +30 -0
  26. data/lib/active_groonga/validations.rb +26 -0
  27. data/lib/active_groonga/version.rb +24 -0
  28. data/license/LGPL +504 -0
  29. data/rails/README +28 -0
  30. data/rails/init.rb +70 -0
  31. data/rails_generators/model_groonga/USAGE +28 -0
  32. data/rails_generators/model_groonga/model_groonga_generator.rb +45 -0
  33. data/rails_generators/model_groonga/templates/fixtures.yml +17 -0
  34. data/rails_generators/model_groonga/templates/migration.rb +16 -0
  35. data/rails_generators/model_groonga/templates/model.rb +2 -0
  36. data/rails_generators/model_groonga/templates/unit_test.rb +8 -0
  37. data/test-unit/Rakefile +35 -0
  38. data/test-unit/TODO +5 -0
  39. data/test-unit/bin/testrb +5 -0
  40. data/test-unit/html/classic.html +15 -0
  41. data/test-unit/html/index.html +25 -0
  42. data/test-unit/html/index.html.ja +27 -0
  43. data/test-unit/lib/test/unit.rb +342 -0
  44. data/test-unit/lib/test/unit/assertionfailederror.rb +14 -0
  45. data/test-unit/lib/test/unit/assertions.rb +1149 -0
  46. data/test-unit/lib/test/unit/attribute.rb +125 -0
  47. data/test-unit/lib/test/unit/autorunner.rb +306 -0
  48. data/test-unit/lib/test/unit/collector.rb +43 -0
  49. data/test-unit/lib/test/unit/collector/descendant.rb +23 -0
  50. data/test-unit/lib/test/unit/collector/dir.rb +108 -0
  51. data/test-unit/lib/test/unit/collector/load.rb +135 -0
  52. data/test-unit/lib/test/unit/collector/objectspace.rb +34 -0
  53. data/test-unit/lib/test/unit/color-scheme.rb +86 -0
  54. data/test-unit/lib/test/unit/color.rb +96 -0
  55. data/test-unit/lib/test/unit/diff.rb +538 -0
  56. data/test-unit/lib/test/unit/error.rb +124 -0
  57. data/test-unit/lib/test/unit/exceptionhandler.rb +39 -0
  58. data/test-unit/lib/test/unit/failure.rb +110 -0
  59. data/test-unit/lib/test/unit/fixture.rb +176 -0
  60. data/test-unit/lib/test/unit/notification.rb +125 -0
  61. data/test-unit/lib/test/unit/omission.rb +143 -0
  62. data/test-unit/lib/test/unit/pending.rb +146 -0
  63. data/test-unit/lib/test/unit/priority.rb +161 -0
  64. data/test-unit/lib/test/unit/runner/console.rb +52 -0
  65. data/test-unit/lib/test/unit/runner/emacs.rb +8 -0
  66. data/test-unit/lib/test/unit/testcase.rb +360 -0
  67. data/test-unit/lib/test/unit/testresult.rb +89 -0
  68. data/test-unit/lib/test/unit/testsuite.rb +110 -0
  69. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +14 -0
  70. data/test-unit/lib/test/unit/ui/console/testrunner.rb +220 -0
  71. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +49 -0
  72. data/test-unit/lib/test/unit/ui/testrunner.rb +20 -0
  73. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +77 -0
  74. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +41 -0
  75. data/test-unit/lib/test/unit/util/backtracefilter.rb +41 -0
  76. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  77. data/test-unit/lib/test/unit/util/observable.rb +90 -0
  78. data/test-unit/lib/test/unit/util/procwrapper.rb +48 -0
  79. data/test-unit/lib/test/unit/version.rb +7 -0
  80. data/test-unit/sample/adder.rb +13 -0
  81. data/test-unit/sample/subtracter.rb +12 -0
  82. data/test-unit/sample/tc_adder.rb +18 -0
  83. data/test-unit/sample/tc_subtracter.rb +18 -0
  84. data/test-unit/sample/test_user.rb +22 -0
  85. data/test-unit/sample/ts_examples.rb +7 -0
  86. data/test-unit/test/collector/test-descendant.rb +135 -0
  87. data/test-unit/test/collector/test-load.rb +333 -0
  88. data/test-unit/test/collector/test_dir.rb +406 -0
  89. data/test-unit/test/collector/test_objectspace.rb +98 -0
  90. data/test-unit/test/run-test.rb +13 -0
  91. data/test-unit/test/test-attribute.rb +86 -0
  92. data/test-unit/test/test-color-scheme.rb +56 -0
  93. data/test-unit/test/test-color.rb +47 -0
  94. data/test-unit/test/test-diff.rb +477 -0
  95. data/test-unit/test/test-emacs-runner.rb +60 -0
  96. data/test-unit/test/test-fixture.rb +287 -0
  97. data/test-unit/test/test-notification.rb +33 -0
  98. data/test-unit/test/test-omission.rb +81 -0
  99. data/test-unit/test/test-pending.rb +70 -0
  100. data/test-unit/test/test-priority.rb +119 -0
  101. data/test-unit/test/test_assertions.rb +1082 -0
  102. data/test-unit/test/test_error.rb +26 -0
  103. data/test-unit/test/test_failure.rb +33 -0
  104. data/test-unit/test/test_testcase.rb +478 -0
  105. data/test-unit/test/test_testresult.rb +113 -0
  106. data/test-unit/test/test_testsuite.rb +129 -0
  107. data/test-unit/test/testunit-test-util.rb +14 -0
  108. data/test-unit/test/ui/test_testrunmediator.rb +20 -0
  109. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  110. data/test-unit/test/util/test_backtracefilter.rb +41 -0
  111. data/test-unit/test/util/test_observable.rb +102 -0
  112. data/test-unit/test/util/test_procwrapper.rb +36 -0
  113. data/test/active-groonga-test-utils.rb +234 -0
  114. data/test/fixtures/bookmark.rb +2 -0
  115. data/test/fixtures/task.rb +2 -0
  116. data/test/fixtures/user.rb +2 -0
  117. data/test/run-test.rb +51 -0
  118. data/test/test-associations.rb +24 -0
  119. data/test/test-base.rb +194 -0
  120. data/test/test-schema.rb +49 -0
  121. metadata +192 -0
@@ -0,0 +1,314 @@
1
+ # Copyright (C) 2009 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 version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ module ActiveGroonga
17
+ module Schema
18
+ class << self
19
+ def define(info={}, &block)
20
+ initialize_schema_management_tables
21
+ instance_eval(&block)
22
+
23
+ unless info[:version].blank?
24
+ assume_migrated_upto_version(info[:version])
25
+ end
26
+ end
27
+
28
+ def assume_migrated_upto_version(version)
29
+ version = version.to_i
30
+ table_name = Migrator.groonga_schema_migrations_table_name
31
+
32
+ migrations_table = Base.context[table_name]
33
+ migrated = migrations_table.records.collect do |record|
34
+ record["version"].to_i
35
+ end
36
+ versions = Dir['db/migrate/[0-9]*_*.rb'].map do |filename|
37
+ filename.split('/').last.split('_').first.to_i
38
+ end
39
+
40
+ unless migrated.include?(version)
41
+ migrations_table.add(version.to_s)
42
+ end
43
+
44
+ inserted = Set.new
45
+ (versions - migrated).each do |v|
46
+ if inserted.include?(v)
47
+ raise "Duplicate migration #{v}. Please renumber your migrations to resolve the conflict."
48
+ elsif v < version
49
+ migration = migrations_table.add
50
+ migration["version"] = v.to_s
51
+ inserted << v
52
+ end
53
+ end
54
+ end
55
+
56
+ def initialize_schema_management_tables
57
+ initialize_index_management_table
58
+ initialize_index_table
59
+ initialize_migrations_table
60
+ end
61
+
62
+ def create_table(name, options={})
63
+ table_definition = TableDefinition.new(name)
64
+ yield(table_definition)
65
+ table_definition.create
66
+ end
67
+
68
+ def drop_table(name, options={})
69
+ table = Base.context[Base.groonga_table_name(name)]
70
+ table_id = table.id
71
+ table.remove
72
+ index_management_table.open_cursor do |cursor|
73
+ while cursor.next
74
+ cursor.delete if cursor.table_id == table_id
75
+ end
76
+ end
77
+ end
78
+
79
+ def add_column(table_name, column_name, type, options={})
80
+ column = ColumnDefinition.new(table_name, column_name)
81
+ if type.to_s == "references"
82
+ table = options.delete(:to) || column_name.pluralize
83
+ column.type = Base.groonga_table_name(table)
84
+ else
85
+ column.type = type
86
+ end
87
+ column.create(options)
88
+ end
89
+
90
+ def remove_column(table_name, *column_names)
91
+ column_names.each do |column_name|
92
+ ColumnDefinition.new(table_name, column_name).remove
93
+ end
94
+ end
95
+
96
+ def add_index(table_name, column_name, options={})
97
+ groonga_table_name = Base.groonga_table_name(table_name)
98
+ table = Base.context[groonga_table_name]
99
+ column_name = column_name.to_s
100
+ column = table.column(column_name)
101
+
102
+ base_dir = File.join(Base.metadata_directory,
103
+ index_table_name,
104
+ table_name)
105
+ FileUtils.mkdir_p(base_dir)
106
+
107
+ name = "#{table_name}/#{column_name}"
108
+ path = File.join(base_dir, "#{column_name}.groonga")
109
+ index_column = index_table.define_column(name, table,
110
+ :path => path,
111
+ :type => "index",
112
+ :compress => "zlib",
113
+ # :with_section => true,
114
+ # :with_weight => true,
115
+ :with_position => true)
116
+ index_column.source = column
117
+
118
+ record = index_management_table.add
119
+ record["table"] = groonga_table_name
120
+ record["column"] = column_name
121
+ record["index"] = name
122
+ end
123
+
124
+ def index_management_table
125
+ Base.context[groonga_index_management_table_name]
126
+ end
127
+
128
+ def index_table
129
+ Base.context[groonga_index_table_name]
130
+ end
131
+
132
+ def indexes(table_or_table_name)
133
+ if table_or_table_name.is_a?(String)
134
+ table_name = table_or_table_name
135
+ table = Base.context[Base.groonga_table_name(table_name)]
136
+ else
137
+ table = table_or_table_name
138
+ table_name = table.name.gsub(/(?:\A<table:|>\z)/, '')
139
+ end
140
+ indexes = []
141
+ index_management_table.records.each do |record|
142
+ next if record["table"] != table.name
143
+ indexes << IndexDefinition.new(table_name, record["index"],
144
+ false, record["column"])
145
+ end
146
+ indexes
147
+ end
148
+
149
+ private
150
+ def index_management_table_name
151
+ Base.table_name_prefix + 'indexes' + Base.table_name_suffix
152
+ end
153
+
154
+ def groonga_index_management_table_name
155
+ Base.groonga_metadata_table_name(index_management_table_name)
156
+ end
157
+
158
+ def index_table_name
159
+ Base.table_name_prefix + 'index' + Base.table_name_suffix
160
+ end
161
+
162
+ def groonga_index_table_name
163
+ Base.groonga_metadata_table_name(index_table_name)
164
+ end
165
+
166
+ def initialize_index_management_table
167
+ table_name = index_management_table_name
168
+ groonga_table_name = groonga_index_management_table_name
169
+ if Base.context[groonga_table_name].nil?
170
+ table_file = File.join(Base.metadata_directory,
171
+ "#{table_name}.groonga")
172
+ table = Groonga::Array.create(:name => groonga_table_name,
173
+ :path => table_file)
174
+
175
+ base_dir = File.join(Base.metadata_directory, table_name)
176
+ FileUtils.mkdir_p(base_dir)
177
+
178
+ column_file = File.join(base_dir, "table.groonga")
179
+ table.define_column("table", "<shorttext>", :path => column_file)
180
+
181
+ column_file = File.join(base_dir, "column.groonga")
182
+ table.define_column("column", "<shorttext>", :path => column_file)
183
+
184
+ column_file = File.join(base_dir, "index.groonga")
185
+ table.define_column("index", "<shorttext>", :path => column_file)
186
+ end
187
+ end
188
+
189
+ def initialize_index_table
190
+ table_name = index_table_name
191
+ groonga_table_name = groonga_index_table_name
192
+ if Base.context[groonga_table_name].nil?
193
+ table_file = File.join(Base.metadata_directory,
194
+ "#{table_name}.groonga")
195
+ table = Groonga::PatriciaTrie.create(:name => groonga_table_name,
196
+ :key_type => "<shorttext>",
197
+ # :key_with_sis => true,
198
+ # :key_normalize => true,
199
+ :path => table_file)
200
+
201
+ base_dir = File.join(Base.metadata_directory, table_name)
202
+ FileUtils.mkdir_p(base_dir)
203
+ end
204
+ end
205
+
206
+ def initialize_migrations_table
207
+ table_name = Migrator.schema_migrations_table_name
208
+ groonga_table_name = Migrator.groonga_schema_migrations_table_name
209
+ if Base.context[groonga_table_name].nil?
210
+ table_file = File.join(Base.metadata_directory,
211
+ "#{table_name}.groonga")
212
+ Groonga::Hash.create(:name => groonga_table_name,
213
+ :path => table_file,
214
+ :key_type => "<shorttext>")
215
+ end
216
+ end
217
+ end
218
+
219
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
220
+ undef_method :primary_key, :to_sql, :native
221
+
222
+ def initialize(name)
223
+ super(nil)
224
+ @name = name
225
+ @indexes = []
226
+ end
227
+
228
+ def create
229
+ table_file = File.join(Base.tables_directory, "#{@name}.groonga")
230
+ Groonga::Array.create(:name => Base.groonga_table_name(@name),
231
+ :path => table_file)
232
+ @columns.each(&:create)
233
+ @indexes.each do |column_name, options|
234
+ Schema.add_index(@name.to_s, column_name, options)
235
+ end
236
+ end
237
+
238
+ def column(name, type, options={})
239
+ column = self[name] || ColumnDefinition.new(@name, name)
240
+ column.type = type
241
+ @columns << column unless @columns.include?(column)
242
+ self
243
+ end
244
+
245
+ def index(column_name, options={})
246
+ @indexes << [column_name.to_s, options]
247
+ end
248
+
249
+ def references(*args)
250
+ options = args.extract_options!
251
+ args.each do |col|
252
+ groonga_table_name = Base.groonga_table_name(col.to_s.pluralize)
253
+ table = Base.context[groonga_table_name]
254
+ column(col, table, options)
255
+ end
256
+ end
257
+ alias :belongs_to :references
258
+ end
259
+
260
+ class ColumnDefinition
261
+ attr_accessor :name, :type
262
+
263
+ def initialize(table_name, name)
264
+ @table_name = table_name
265
+ @name = name
266
+ @name = @name.to_s if @name.is_a?(Symbol)
267
+ @type = nil
268
+ end
269
+
270
+ def create(options={})
271
+ column_file = File.join(Base.columns_directory(@table_name),
272
+ "#{@name}.groonga")
273
+ options = options.merge(:path => column_file)
274
+ table = Base.context[Base.groonga_table_name(@table_name)]
275
+ table.define_column(@name,
276
+ normalize_type(@type),
277
+ options)
278
+ end
279
+
280
+ def remove
281
+ Base.context[@name].remove
282
+ end
283
+
284
+ def normalize_type(type)
285
+ return type if type.is_a?(Groonga::Object)
286
+ case type.to_s
287
+ when "string"
288
+ "<shorttext>"
289
+ when "text"
290
+ "<text>"
291
+ when "integer"
292
+ "<int>"
293
+ when "float"
294
+ "<float>"
295
+ when "decimal"
296
+ "<int64>"
297
+ when "datetime", "timestamp", "time", "date"
298
+ "<time>"
299
+ when "binary"
300
+ "<longtext>"
301
+ when "boolean"
302
+ "<int>"
303
+ else
304
+ type
305
+ end
306
+ end
307
+ end
308
+
309
+ class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
310
+ alias_method :column, :columns
311
+ alias_method :column=, :columns=
312
+ end
313
+ end
314
+ end
@@ -0,0 +1,147 @@
1
+ # Copyright (C) 2009 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 version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ module ActiveGroonga
17
+ class SchemaDumper < ActiveRecord::SchemaDumper
18
+ class << self
19
+ def dump(stream=STDOUT)
20
+ new.dump(StreamWrapper.new(stream))
21
+ stream
22
+ end
23
+ end
24
+
25
+ def initialize
26
+ @version = Migrator.current_version
27
+ end
28
+
29
+ def dump(stream)
30
+ @references = []
31
+ header(stream)
32
+ dump_tables(stream)
33
+ dump_references(stream)
34
+ trailer(stream)
35
+ stream
36
+ end
37
+
38
+ private
39
+ def dump_tables(stream)
40
+ tables.sort.each do |name|
41
+ next if ignore_tables.any? {|ignored| ignored === name}
42
+ dump_table(name, stream)
43
+ end
44
+ end
45
+
46
+ def tables
47
+ Dir[File.join(Base.tables_directory, "*.groonga")].collect do |path|
48
+ File.basename(path, ".groonga")
49
+ end
50
+ end
51
+
52
+ def dump_table(name, stream)
53
+ begin
54
+ table_schema = StringIO.new
55
+ table_schema.puts " create_table #{name.inspect}, :force => true do |t|"
56
+ column_specs = []
57
+ columns(name).each do |column|
58
+ if column.reference_type?
59
+ @references << [name, column]
60
+ next
61
+ end
62
+
63
+ spec = {}
64
+ spec[:type] = column.type.to_s
65
+ spec[:name] = column.name.inspect
66
+ column_specs << spec
67
+ end
68
+
69
+ column_specs.each do |spec|
70
+ table_schema.print(" t.#{spec[:type]} #{spec[:name]}")
71
+ table_schema.puts
72
+ end
73
+
74
+ table_schema.puts " end"
75
+ table_schema.puts
76
+
77
+ dump_indexes(name, table_schema)
78
+
79
+ stream.print table_schema.string
80
+ rescue => e
81
+ stream.puts "# Could not dump table #{name.inspect} because of following #{e.class}"
82
+ stream.puts "# #{e.message}"
83
+ e.backtrace.each do |trace|
84
+ stream.puts "# #{trace}"
85
+ end
86
+ stream.puts
87
+ end
88
+
89
+ stream
90
+ end
91
+
92
+ def dump_indexes(table, stream)
93
+ _indexes = indexes(table)
94
+ return if _indexes.empty?
95
+
96
+ add_index_statements = _indexes.collect do |index|
97
+ statement_parts = []
98
+ statement_parts << "add_index #{index.table.inspect}"
99
+ statement_parts << index.columns.inspect
100
+ statement_parts << ":name => #{index.name.inspect}"
101
+ ' ' + statement_parts.join(', ')
102
+ end
103
+
104
+ stream.puts add_index_statements.sort.join("\n")
105
+ stream.puts
106
+ end
107
+
108
+ def dump_references(stream)
109
+ @references.sort_by do |name, column|
110
+ [name, column.name]
111
+ end.each do |name, column|
112
+ statement = " add_column #{name.inspect}, "
113
+ statement << "#{column.name.inspect}, :references, "
114
+ statement << ":to => #{column.reference_object_name.inspect}"
115
+ stream.puts(statement)
116
+ end
117
+ end
118
+
119
+ def columns(table_name)
120
+ table_name = Base.groonga_table_name(table_name)
121
+ Base.context[table_name].columns.collect {|column| Column.new(column)}
122
+ end
123
+
124
+ def indexes(table_name)
125
+ Schema.indexes(table_name)
126
+ end
127
+
128
+ class StreamWrapper
129
+ def initialize(stream)
130
+ @stream = stream
131
+ end
132
+
133
+ def method_missing(name, *args, &block)
134
+ @stream.send(name, *args.collect {|arg| normalize_string(arg)}, &block)
135
+ end
136
+
137
+ private
138
+ def normalize_string(string)
139
+ if string.is_a?(String)
140
+ string.gsub(/Active ?Record/, "ActiveGroonga")
141
+ else
142
+ string
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end