/**
 * React Native SQLite Demo
 * Copyright (c) 2018-2020 Bruce Lefebvre <bruce@brucelefebvre.com>
 * https://github.com/blefebvre/react-native-sqlite-demo/blob/master/LICENSE
 */ import SQLite from "react-native-sqlite-storage" ; import { DatabaseInitialization } from "./DatabaseInitialization" ; import { List } from "../types/List" ; import { ListItem } from "../types/ListItem" ; import { DATABASE } from "./Constants" ; import { DropboxDatabaseSync } from "../sync/dropbox/DropboxDatabaseSync" ; import { AppState , AppStateStatus } from "react-native" ; export interface Database { createList ( newListTitle ) : Promise < void > ; addListItem ( text , list ) : Promise < void > ; getAllLists ( ) : Promise < List [ ] > ; getListItems ( list , doneItemsLast ) : Promise < ListItem [ ] > ; updateListItem ( listItem ) : Promise < void > ; deleteList ( list ) : Promise < void > ; } let databaseInstance ; const databaseSync = new DropboxDatabaseSync ( ) ; async function createList ( newListTitle ) { return getDatabase ( ) . then ( ( db ) => db . executeSql ( "INSERT INTO List (title) VALUES (?);" , [ newListTitle ] ) ) . then ( ( [ results ] ) => { const { insertId } = results ; console . log ( `[db] Added list with title: "${ newListTitle }"! InsertId: ${ insertId }` ) ; return databaseSync . upload ( ) ; } ) ; } async function getAllLists ( ) { console . log ( "[db] Fetching lists from the db..." ) ; return getDatabase ( ) . then ( ( db ) => db . executeSql ( "SELECT list_id as id, title FROM List ORDER BY id DESC;" ) ) . then ( ( [ results ] ) => { if ( results === undefined ) { return [ ] ; } const count = results . rows . length ; const lists = [ ] ; for ( let i = 0 ; i < count ; i ++ ) { const row = results . rows . item ( i ) ; const { title , id } = row ; console . log ( `[db] List title: ${ title }, id: ${ id }` ) ; lists . push ( { id , title } ) ; } return lists ; } ) ; } async function addListItem ( text , list ) { if ( list === undefined ) { return Promise . reject ( Error ( `Could not add item to undefined list.` ) ) ; } return getDatabase ( ) . then ( ( db ) => db . executeSql ( "INSERT INTO ListItem (text, list_id) VALUES (?, ?);" , [ text , list . id ] ) ) . then ( ( [ results ] ) => { console . log ( `[db] ListItem with "${ text }" created successfully with id: ${ results . insertId }` ) ; return databaseSync . upload ( ) ; } ) ; } async function getListItems ( list , orderByDone = false ) { if ( list === undefined ) { return Promise . resolve ( [ ] ) ; } return getDatabase ( ) . then ( ( db ) => db . executeSql ( `SELECT item_id as id, text, done FROM ListItem WHERE list_id = ? ${ orderByDone ? "ORDER BY done" : "" };` , [ list . id ] ) ) . then ( ( [ results ] ) => { if ( results === undefined ) { return [ ] ; } const count = results . rows . length ; const listItems = [ ] ; for ( let i = 0 ; i < count ; i ++ ) { const row = results . rows . item ( i ) ; const { text , done : doneNumber , id } = row ; const done = doneNumber === 1 ? true : false ; console . log ( `[db] List item text: ${ text }, done? ${ done } id: ${ id }` ) ; listItems . push ( { id , text , done } ) ; } console . log ( `[db] List items for list "${ list . title }":` , listItems ) ; return listItems ; } ) ; } async function updateListItem ( listItem ) { const doneNumber = listItem . done ? 1 : 0 ; return getDatabase ( ) . then ( ( db ) => db . executeSql ( "UPDATE ListItem SET text = ?, done = ? WHERE item_id = ?;" , [ listItem . text , doneNumber , listItem . id , ] ) ) . then ( ( [ results ] ) => { console . log ( `[db] List item with id: ${ listItem . id } updated.` ) ; return databaseSync . upload ( ) ; } ) ; } async function deleteList ( list ) { console . log ( `[db] Deleting list titled: "${ list . title }" with id: ${ list . id }` ) ; return getDatabase ( ) . then ( ( db ) => { return db . executeSql ( "DELETE FROM ListItem WHERE list_id = ?;" , [ list . id ] ) . then ( ( ) => db ) ; } ) . then ( ( db ) => db . executeSql ( "DELETE FROM List WHERE list_id = ?;" , [ list . id ] ) ) . then ( ( ) => { console . log ( `[db] Deleted list titled: "${ list . title }"!` ) ; return databaseSync . upload ( ) ; } ) ; } async function getDatabase ( ) { if ( databaseInstance !== undefined ) { return Promise . resolve ( databaseInstance ) ; } return open ( ) ; } async function open ( ) { SQLite . DEBUG ( true ) ; SQLite . enablePromise ( true ) ; if ( databaseInstance ) { console . log ( "[db] Database is already open: returning the existing instance" ) ; return databaseInstance ; } const db = await SQLite . openDatabase ( { name : DATABASE . FILE_NAME , location : "default" , } ) ; console . log ( "[db] Database open!" ) ; const databaseInitialization = new DatabaseInitialization ( ) ; await databaseInitialization . updateDatabaseTables ( db ) ; databaseInstance = db ; return db ; } async function close ( ) { if ( databaseInstance === undefined ) { console . log ( "[db] No need to close DB again - it's already closed" ) ; return ; } const status = await databaseInstance . close ( ) ; console . log ( "[db] Database closed." ) ; databaseInstance = undefined ; } let appState = "active" ; console . log ( "[db] Adding listener to handle app state changes" ) ; AppState . addEventListener ( "change" , handleAppStateChange ) ; function handleAppStateChange ( nextAppState ) { if ( appState === "active" && nextAppState . match ( /inactive|background/ ) ) { console . log ( "[db] App has gone to the background - closing DB connection." ) ; close ( ) ; } appState = nextAppState ; } export const sqliteDatabase = { createList , addListItem , getAllLists , getListItems , updateListItem , deleteList , } ;