const uuid = require('uuid').v4 const { Model } = require('flitter-orm') const { NodeDescriptorType } = require('../../enum') class Node extends Model { static get services() { return [...super.services, 'models'] } static get schema() { return { uuid: { type: String, default: uuid }, pied_name: String, pied_parent_path: { type: String, default: '/' }, overlay_name: { type: String, default: 'mainline' }, mtime: { type: Date, default: () => new Date }, atime: { type: Date, default: () => new Date }, ctime: { type: Date, default: () => new Date }, mode: { type: Number, default: 33188 }, size: { type: Number, default: 0 }, descriptor_type: { type: String, default: NodeDescriptorType.File }, uploaded_file_id: String, deleted: { type: Boolean, default: false }, root: { type: Boolean, default: false }, } } static path_parts(path) { const path_parts = path.split('/') const pied_name = path_parts.pop() let pied_parent_path = path_parts.join('/') if ( !pied_parent_path.startsWith('/') ) pied_parent_path = `/${pied_parent_path}` return [pied_parent_path, pied_name] } static async get_root() { let root = await this.findOne({ deleted: false, root: true, pied_parent_path: '/', pied_name: '/', }) if ( !root ) { root = new this({ pied_name: '/', mode: 16877, root: true, descriptor_type: NodeDescriptorType.Directory, }) await root.save() } return root } static async get_path(path, workspace = 'mainline') { const [pied_parent_path, pied_name] = this.path_parts(path) const nodes = await this.find({ pied_name, pied_parent_path, overlay_name: { $in: [workspace, 'mainline'], }, deleted: false, root: false, }) if ( nodes.length === 1 ) { return nodes[0] } if ( nodes.length === 2 ) { return nodes.find(x => x.overlay_name === workspace) } } static async list_path(path, workspace = 'mainline') { const nodes = await this.find({ pied_parent_path: path, overlay_name: workspace, // deleted: false, root: false, }) const mainline_nodes = await this.find({ pied_name: { $nin: nodes.map(x => x.pied_name), }, pied_parent_path: path, overlay_name: 'mainline', deleted: false, root: false, }) return [...nodes, ...mainline_nodes].filter(x => !x.deleted) } async uploaded_file() { if ( !this.uploaded_file_id ) return; const File = this.models.get('upload::File') return File.findById(this.uploaded_file_id) } async all_descendants(workspace = 'mainline') { const formatted_parent = `${this.pied_parent_path === '/' ? '/' : this.pied_parent_path + '/'}${this.pied_name}` const nodes = await this.constructor.find({ pied_parent_path: { $regex: this.root ? `/.*` : `(?:${formatted_parent}/.*)|(?:${formatted_parent}$)`, }, overlay_name: workspace, root: false, // deleted: false, }) const mainline_nodes = await this.constructor.find({ $and: [ { pied_parent_path: { $regex: this.root ? `/.*` : `(?:${formatted_parent}/.*)|(?:${formatted_parent}$)`, }, overlay_name: 'mainline', root: false, deleted: false, }, ...nodes.map(node => { return { pied_parent_path: { $ne: node.pied_parent_path, }, pied_name: { $ne: node.pied_name, }, } }) ], }) return [...nodes, ...mainline_nodes].filter(x => !x.deleted) } to_api() { return { pied_name: this.pied_name, mtime: this.mtime, atime: this.atime, ctime: this.ctime, mode: this.mode, nlink: 1, uid: 0, // TODO gid: 0, // TODO size: this.size, } } } module.exports = exports = Node