Class: XGen::Mongo::GridFS::GridStore

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/mongo/gridfs/grid_store.rb

Overview

GridStore is an IO-like object that provides input and output for streams of data to Mongo. See Mongo’s documentation about GridFS for storage implementation details.

Example code:

require 'mongo/gridfs'
GridStore.open(database, 'filename', 'w') { |f|
  f.puts "Hello, world!"
}
GridStore.open(database, 'filename, 'r') { |f|
  puts f.read         # => Hello, world!\n
}
GridStore.open(database, 'filename', 'w+') { |f|
  f.puts "But wait, there's more!"
}
GridStore.open(database, 'filename, 'r') { |f|
  puts f.read         # => Hello, world!\nBut wait, there's more!\n
}

Constant Summary collapse

DEFAULT_ROOT_COLLECTION =
'fs'
DEFAULT_CONTENT_TYPE =
'text/plain'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db, name, mode = 'r', options = {}) ⇒ GridStore

Mode may only be ‘r’, ‘w’, or ‘w+’.

Options. Descriptions start with a list of the modes for which that option is legitimate.

:root

(r, w, w+) Name of root collection to use, instead of DEFAULT_ROOT_COLLECTION.

:metadata

(w, w+) A hash containing any data you want persisted as

this file's metadata. See also metadata=
:chunk_size

(w) Sets chunk size for files opened for writing See also chunk_size= which may only be called before any data is written.

:content_type

(w) Default value is DEFAULT_CONTENT_TYPE. See also #content_type=



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/mongo/gridfs/grid_store.rb', line 146

def initialize(db, name, mode='r', options={})
  @db, @filename, @mode = db, name, mode
  @root = options[:root] || DEFAULT_ROOT_COLLECTION

  doc = collection.find({'filename' => @filename}).next_object
  if doc
    @files_id = doc['_id']
    @content_type = doc['contentType']
    @chunk_size = doc['chunkSize']
    @upload_date = doc['uploadDate']
    @aliases = doc['aliases']
    @length = doc['length']
    @metadata = doc['metadata']
    @md5 = doc['md5']
  else
    @files_id = XGen::Mongo::Driver::ObjectID.new
    @content_type = DEFAULT_CONTENT_TYPE
    @chunk_size = Chunk::DEFAULT_CHUNK_SIZE
    @length = 0
  end

  case mode
  when 'r'
    @curr_chunk = nth_chunk(0)
    @position = 0
  when 'w'
    chunk_collection.create_index([['files_id', XGen::Mongo::ASCENDING], ['n', XGen::Mongo::ASCENDING]])
    delete_chunks
    @curr_chunk = Chunk.new(self, 'n' => 0)
    @content_type = options[:content_type] if options[:content_type]
    @chunk_size = options[:chunk_size] if options[:chunk_size]
    @metadata = options[:metadata] if options[:metadata]
    @position = 0
  when 'w+'
    chunk_collection.create_index([['files_id', XGen::Mongo::ASCENDING], ['n', XGen::Mongo::ASCENDING]])
    @curr_chunk = nth_chunk(last_chunk_number) || Chunk.new(self, 'n' => 0) # might be empty
    @curr_chunk.pos = @curr_chunk.data.length if @curr_chunk
    @metadata = options[:metadata] if options[:metadata]
    @position = @length
  else
    raise "error: illegal mode #{mode}"
  end

  @lineno = 0
  @pushback_byte = nil
end

Instance Attribute Details

#aliasesObject

Array of strings; may be nil



54
55
56
# File 'lib/mongo/gridfs/grid_store.rb', line 54

def aliases
  @aliases
end

#chunk_sizeObject

Returns the value of attribute chunk_size.



66
67
68
# File 'lib/mongo/gridfs/grid_store.rb', line 66

def chunk_size
  @chunk_size
end

#content_typeObject

Default is DEFAULT_CONTENT_TYPE



57
58
59
# File 'lib/mongo/gridfs/grid_store.rb', line 57

def content_type
  @content_type
end

#filenameObject

Returns the value of attribute filename.



51
52
53
# File 'lib/mongo/gridfs/grid_store.rb', line 51

def filename
  @filename
end

#files_idObject (readonly)

Returns the value of attribute files_id.



61
62
63
# File 'lib/mongo/gridfs/grid_store.rb', line 61

def files_id
  @files_id
end

#linenoObject

Returns the value of attribute lineno.



68
69
70
# File 'lib/mongo/gridfs/grid_store.rb', line 68

def lineno
  @lineno
end

#md5Object (readonly)

Returns the value of attribute md5.



70
71
72
# File 'lib/mongo/gridfs/grid_store.rb', line 70

def md5
  @md5
end

#metadataObject

Returns the value of attribute metadata.



59
60
61
# File 'lib/mongo/gridfs/grid_store.rb', line 59

def 
  @metadata
end

#upload_dateObject (readonly)

Time that the file was first saved.



64
65
66
# File 'lib/mongo/gridfs/grid_store.rb', line 64

def upload_date
  @upload_date
end

Class Method Details

.exist?(db, name, root_collection = DEFAULT_ROOT_COLLECTION) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
# File 'lib/mongo/gridfs/grid_store.rb', line 74

def exist?(db, name, root_collection=DEFAULT_ROOT_COLLECTION)
  db.collection("#{root_collection}.files").find({'filename' => name}).next_object != nil
end

.list(db, root_collection = DEFAULT_ROOT_COLLECTION) ⇒ Object

List the contains of all GridFS files stored in the given db and root collection.

:db

the database to use

:root_collection

the root collection to use



102
103
104
105
106
# File 'lib/mongo/gridfs/grid_store.rb', line 102

def list(db, root_collection=DEFAULT_ROOT_COLLECTION)
  db.collection("#{root_collection}.files").find().map { |f|
    f['filename']
  }
end

.open(db, name, mode, options = {}) ⇒ Object



78
79
80
81
82
83
84
85
86
87
# File 'lib/mongo/gridfs/grid_store.rb', line 78

def open(db, name, mode, options={})
  gs = self.new(db, name, mode, options)
  result = nil
  begin
    result = yield gs if block_given?
  ensure
    gs.close
  end
  result
end

.read(db, name, length = nil, offset = nil) ⇒ Object



89
90
91
92
93
94
# File 'lib/mongo/gridfs/grid_store.rb', line 89

def read(db, name, length=nil, offset=nil)
  GridStore.open(db, name, 'r') { |gs|
    gs.seek(offset) if offset
    gs.read(length)
  }
end

.readlines(db, name, separator = $/) ⇒ Object



108
109
110
111
112
# File 'lib/mongo/gridfs/grid_store.rb', line 108

def readlines(db, name, separator=$/)
  GridStore.open(db, name, 'r') { |gs|
    gs.readlines(separator)
  }
end


114
115
116
117
118
119
120
# File 'lib/mongo/gridfs/grid_store.rb', line 114

def unlink(db, *names)
  names.each { |name|
    gs = GridStore.new(db, name)
    gs.send(:delete_chunks)
    gs.collection.remove('_id' => gs.files_id)
  }
end

Instance Method Details

#<<(obj) ⇒ Object



332
333
334
# File 'lib/mongo/gridfs/grid_store.rb', line 332

def <<(obj)
  write(obj.to_s)
end

#chunk_collectionObject

Returns collection used for storing chunks. Depends on value of



199
200
201
# File 'lib/mongo/gridfs/grid_store.rb', line 199

def chunk_collection
  @db.collection("#{@root}.chunks")
end

#closeObject


closing ================

+++



407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'lib/mongo/gridfs/grid_store.rb', line 407

def close
  if @mode[0] == ?w
    if @curr_chunk
      @curr_chunk.truncate
      @curr_chunk.save if @curr_chunk.pos > 0
    end
    files = collection
    if @upload_date
      files.remove('_id' => @files_id)
    else
      @upload_date = Time.now
    end
    files.insert(to_mongo_object)
  end
  @db = nil
end

#closed?Boolean

Returns:

  • (Boolean)


424
425
426
# File 'lib/mongo/gridfs/grid_store.rb', line 424

def closed?
  @db == nil
end

#collectionObject



193
194
195
# File 'lib/mongo/gridfs/grid_store.rb', line 193

def collection
  @db.collection("#{@root}.files")
end

#eachObject Also known as: each_line



274
275
276
277
278
279
280
# File 'lib/mongo/gridfs/grid_store.rb', line 274

def each
  line = gets
  while line
    yield line
    line = gets
  end
end

#each_byteObject



283
284
285
286
287
288
289
# File 'lib/mongo/gridfs/grid_store.rb', line 283

def each_byte
  byte = self.getc
  while byte
    yield byte
    byte = self.getc
  end
end

#eofObject Also known as: eof?


status ================

+++

Raises:

  • (IOError)


355
356
357
358
# File 'lib/mongo/gridfs/grid_store.rb', line 355

def eof
  raise IOError.new("stream not open for reading") unless @mode[0] == ?r
  @position >= @length
end

#flushObject

A no-op.



348
349
# File 'lib/mongo/gridfs/grid_store.rb', line 348

def flush
end

#getcObject


reading ================

+++



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/mongo/gridfs/grid_store.rb', line 216

def getc
  if @pushback_byte
    byte = @pushback_byte
    @pushback_byte = nil
    @position += 1
    byte
  elsif eof?
    nil
  else
    if @curr_chunk.eof?
      @curr_chunk = nth_chunk(@curr_chunk.chunk_number + 1)
    end
    @position += 1
    @curr_chunk.getc
  end
end

#gets(separator = $/) ⇒ Object



233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/mongo/gridfs/grid_store.rb', line 233

def gets(separator=$/)
  str = ''
  byte = self.getc
  return nil if byte == nil # EOF
  while byte != nil
    s = byte.chr
    str << s
    break if s == separator
    byte = self.getc
  end
  @lineno += 1
  str
end


310
311
312
313
314
315
316
317
# File 'lib/mongo/gridfs/grid_store.rb', line 310

def print(*objs)
  objs = [$_] if objs == nil || objs.empty?
  objs.each { |obj|
    str = obj.to_s
    str.each_byte { |byte| self.putc(byte) }
  }
  nil
end

#putc(byte) ⇒ Object


writing ================

+++



300
301
302
303
304
305
306
307
308
# File 'lib/mongo/gridfs/grid_store.rb', line 300

def putc(byte)
  if @curr_chunk.pos == @chunk_size
    prev_chunk_number = @curr_chunk.chunk_number
    @curr_chunk.save
    @curr_chunk = Chunk.new(self, 'n' => prev_chunk_number + 1)
  end
  @position += 1
  @curr_chunk.putc(byte)
end

#puts(*objs) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/mongo/gridfs/grid_store.rb', line 319

def puts(*objs)
  if objs == nil || objs.empty?
    self.putc(10)
  else
    print(*objs.collect{ |obj|
            str = obj.to_s
            str << "\n" unless str =~ /\n$/
            str
          })
  end
  nil
end

#read(len = nil, buf = nil) ⇒ Object



247
248
249
250
251
252
253
254
255
256
# File 'lib/mongo/gridfs/grid_store.rb', line 247

def read(len=nil, buf=nil)
  buf ||= ''
  byte = self.getc
  while byte != nil && (len == nil || len > 0)
    buf << byte.chr
    len -= 1 if len
    byte = self.getc if (len == nil || len > 0)
  end
  buf
end

#readcharObject

Raises:

  • (EOFError)


258
259
260
261
262
# File 'lib/mongo/gridfs/grid_store.rb', line 258

def readchar
  byte = self.getc
  raise EOFError.new if byte == nil
  byte
end

#readline(separator = $/) ⇒ Object

Raises:

  • (EOFError)


264
265
266
267
268
# File 'lib/mongo/gridfs/grid_store.rb', line 264

def readline(separator=$/)
  line = gets
  raise EOFError.new if line == nil
  line
end

#readlines(separator = $/) ⇒ Object



270
271
272
# File 'lib/mongo/gridfs/grid_store.rb', line 270

def readlines(separator=$/)
  read.split(separator).collect { |line| "#{line}#{separator}" }
end

#rewindObject


positioning ================

+++



365
366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/mongo/gridfs/grid_store.rb', line 365

def rewind
  if @curr_chunk.chunk_number != 0
    if @mode[0] == ?w
      delete_chunks
      @curr_chunk = Chunk.new(self, 'n' => 0)
    else
      @curr_chunk == nth_chunk(0)
    end
  end
  @curr_chunk.pos = 0
  @lineno = 0
  @position = 0
end

#seek(pos, whence = IO::SEEK_SET) ⇒ Object



379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/mongo/gridfs/grid_store.rb', line 379

def seek(pos, whence=IO::SEEK_SET)
  target_pos = case whence
               when IO::SEEK_CUR
                 @position + pos
               when IO::SEEK_END
                 @length + pos
               when IO::SEEK_SET
                 pos
               end

  new_chunk_number = (target_pos / @chunk_size).to_i
  if new_chunk_number != @curr_chunk.chunk_number
    @curr_chunk.save if @mode[0] == ?w
    @curr_chunk = nth_chunk(new_chunk_number)
  end
  @position = target_pos
  @curr_chunk.pos = @position % @chunk_size
  0
end

#tellObject



399
400
401
# File 'lib/mongo/gridfs/grid_store.rb', line 399

def tell
 @position
end

#ungetc(byte) ⇒ Object



291
292
293
294
# File 'lib/mongo/gridfs/grid_store.rb', line 291

def ungetc(byte)
  @pushback_byte = byte
  @position -= 1
end

#write(string) ⇒ Object

Writes string as bytes and returns the number of bytes written.



337
338
339
340
341
342
343
344
345
# File 'lib/mongo/gridfs/grid_store.rb', line 337

def write(string)
  raise "#@filename not opened for write" unless @mode[0] == ?w
  count = 0
  string.each_byte { |byte|
    self.putc byte
    count += 1
  }
  count
end