import ChannelId from '../../ChannelId' ; import * as BigNumber from 'bignumber.js' ; import { PaymentChannel , PaymentChannelJSON } from '../../PaymentChannel' ; import EngineSqlite from './EngineSqlite' ; import AbstractChannelsDatabase from '../AbstractChannelsDatabase' ; export default class SqliteChannelsDatabase extends AbstractChannelsDatabase < EngineSqlite > { async save ( paymentChannel ) { return this . engine . exec ( async ( client ) => { await client . run ( 'INSERT INTO channel("channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil") ' + 'VALUES ($channelId, $kind, $sender, $receiver, $value, $spent, $state, $tokenContract, $settlementPeriod, $settlingUntil)' , { $channelId : paymentChannel . channelId , $kind : this . kind , $sender : paymentChannel . sender , $receiver : paymentChannel . receiver , $value : paymentChannel . value . toString ( ) , $spent : paymentChannel . spent . toString ( ) , $state : paymentChannel . state , $tokenContract : paymentChannel . tokenContract , $settlementPeriod : paymentChannel . settlementPeriod , $settlingUntil : paymentChannel . settlingUntil . toString ( ) } ) ; } ) ; } async firstById ( channelId ) { return this . engine . exec ( async ( client ) => { let raw = await client . get < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel ' + 'WHERE "channelId" = $channelId LIMIT 1' , { $channelId : channelId . toString ( ) } ) ; return raw ? this . inflatePaymentChannel ( raw ) : null ; } ) ; } async spend ( channelId , spent ) { return this . engine . exec ( async ( client ) => { return client . run ( 'UPDATE channel SET spent = $spent WHERE "channelId" = $channelId' , { $channelId : channelId . toString ( ) , $spent : spent . toString ( ) } ) ; } ) ; } async deposit ( channelId , value ) { return this . engine . exec ( async ( client ) => { let channel = await this . firstById ( channelId ) ; if ( ! channel ) { throw new Error ( 'Channel not found.' ) ; } const newValue = channel . value . add ( value ) ; return client . run ( 'UPDATE channel SET value = $value WHERE "channelId" = $channelId' , { $channelId : channelId . toString ( ) , $value : newValue . toString ( ) } ) ; } ) ; } async all ( ) { return this . engine . exec ( async ( client ) => { let raw = await client . all < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel' ) ; return this . inflatePaymentChannels ( raw ) ; } ) ; } async allOpen ( ) { return this . engine . exec ( async ( client ) => { let raw = await client . all < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel ' + 'WHERE state = 0' ) ; let channels = await this . inflatePaymentChannels ( raw ) ; return this . filterByState ( 0 , channels ) ; } ) ; } async findUsable ( sender , receiver , amount ) { return this . engine . exec ( async ( client ) => { let raw = await client . get < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel ' + 'WHERE sender = $sender AND receiver = $receiver AND value >= spent + $amount AND state = 0' , { $sender : sender , $receiver : receiver , $amount : amount . toString ( ) } ) ; if ( raw ) { let channel = await this . inflatePaymentChannel ( raw ) ; if ( channel && channel . state === 0 ) { return channel ; } return null ; } else { return null ; } } ) ; } async findBySenderReceiver ( sender , receiver ) { return this . engine . exec ( async ( client ) => { let rows = await client . all < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel ' + 'WHERE sender = $sender AND receiver = $receiver' , { $sender : sender , $receiver : receiver } ) ; return this . inflatePaymentChannels ( rows ) ; } ) ; } async findBySenderReceiverChannelId ( sender , receiver , channelId ) { return this . engine . exec ( async ( client ) => { let row = await client . get < PaymentChannelJSON > ( 'SELECT "channelId", kind, sender, receiver, value, spent, state, "tokenContract", "settlementPeriod", "settlingUntil" FROM channel ' + 'WHERE sender = $sender AND receiver = $receiver AND "channelId" = $channelId LIMIT 1' , { $sender : sender , $receiver : receiver , $channelId : channelId . toString ( ) } ) ; return row ? this . inflatePaymentChannel ( row ) : null ; } ) ; } async updateState ( channelId , state ) { return this . engine . exec ( async ( client ) => { return client . run ( 'UPDATE channel SET state = $state WHERE "channelId" = $channelId' , { $state : state , $channelId : channelId . toString ( ) } ) ; } ) ; } async updateSettlingUntil ( channelId , settlingUntil ) { return this . engine . exec ( async ( client ) => { return client . run ( 'UPDATE channel SET "settlingUntil" = $settlingUntil WHERE "channelId" = $channelId' , { $settlingUntil : settlingUntil . toString ( ) , $channelId : channelId . toString ( ) } ) ; } ) ; } }