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=



134
135
136
137
138
139
140
141
142
143
144
145
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
# File 'lib/mongo/gridfs/grid_store.rb', line 134

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

.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



96
97
98
99
100
# File 'lib/mongo/gridfs/grid_store.rb', line 96

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


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

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



320
321
322
# File 'lib/mongo/gridfs/grid_store.rb', line 320

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

#chunk_collectionObject

Returns collection used for storing chunks. Depends on value of



187
188
189
# File 'lib/mongo/gridfs/grid_store.rb', line 187

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

#closeObject


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

+++



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/mongo/gridfs/grid_store.rb', line 395

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)


412
413
414
# File 'lib/mongo/gridfs/grid_store.rb', line 412

def closed?
  @db == nil
end

#collectionObject



181
182
183
# File 'lib/mongo/gridfs/grid_store.rb', line 181

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

#eachObject Also known as: each_line



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

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

#each_byteObject



271
272
273
274
275
276
277
# File 'lib/mongo/gridfs/grid_store.rb', line 271

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

#eofObject Also known as: eof?


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

+++

Raises:

  • (IOError)


343
344
345
346
# File 'lib/mongo/gridfs/grid_store.rb', line 343

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

#flushObject

A no-op.



336
337
# File 'lib/mongo/gridfs/grid_store.rb', line 336

def flush
end

#getcObject


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

+++



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/mongo/gridfs/grid_store.rb', line 204

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



221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/mongo/gridfs/grid_store.rb', line 221

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


298
299
300
301
302
303
304
305
# File 'lib/mongo/gridfs/grid_store.rb', line 298

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 ================

+++



288
289
290
291
292
293
294
295
296
# File 'lib/mongo/gridfs/grid_store.rb', line 288

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



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

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



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

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)


246
247
248
249
250
# File 'lib/mongo/gridfs/grid_store.rb', line 246

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

#readline(separator = $/) ⇒ Object

Raises:

  • (EOFError)


252
253
254
255
256
# File 'lib/mongo/gridfs/grid_store.rb', line 252

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

#readlines(separator = $/) ⇒ Object



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

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

#rewindObject


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

+++



353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/mongo/gridfs/grid_store.rb', line 353

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



367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/mongo/gridfs/grid_store.rb', line 367

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



387
388
389
# File 'lib/mongo/gridfs/grid_store.rb', line 387

def tell
 @position
end

#ungetc(byte) ⇒ Object



279
280
281
282
# File 'lib/mongo/gridfs/grid_store.rb', line 279

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

#write(string) ⇒ Object

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



325
326
327
328
329
330
331
332
333
# File 'lib/mongo/gridfs/grid_store.rb', line 325

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