173 lines
6.4 KiB
TypeScript
173 lines
6.4 KiB
TypeScript
import { Document, DocumentBody, DocumentAccessor, QueryListOption } from '../model/doc';
|
|
import Knex from 'knex';
|
|
import {createKnexTagController} from './tag';
|
|
import { TagAccessor } from '../model/tag';
|
|
|
|
type DBTagContentRelation = {
|
|
doc_id:number,
|
|
tag_name:string
|
|
}
|
|
|
|
class KnexDocumentAccessor implements DocumentAccessor{
|
|
knex : Knex;
|
|
tagController: TagAccessor;
|
|
constructor(knex : Knex){
|
|
this.knex = knex;
|
|
this.tagController = createKnexTagController(knex);
|
|
}
|
|
async add(c: DocumentBody){
|
|
const {tags,additional, ...rest} = c;
|
|
const id_lst = await this.knex.insert({
|
|
additional:JSON.stringify(additional),
|
|
created_at:Date.now(),
|
|
...rest
|
|
}).into('document');
|
|
const id = id_lst[0];
|
|
for (const it of tags) {
|
|
this.tagController.addTag({name:it});
|
|
}
|
|
if(tags.length > 0){
|
|
await this.knex.insert<DBTagContentRelation>(
|
|
tags.map(x=>({doc_id:id,tag_name:x}))
|
|
).into("doc_tag_relation");
|
|
}
|
|
return id;
|
|
};
|
|
async del(id:number) {
|
|
if (await this.findById(id) !== undefined){
|
|
await this.knex.delete().from("doc_tag_relation").where({doc_id:id});
|
|
await this.knex.delete().from("document").where({id:id});
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
async findById(id:number,tagload?:boolean): Promise<Document|undefined>{
|
|
const s = await this.knex.select("*").from("document").where({id:id});
|
|
if(s.length === 0) return undefined;
|
|
const first = s[0];
|
|
let ret_tags:string[] = []
|
|
if(tagload === true){
|
|
const tags : DBTagContentRelation[] = await this.knex.select("*")
|
|
.from("doc_tag_relation").where({doc_id:first.id});
|
|
ret_tags = tags.map(x=>x.tag_name);
|
|
}
|
|
return {
|
|
...first,
|
|
tags:ret_tags,
|
|
additional: first.additional !== null ? JSON.parse(first.additional) : {},
|
|
};
|
|
};
|
|
async findDeleted(content_type:string){
|
|
const s = await this.knex.select("*")
|
|
.where({content_type:content_type})
|
|
.whereNotNull("update_at")
|
|
.from("document");
|
|
return s.map(x=>({
|
|
...x,
|
|
tags:[],
|
|
additional:{}
|
|
}));
|
|
}
|
|
async findList(option?:QueryListOption){
|
|
option = option || {};
|
|
const allow_tag = option.allow_tag || [];
|
|
const eager_loading = typeof option.eager_loading === "undefined" || option.eager_loading;
|
|
const limit = option.limit || 20;
|
|
const use_offset = option.use_offset || false;
|
|
const offset = option.offset || 0;
|
|
const word = option.word;
|
|
const content_type = option.content_type;
|
|
const cursor = option.cursor;
|
|
|
|
const buildquery = ()=>{
|
|
let query = this.knex.select("document.*");
|
|
if(allow_tag.length > 0){
|
|
query = query.from("doc_tag_relation as tags_0");
|
|
query = query.where("tags_0.tag_name","=",allow_tag[0]);
|
|
for (let index = 1; index < allow_tag.length; index++) {
|
|
const element = allow_tag[index];
|
|
query = query.innerJoin(`doc_tag_relation as tags_${index}`,`tags_${index}.doc_id`,"tags_0.doc_id");
|
|
query = query.where(`tags_${index}.tag_name`,'=',element);
|
|
}
|
|
query = query.innerJoin("document","tags_0.doc_id","document.id");
|
|
}
|
|
else{
|
|
query = query.from("document");
|
|
}
|
|
if(word !== undefined){
|
|
//don't worry about sql injection.
|
|
query = query.where('title','like',`%${word}%`);
|
|
}
|
|
if(content_type !== undefined){
|
|
query = query.where('content_type','=',content_type);
|
|
}
|
|
if(use_offset){
|
|
query = query.offset(offset);
|
|
}
|
|
else{
|
|
if(cursor !== undefined){
|
|
query = query.where('id','<',cursor);
|
|
}
|
|
}
|
|
query = query.limit(limit);
|
|
query = query.orderBy('id',"desc");
|
|
return query;
|
|
}
|
|
let query = buildquery();
|
|
//console.log(query.toSQL());
|
|
let result:Document[] = await query;
|
|
for(let i of result){
|
|
i.additional = JSON.parse((i.additional as unknown) as string);
|
|
}
|
|
if(eager_loading){
|
|
let idmap: {[index:number]:Document} = {};
|
|
for(const r of result){
|
|
idmap[r.id] = r;
|
|
r.tags = [];
|
|
}
|
|
let subquery = buildquery();
|
|
let tagquery= this.knex.select("id","doc_tag_relation.tag_name").from(subquery)
|
|
.innerJoin("doc_tag_relation","doc_tag_relation.doc_id","id");
|
|
//console.log(tagquery.toSQL());
|
|
let tagresult:{id:number,tag_name:string}[] = await tagquery;
|
|
for(const {id,tag_name} of tagresult){
|
|
idmap[id].tags.push(tag_name);
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
async findByPath(path:string,filename?:string):Promise<Document[]>{
|
|
const e = filename == undefined ? {} : {filename:filename}
|
|
const results = await this.knex.select("*").from("document").where({basepath:path,...e});
|
|
return results.map(x=>({
|
|
...x,
|
|
tags:[],
|
|
additional:{}
|
|
}))
|
|
}
|
|
async update(c:Partial<Document> & { id:number }){
|
|
const {id,tags,...rest} = c;
|
|
if (await this.findById(id) !== undefined){
|
|
await this.knex.update(rest).where({id: id}).from("document");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
async addTag(c: Document,tag_name:string){
|
|
if (c.tags.includes(tag_name)) return false;
|
|
this.tagController.addTag({name:tag_name});
|
|
await this.knex.insert<DBTagContentRelation>({tag_name: tag_name, doc_id: c.id})
|
|
.into("doc_tag_relation");
|
|
c.tags.push(tag_name);
|
|
return true;
|
|
}
|
|
async delTag(c: Document,tag_name:string){
|
|
if (c.tags.includes(tag_name)) return false;
|
|
await this.knex.delete().where({tag_name: tag_name,doc_id: c.id}).from("doc_tag_relation");
|
|
c.tags.push(tag_name);
|
|
return true;
|
|
}
|
|
}
|
|
export const createKnexDocumentAccessor = (knex:Knex): DocumentAccessor=>{
|
|
return new KnexDocumentAccessor(knex);
|
|
} |