import { inject , injectable } from 'inversify' ; import { In , IsNull , Not } from 'typeorm' ; import * as apid from '../../../api' ; import Recorded from '../../db/entities/Recorded' ; import Thumbnail from '../../db/entities/Thumbnail' ; import VideoFile from '../../db/entities/VideoFile' ; import StrUtil from '../../util/StrUtil' ; import IPromiseRetry from '../IPromiseRetry' ; import DBUtil from './DBUtil' ; import IDBOperator from './IDBOperator' ; import IRecordedDB , { FindAllOption , RecordedColumnOption } from './IRecordedDB' ; @ injectable ( ) export default class RecordedDB implements IRecordedDB { private op : IDBOperator ; private promieRetry : IPromiseRetry ; constructor ( @ inject ( 'IDBOperator' ) op , @ inject ( 'IPromiseRetry' ) promieRetry ) { this . op = op ; this . promieRetry = promieRetry ; } param items return public async restore ( items ) { const connection = await this . op . getConnection ( ) ; const queryRunner = connection . createQueryRunner ( ) ; await queryRunner . startTransaction ( ) ; let hasError = false ; try { await queryRunner . manager . delete ( Thumbnail , { } ) ; await queryRunner . manager . delete ( VideoFile , { } ) ; await queryRunner . manager . delete ( Recorded , { } ) ; for ( const item of items ) { await queryRunner . manager . insert ( Recorded , item ) ; } await queryRunner . commitTransaction ( ) ; } catch ( err ) { console . error ( err ) ; hasError = err ; await queryRunner . rollbackTransaction ( ) ; } finally { await queryRunner . release ( ) ; } if ( hasError ) { throw new Error ( 'restore error' ) ; } } param recorded return public async insertOnce ( recorded ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . insert ( ) . into ( Recorded ) . values ( recorded ) ; const insertedResult = await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; return insertedResult . identifiers [ 0 ] . id ; } param recorded return public async updateOnce ( recorded ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . update ( Recorded ) . set ( recorded ) . where ( { id : recorded . id } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param recordedId return public async removeRecording ( recordedId ) { const recorded = await this . findId ( recordedId ) ; if ( recorded === null ) { throw new Error ( 'RecordedIsNull' ) ; } if ( recorded . isRecording === false ) { return ; } const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . update ( Recorded ) . set ( { isRecording : false , } ) . where ( { id : recordedId } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param dropLogFileId return public async removeDropLogFileId ( dropLogFileId ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . update ( Recorded ) . set ( { dropLogFileId : null , } ) . where ( { dropLogFileId : dropLogFileId } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param ruleId return public async removeRuleId ( ruleId ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . update ( Recorded ) . set ( { ruleId : null , } ) . where ( { ruleId : ruleId } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param recordedId param isProtect return public async changeProtect ( recordedId , isProtect ) { const recorded = await this . findId ( recordedId ) ; if ( recorded === null ) { throw new Error ( 'RecordedIsNull' ) ; } if ( recorded . isProtected === isProtect ) { return ; } const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . update ( Recorded ) . set ( { isProtected : isProtect , } ) . where ( { id : recordedId } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param recordedId return public async deleteOnce ( recordedId ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . createQueryBuilder ( ) . delete ( ) . from ( Recorded ) . where ( { id : recordedId , } ) ; await this . promieRetry . run ( ( ) => { return queryBuilder . execute ( ) ; } ) ; } param recordedId return public async findId ( recordedId ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . where ( { id : recordedId } ) . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) . leftJoinAndSelect ( 'recorded.dropLogFile' , 'dropLogFile' ) . leftJoinAndSelect ( 'recorded.tags' , 'tags' ) ; const result = await this . promieRetry . run ( ( ) => { return queryBuilder . getMany ( ) ; } ) ; return result . length === 0 ? null : result [ 0 ] ; } param recordedIds return public async findIds ( recordedIds , columnOption ? , isReverse ? ) { if ( recordedIds . length === 0 ) { return [ ] ; } const connection = await this . op . getConnection ( ) ; let queryBuilder = connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . where ( { id : In ( recordedIds ) } ) ; if ( typeof columnOption === 'undefined' ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) ; } else { if ( columnOption . isNeedVideoFiles === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) ; } if ( columnOption . isNeedThumbnails === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) ; } if ( columnOption . isNeedsDropLog === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.dropLogFile' , 'dropLogFile' ) ; } if ( columnOption . isNeedTags === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.tags' , 'tags' ) ; } } queryBuilder = queryBuilder . orderBy ( 'recorded.startAt' , isReverse ? 'ASC' : 'DESC' ) ; const result = await this . promieRetry . run ( ( ) => { return queryBuilder . getMany ( ) ; } ) ; return result ; } param option param columnOption return public async findAll ( option , columnOption ) { const connection = await this . op . getConnection ( ) ; let queryBuilder = connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) ; const querys = [ ] ; if ( typeof option . isRecording !== 'undefined' ) { querys . push ( { query : 'recorded.isRecording = :isRecording' , values : { isRecording : option . isRecording , } , } ) ; } if ( typeof option . ruleId !== 'undefined' ) { if ( option . ruleId === 0 ) { querys . push ( { query : 'recorded.ruleId is null' , values : { } , } ) ; } else { querys . push ( { query : 'recorded.ruleId = :ruleId' , values : { ruleId : option . ruleId , } , } ) ; } } if ( typeof option . channelId !== 'undefined' ) { querys . push ( { query : 'recorded.channelId = :channelId' , values : { channelId : option . channelId , } , } ) ; } if ( typeof option . genre !== 'undefined' ) { querys . push ( { query : '(genre1 = :genre or genre2 = :genre or genre3 = :genre)' , values : { genre : option . genre , } , } ) ; } if ( typeof option . keyword !== 'undefined' ) { const keywords = StrUtil . toHalf ( option . keyword ) . split ( / / ) ; const like = this . op . getLikeStr ( false ) ; const valueBaseName = 'keyword' ; const nameAnd = [ ] ; const descriptionAnd = [ ] ; const values = { } ; keywords . forEach ( ( str , i ) => { str = `%${ str }%` ; const valueName = `${ valueBaseName }Name${ i }` ; values [ valueName ] = str ; nameAnd . push ( `halfWidthName ${ like } :${ valueName }` ) ; descriptionAnd . push ( `halfWidthDescription ${ like } :${ valueName }` ) ; } ) ; const or = [ ] ; if ( nameAnd . length > 0 ) { or . push ( `(${ DBUtil . createAndQuery ( nameAnd ) })` ) ; } if ( descriptionAnd . length > 0 ) { or . push ( `(${ DBUtil . createAndQuery ( descriptionAnd ) })` ) ; } querys . push ( { query : DBUtil . createOrQuery ( or ) , values : values , } ) ; } if ( columnOption . isNeedVideoFiles === true && ! ! option . hasOriginalFile === true ) { querys . push ( { query : 'videoFiles.type <> :type' , values : { type : 'encoded' , } , } ) ; } for ( const q of querys ) { queryBuilder = queryBuilder . andWhere ( q . query , q . values ) ; } if ( typeof option . offset !== 'undefined' ) { queryBuilder . skip ( option . offset ) ; } if ( typeof option . limit !== 'undefined' ) { queryBuilder . take ( option . limit ) ; } queryBuilder = queryBuilder . orderBy ( 'recorded.startAt' , option . isReverse ? 'ASC' : 'DESC' ) ; if ( columnOption . isNeedVideoFiles === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) ; } if ( ! ! option . hasOriginalFile === false ) { if ( columnOption . isNeedThumbnails === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) ; } if ( columnOption . isNeedsDropLog === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.dropLogFile' , 'dropLogFile' ) ; } if ( columnOption . isNeedTags === true ) { queryBuilder = queryBuilder . leftJoinAndSelect ( 'recorded.tags' , 'tags' ) ; } return await this . promieRetry . run ( ( ) => { return queryBuilder . getManyAndCount ( ) ; } ) ; } else { const [ records , total ] = await this . promieRetry . run ( ( ) => { return queryBuilder . getManyAndCount ( ) ; } ) ; const recordedIds = records . map ( r => { return r . id ; } ) ; const result = await this . promieRetry . run ( ( ) => { return this . findIds ( recordedIds , columnOption , option . isReverse ) ; } ) ; return [ result , total ] ; } } return public async findChannelList ( ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = await connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . select ( 'count(*) as cnt, channelId' ) . groupBy ( 'channelId' ) ; return await this . promieRetry . run ( ( ) => { return queryBuilder . getRawMany ( ) ; } ) ; } return public async findGenreList ( ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = await connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . select ( 'count(*) as cnt, genre1 as genre' ) . where ( { genre1 : Not ( IsNull ( ) ) } ) . groupBy ( 'genre' ) ; return await this . promieRetry . run ( ( ) => { return queryBuilder . getRawMany ( ) ; } ) ; } return public async findOld ( ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . where ( { isProtected : false , } ) . orderBy ( 'recorded.startAt' , 'ASC' ) . orderBy ( 'recorded.id' , 'ASC' ) . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) . leftJoinAndSelect ( 'recorded.dropLogFile' , 'dropLogFile' ) . leftJoinAndSelect ( 'recorded.tags' , 'tags' ) ; const result = await this . promieRetry . run ( ( ) => { return queryBuilder . getOne ( ) ; } ) ; return typeof result === 'undefined' ? null : result ; } param reserveId return public async findReserveId ( reserveId ) { const connection = await this . op . getConnection ( ) ; const queryBuilder = connection . getRepository ( Recorded ) . createQueryBuilder ( 'recorded' ) . where ( { reserveId : reserveId } ) . leftJoinAndSelect ( 'recorded.videoFiles' , 'videoFiles' ) . leftJoinAndSelect ( 'recorded.thumbnails' , 'thumbnails' ) . leftJoinAndSelect ( 'recorded.dropLogFile' , 'dropLogFile' ) . leftJoinAndSelect ( 'recorded.tags' , 'tags' ) ; return await this . promieRetry . run ( ( ) => { return queryBuilder . getMany ( ) ; } ) ; } }