/**
* @module flitter-gridfs/models/File
*/
const Model = require('flitter-orm/src/model/Model')
const path = require('path')
const fs = require('fs')
const Mongo = require('mongodb')
/**
* Model to represent a stored file.
* @extends {module:flitter-orm/src/model/Model~Model}
*/
class GridFile extends Model {
/**
* Defines the services required by this model.
* @returns {Array<string>}
*/
static get services() {
return [...super.services, 'gridfs']
}
/**
* Defines the schema used by this model.
* @returns {object}
*/
static get schema() {
return {
name: String,
content_type: String,
created_on: {type: Date, default: () => new Date},
file_id: String,
data: {type: String, default: '{}'},
}
}
/**
* Get the GridFS files collection.
* @returns {Promise<mongodb/Collection>}
*/
static async files() {
return this.gridfs.mongo_db.collection('fs.files')
}
/**
* Convert an object ID string to a MongoDB ObjectId.
* @param {string} id
* @returns {mongodb/ObjectId}
*/
static object_id(id) {
return Mongo.ObjectId(id)
}
/**
* Get a file record by ID string from the grid files collection.
* @param {string} id
* @returns {Promise<object>} - resolves to the retrieved file record object
*/
static async one(id) {
const files = await this.files()
return files.findOne({_id: this.object_id(id)})
}
/**
* Get the GridFSBucket used by the model.
* @returns {mongodb/GridFS/Bucket} - the GridFS bucket
*/
grid() {
return this.gridfs.mongo_bucket
}
/**
* Save a file to the grid from a local file.
* @param {string} filepath - path of the file to be uploaded
* @param {string} [filename] - name of the file to save, defaults to the model's this.name
* @returns {Promise<void>}
*/
write_from_file({filepath, filename}){
const grid = this.grid()
filename = filename ? filename : this.name
filepath = path.resolve(filepath)
return new Promise((resolve, reject) => {
fs.createReadStream(filepath)
.pipe(grid.openUploadStream(filename))
.on('error', (e) => reject(e))
.on('finish', (file) => {
this.file_id = file._id.toString()
this.save().then(resolve)
})
})
}
/**
* Retrieve the model's file from the Grid and store it to the local filesystem.
* @param {string} filepath - path to which the file should be saved
* @returns {Promise<void>}
*/
write_to_file({filepath}){
filepath = path.resolve(filepath)
return new Promise((resolve, reject) => {
this.get_read_stream()
.pipe(fs.createWriteStream(filepath))
.on('error', e => reject(e))
.on('finish', () => resolve())
})
}
/**
* Get the read stream for the model's stored Grid file.
* @returns {mongodb/GridFS/GridFSBucketReadStream}
*/
get_read_stream(){
const grid = this.grid()
return grid.openDownloadStream(this.constructor.object_id(this.file_id))
}
/**
* Send this model's stored Grid file as data for the specified response.
* @param {express/Response} response - the response to send to
* @returns {boolean | void}
*/
send_to_response(response){
const stream = this.get_read_stream()
response.set({
'Content-Disposition': `inline; filename="${this.name}"`
})
return stream.pipe(response)
}
}
module.exports = exports = GridFile