activegroonga 0.0.2 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS.ja.rdoc +4 -0
- data/NEWS.rdoc +4 -0
- data/README.ja.rdoc +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +3 -4
- data/lib/active_groonga.rb +2 -0
- data/lib/active_groonga/base.rb +125 -99
- data/lib/active_groonga/column.rb +9 -0
- data/lib/active_groonga/dynamic_record_expression_builder.rb +40 -0
- data/lib/active_groonga/schema.rb +107 -204
- data/lib/active_groonga/schema_dumper.rb +40 -25
- data/lib/active_groonga/tasks/groonga.rake +2 -0
- data/lib/active_groonga/version.rb +1 -1
- data/rails_generators/index_table_groonga/USAGE +23 -0
- data/rails_generators/index_table_groonga/index_table_groonga_generator.rb +44 -0
- data/rails_generators/index_table_groonga/templates/migration.rb +12 -0
- data/rails_generators/migration_groonga/USAGE +29 -0
- data/rails_generators/migration_groonga/migration_groonga_generator.rb +19 -0
- data/rails_generators/migration_groonga/templates/migration.rb +11 -0
- data/test-unit/Rakefile +6 -1
- data/test-unit/lib/test/unit/autorunner.rb +26 -3
- data/test-unit/lib/test/unit/priority.rb +21 -1
- data/test-unit/lib/test/unit/testcase.rb +101 -36
- data/test-unit/lib/test/unit/ui/console/testrunner.rb +7 -4
- data/test-unit/test/{test_testcase.rb → test-testcase.rb} +30 -1
- data/test-unit/test/test_assertions.rb +1 -1
- data/test/active-groonga-test-utils.rb +25 -26
- data/test/test-base.rb +16 -6
- data/test/test-schema-dumper.rb +48 -0
- data/test/test-schema.rb +20 -4
- data/test/tmp/database/database.groonga +0 -0
- data/test/tmp/database/database.groonga.0000000 +0 -0
- data/test/tmp/database/database.groonga.0000100 +0 -0
- data/test/tmp/database/database.groonga.0000101 +0 -0
- metadata +19 -7
@@ -60,6 +60,14 @@ module ActiveGroonga
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
def index?
|
64
|
+
@type == :index
|
65
|
+
end
|
66
|
+
|
67
|
+
def index_sources
|
68
|
+
@column.sources
|
69
|
+
end
|
70
|
+
|
63
71
|
def reference_type?
|
64
72
|
@type == :references
|
65
73
|
end
|
@@ -77,6 +85,7 @@ module ActiveGroonga
|
|
77
85
|
|
78
86
|
private
|
79
87
|
def detect_type
|
88
|
+
return :index if @column.is_a?(Groonga::IndexColumn)
|
80
89
|
case @column.range
|
81
90
|
when Groonga::Type
|
82
91
|
case @column.range.id
|
@@ -0,0 +1,40 @@
|
|
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 DynamicRecordExpressionBuilder
|
18
|
+
# Instantiates a new dynamic record expression builder.
|
19
|
+
#
|
20
|
+
# +record+ is a Groonga::RecordExpressionBuilder.
|
21
|
+
def initialize(record)
|
22
|
+
@record = record
|
23
|
+
define_column_readers
|
24
|
+
end
|
25
|
+
|
26
|
+
def [](name)
|
27
|
+
@record[name]
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def define_column_readers
|
32
|
+
singleton_class = class << self; self; end
|
33
|
+
@record.table.columns.each do |column|
|
34
|
+
singleton_class.send(:define_method, column.local_name) do ||
|
35
|
+
self[column.local_name]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -54,155 +54,54 @@ module ActiveGroonga
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def initialize_schema_management_tables
|
57
|
-
initialize_index_management_table
|
58
|
-
initialize_index_table
|
59
57
|
initialize_migrations_table
|
60
58
|
end
|
61
59
|
|
62
|
-
def create_table(name, options={})
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
def create_table(name, options={}, &block)
|
61
|
+
table_file = File.join(Base.tables_directory, "#{name}.groonga")
|
62
|
+
table_name = Base.groonga_table_name(name)
|
63
|
+
options = {:path => table_file}.merge(options)
|
64
|
+
options = default_table_options(options).merge(options)
|
65
|
+
options = options.merge(:context => Base.context)
|
66
|
+
Groonga::Schema.create_table(table_name, options) do |table|
|
67
|
+
block.call(TableDefinitionWrapper.new(table))
|
68
|
+
end
|
66
69
|
end
|
67
70
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
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
|
71
|
+
def remove_table(name, options={})
|
72
|
+
options = options.merge(:context => Base.context)
|
73
|
+
Groonga::Schema.remove_table(name, options)
|
77
74
|
end
|
75
|
+
alias_method :drop_table, :remove_table
|
78
76
|
|
79
77
|
def add_column(table_name, column_name, type, options={})
|
80
|
-
|
81
|
-
|
82
|
-
table =
|
83
|
-
column
|
84
|
-
else
|
85
|
-
column.type = type
|
78
|
+
options_with_context = options.merge(:context => Base.context)
|
79
|
+
Groonga::Schema.change_table(table_name, options_with_context) do |table|
|
80
|
+
table = TableDefinitionWrapper.new(table)
|
81
|
+
table.column(column_name, type, options)
|
86
82
|
end
|
87
|
-
column.create(options)
|
88
83
|
end
|
89
84
|
|
90
85
|
def remove_column(table_name, *column_names)
|
91
|
-
|
92
|
-
|
86
|
+
options_with_context = options.merge(:context => Base.context)
|
87
|
+
Groonga::Schema.change_table(table_name, options_with_context) do |table|
|
88
|
+
column_names.each do |column_name|
|
89
|
+
table.remove_column(column_name)
|
90
|
+
end
|
93
91
|
end
|
94
92
|
end
|
95
93
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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_index_column(name, table,
|
110
|
-
:path => path,
|
111
|
-
:compress => "zlib",
|
112
|
-
# :with_section => true,
|
113
|
-
# :with_weight => true,
|
114
|
-
:with_position => true)
|
115
|
-
index_column.source = column
|
116
|
-
|
117
|
-
record = index_management_table.add
|
118
|
-
record["table"] = groonga_table_name
|
119
|
-
record["column"] = column_name
|
120
|
-
record["index"] = name
|
121
|
-
end
|
122
|
-
|
123
|
-
def index_management_table
|
124
|
-
Base.context[groonga_index_management_table_name]
|
125
|
-
end
|
126
|
-
|
127
|
-
def index_table
|
128
|
-
Base.context[groonga_index_table_name]
|
129
|
-
end
|
130
|
-
|
131
|
-
def indexes(table_or_table_name)
|
132
|
-
if table_or_table_name.is_a?(String)
|
133
|
-
table_name = table_or_table_name
|
134
|
-
table = Base.context[Base.groonga_table_name(table_name)]
|
135
|
-
else
|
136
|
-
table = table_or_table_name
|
137
|
-
table_name = table.name.gsub(/(?:\A<table:|>\z)/, '')
|
138
|
-
end
|
139
|
-
indexes = []
|
140
|
-
index_management_table.records.each do |record|
|
141
|
-
next if record["table"] != table.name
|
142
|
-
indexes << IndexDefinition.new(table_name, record["index"],
|
143
|
-
false, record["column"])
|
94
|
+
def add_index_column(table_name, target_table_name, target_column_name,
|
95
|
+
options={})
|
96
|
+
options_for_table = options.reject {|key, value| key == :name}
|
97
|
+
options_for_table = options_for_table.merge(:context => Base.context)
|
98
|
+
Groonga::Schema.change_table(table_name, options_for_table) do |table|
|
99
|
+
table = TableDefinitionWrapper.new(table)
|
100
|
+
table.index(target_table_name, target_column_name, options)
|
144
101
|
end
|
145
|
-
indexes
|
146
102
|
end
|
147
103
|
|
148
104
|
private
|
149
|
-
def index_management_table_name
|
150
|
-
Base.table_name_prefix + 'indexes' + Base.table_name_suffix
|
151
|
-
end
|
152
|
-
|
153
|
-
def groonga_index_management_table_name
|
154
|
-
Base.groonga_metadata_table_name(index_management_table_name)
|
155
|
-
end
|
156
|
-
|
157
|
-
def index_table_name
|
158
|
-
Base.table_name_prefix + 'index' + Base.table_name_suffix
|
159
|
-
end
|
160
|
-
|
161
|
-
def groonga_index_table_name
|
162
|
-
Base.groonga_metadata_table_name(index_table_name)
|
163
|
-
end
|
164
|
-
|
165
|
-
def initialize_index_management_table
|
166
|
-
table_name = index_management_table_name
|
167
|
-
groonga_table_name = groonga_index_management_table_name
|
168
|
-
if Base.context[groonga_table_name].nil?
|
169
|
-
table_file = File.join(Base.metadata_directory,
|
170
|
-
"#{table_name}.groonga")
|
171
|
-
table = Groonga::Array.create(:name => groonga_table_name,
|
172
|
-
:path => table_file)
|
173
|
-
|
174
|
-
base_dir = File.join(Base.metadata_directory, table_name)
|
175
|
-
FileUtils.mkdir_p(base_dir)
|
176
|
-
|
177
|
-
column_file = File.join(base_dir, "table.groonga")
|
178
|
-
table.define_column("table", "<shorttext>", :path => column_file)
|
179
|
-
|
180
|
-
column_file = File.join(base_dir, "column.groonga")
|
181
|
-
table.define_column("column", "<shorttext>", :path => column_file)
|
182
|
-
|
183
|
-
column_file = File.join(base_dir, "index.groonga")
|
184
|
-
table.define_column("index", "<shorttext>", :path => column_file)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def initialize_index_table
|
189
|
-
table_name = index_table_name
|
190
|
-
groonga_table_name = groonga_index_table_name
|
191
|
-
if Base.context[groonga_table_name].nil?
|
192
|
-
table_file = File.join(Base.metadata_directory,
|
193
|
-
"#{table_name}.groonga")
|
194
|
-
table = Groonga::PatriciaTrie.create(:name => groonga_table_name,
|
195
|
-
:key_type => "<shorttext>",
|
196
|
-
# :key_with_sis => true,
|
197
|
-
# :key_normalize => true,
|
198
|
-
:path => table_file)
|
199
|
-
table.default_tokenizer = "<token:bigram>"
|
200
|
-
|
201
|
-
base_dir = File.join(Base.metadata_directory, table_name)
|
202
|
-
FileUtils.mkdir_p(base_dir)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
105
|
def initialize_migrations_table
|
207
106
|
table_name = Migrator.schema_migrations_table_name
|
208
107
|
groonga_table_name = Migrator.groonga_schema_migrations_table_name
|
@@ -211,104 +110,108 @@ module ActiveGroonga
|
|
211
110
|
"#{table_name}.groonga")
|
212
111
|
Groonga::Hash.create(:name => groonga_table_name,
|
213
112
|
:path => table_file,
|
214
|
-
:key_type => "
|
113
|
+
:key_type => "ShortText")
|
215
114
|
end
|
216
115
|
end
|
116
|
+
|
117
|
+
def default_table_options(options)
|
118
|
+
default_options = {:sub_records => true}
|
119
|
+
case options[:type]
|
120
|
+
when :hash, :patricia_trie
|
121
|
+
default_options[:default_tokenizer] = "TokenBigram"
|
122
|
+
end
|
123
|
+
default_options
|
124
|
+
end
|
217
125
|
end
|
218
126
|
|
219
|
-
class
|
220
|
-
|
127
|
+
class TableDefinitionWrapper
|
128
|
+
def initialize(definition)
|
129
|
+
@definition = definition
|
130
|
+
end
|
131
|
+
|
132
|
+
def column(name, type, options={})
|
133
|
+
column_file = File.join(Base.columns_directory(@definition.name),
|
134
|
+
"#{name}.groonga")
|
135
|
+
options = {:path => column_file}.merge(options)
|
136
|
+
@definition.column(name, type, options)
|
137
|
+
end
|
138
|
+
|
139
|
+
def remove_column(name, options={})
|
140
|
+
@definition.remove_column(name, options)
|
141
|
+
end
|
142
|
+
alias_method :remove_index, :remove_column
|
143
|
+
|
144
|
+
def index(target_table_name, target_column_name, options={})
|
145
|
+
column_name = options.delete(:name)
|
146
|
+
column_name ||= [target_table_name, target_column_name].join("_")
|
147
|
+
column_dir = Base.index_columns_directory(@definition.name,
|
148
|
+
target_table_name.to_s)
|
149
|
+
column_file = File.join(column_dir, "#{column_name}.groonga")
|
150
|
+
options = {
|
151
|
+
:with_position => true,
|
152
|
+
:path => column_file,
|
153
|
+
:name => column_name,
|
154
|
+
}.merge(options)
|
155
|
+
target_table = @definition.context[target_table_name]
|
156
|
+
target_column = target_table.column(target_column_name)
|
157
|
+
@definition.index(target_column, options)
|
158
|
+
end
|
159
|
+
|
160
|
+
def timestamps(*args)
|
161
|
+
options = args.extract_options!
|
162
|
+
column(:created_at, :datetime, options)
|
163
|
+
column(:updated_at, :datetime, options)
|
164
|
+
end
|
221
165
|
|
222
|
-
def
|
223
|
-
|
224
|
-
@name = name
|
225
|
-
@indexes = []
|
166
|
+
def string(*args)
|
167
|
+
columns("ShortText", *args)
|
226
168
|
end
|
227
169
|
|
228
|
-
def
|
229
|
-
|
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
|
170
|
+
def text(*args)
|
171
|
+
columns("Text", *args)
|
236
172
|
end
|
237
173
|
|
238
|
-
def
|
239
|
-
|
240
|
-
column.type = type
|
241
|
-
@columns << column unless @columns.include?(column)
|
242
|
-
self
|
174
|
+
def integer(*args)
|
175
|
+
columns("Int32", *args)
|
243
176
|
end
|
244
177
|
|
245
|
-
def
|
246
|
-
|
178
|
+
def float(*args)
|
179
|
+
columns("Float", *args)
|
247
180
|
end
|
248
181
|
|
249
|
-
def
|
250
|
-
|
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
|
182
|
+
def decimal(*args)
|
183
|
+
columns("Int64", *args)
|
256
184
|
end
|
257
|
-
alias :belongs_to :references
|
258
|
-
end
|
259
185
|
|
260
|
-
|
261
|
-
|
186
|
+
def time(*args)
|
187
|
+
columns("Time", *args)
|
188
|
+
end
|
189
|
+
alias_method :datetime, :time
|
190
|
+
alias_method :timestamp, :time
|
262
191
|
|
263
|
-
def
|
264
|
-
|
265
|
-
@name = name
|
266
|
-
@name = @name.to_s if @name.is_a?(Symbol)
|
267
|
-
@type = nil
|
192
|
+
def binary(*args)
|
193
|
+
columns("LongText", *args)
|
268
194
|
end
|
269
195
|
|
270
|
-
def
|
271
|
-
|
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)
|
196
|
+
def boolean(*args)
|
197
|
+
columns("Bool", *args)
|
278
198
|
end
|
279
199
|
|
280
|
-
def
|
281
|
-
Base.
|
200
|
+
def reference(name, table=nil, options={})
|
201
|
+
table = Base.groonga_table_name(table || name.to_s.pluralize)
|
202
|
+
column(name, table, options)
|
282
203
|
end
|
204
|
+
alias_method :references, :reference
|
205
|
+
alias_method :belongs_to, :references
|
283
206
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
207
|
+
private
|
208
|
+
def columns(type, *args)
|
209
|
+
options = args.extract_options!
|
210
|
+
column_names = args
|
211
|
+
column_names.each do |name|
|
212
|
+
column(name, type, options)
|
305
213
|
end
|
306
214
|
end
|
307
215
|
end
|
308
|
-
|
309
|
-
class IndexDefinition < ActiveRecord::ConnectionAdapters::IndexDefinition
|
310
|
-
alias_method :column, :columns
|
311
|
-
alias_method :column=, :columns=
|
312
|
-
end
|
313
216
|
end
|
314
217
|
end
|
@@ -28,9 +28,11 @@ module ActiveGroonga
|
|
28
28
|
|
29
29
|
def dump(stream)
|
30
30
|
@references = []
|
31
|
+
@indexes = []
|
31
32
|
header(stream)
|
32
33
|
dump_tables(stream)
|
33
34
|
dump_references(stream)
|
35
|
+
dump_indexes(stream)
|
34
36
|
trailer(stream)
|
35
37
|
stream
|
36
38
|
end
|
@@ -52,13 +54,34 @@ module ActiveGroonga
|
|
52
54
|
def dump_table(name, stream)
|
53
55
|
begin
|
54
56
|
table_schema = StringIO.new
|
55
|
-
|
57
|
+
|
58
|
+
table_name = Base.groonga_table_name(name)
|
59
|
+
table = Base.context[table_name]
|
60
|
+
options = [":force => true"]
|
61
|
+
case table
|
62
|
+
when Groonga::Hash
|
63
|
+
options << ":type => :hash"
|
64
|
+
when Groonga::PatriciaTrie
|
65
|
+
options << ":type => :patricia_trie"
|
66
|
+
end
|
67
|
+
if table.domain
|
68
|
+
options << ":key_type => #{table.domain.name.inspect}"
|
69
|
+
end
|
70
|
+
if table.respond_to?(:default_tokenizer) and table.default_tokenizer
|
71
|
+
options << ":default_tokenizer => #{table.default_tokenizer.name.inspect}"
|
72
|
+
end
|
73
|
+
|
74
|
+
table_schema.puts " create_table #{name.inspect}, #{options.join(', ')} do |t|"
|
56
75
|
column_specs = []
|
57
76
|
columns(name).each do |column|
|
58
77
|
if column.reference_type?
|
59
78
|
@references << [name, column]
|
60
79
|
next
|
61
80
|
end
|
81
|
+
if column.index?
|
82
|
+
@indexes << [name, column]
|
83
|
+
next
|
84
|
+
end
|
62
85
|
|
63
86
|
spec = {}
|
64
87
|
spec[:type] = column.type.to_s
|
@@ -74,8 +97,6 @@ module ActiveGroonga
|
|
74
97
|
table_schema.puts " end"
|
75
98
|
table_schema.puts
|
76
99
|
|
77
|
-
dump_indexes(name, table_schema)
|
78
|
-
|
79
100
|
stream.print table_schema.string
|
80
101
|
rescue => e
|
81
102
|
stream.puts "# Could not dump table #{name.inspect} because of following #{e.class}"
|
@@ -89,42 +110,36 @@ module ActiveGroonga
|
|
89
110
|
stream
|
90
111
|
end
|
91
112
|
|
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
113
|
def dump_references(stream)
|
109
114
|
@references.sort_by do |name, column|
|
110
115
|
[name, column.name]
|
111
116
|
end.each do |name, column|
|
112
117
|
statement = " add_column #{name.inspect}, "
|
113
|
-
statement << "#{column.name.inspect},
|
114
|
-
statement << "
|
118
|
+
statement << "#{column.name.inspect}, "
|
119
|
+
statement << "#{column.reference_object_name.inspect}"
|
115
120
|
stream.puts(statement)
|
116
121
|
end
|
117
122
|
end
|
118
123
|
|
124
|
+
def dump_indexes(stream)
|
125
|
+
@indexes.sort_by do |name, column|
|
126
|
+
[name, column.name]
|
127
|
+
end.each do |name, column|
|
128
|
+
column.index_sources.each do |source|
|
129
|
+
statement = " add_index_column #{name.inspect}, "
|
130
|
+
statement << "#{source.table.name.inspect}, "
|
131
|
+
statement << "#{source.local_name.inspect}, "
|
132
|
+
statement << ":name => #{column.name.inspect}"
|
133
|
+
stream.puts(statement)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
119
138
|
def columns(table_name)
|
120
139
|
table_name = Base.groonga_table_name(table_name)
|
121
140
|
Base.context[table_name].columns.collect {|column| Column.new(column)}
|
122
141
|
end
|
123
142
|
|
124
|
-
def indexes(table_name)
|
125
|
-
Schema.indexes(table_name)
|
126
|
-
end
|
127
|
-
|
128
143
|
class StreamWrapper
|
129
144
|
def initialize(stream)
|
130
145
|
@stream = stream
|