--[[----------------------------------------------------------------------------

WFRxDatabaseTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2020 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

local Rx = require "Rx"

	-- WF.core.os
local KSPathUtils = require "KSPathUtils"
local WFFileUtils = require "WFFileUtils"

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.sqlite
local WFRxDatabase = require 'WFRxDatabase'

--============================================================================--

local WFRxDatabaseTest = {}

--------------------------------------------------------------------------------

local rxDatabase

--------------------------------------------------------------------------------

local function tearDown()

	if not rxDatabase then
		return Rx.Observable.just()
	end

	local oldRxDatabase = rxDatabase
	
	local closeOb = rxDatabase:haltAndDelete()
		:tapOnCompleted( function()
			oldRxDatabase:close()
		end )
		
	rxDatabase = nil
	
	return closeOb
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestLoadScript( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	rxTest:expectSingleValue(
		rxDatabase:DEBUG_tableNames(),
		{ notifications = true }
	)
	
	rxTest:expectSingleValue(
		rxDatabase:DEBUG_indexInfos(),
		{ 
			notifications = {
				notifications_id = "CREATE INDEX notifications_id ON notifications( id )",
				notifications_time = "CREATE INDEX notifications_time ON notifications( time )",
			} 
		}
	)
	
	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT COUNT(*) FROM notifications]]
	} )
	
	queryObserve:expectData( { { 0 } } )
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestBulkInsert( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', {{ 'id3', '2011-01-17T18:15:04.543Z', 0 }} ),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
			{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestBulkInsertOrReplace( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )
	
	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsertOrReplace( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:bulkInsertOrReplace( 'notifications', {{ 'id2', '2012-02-17T18:15:04.543Z', 1 }} ),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 1 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestUpdate( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsertOrReplace( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:update( 'notifications', 
			{
				values = { read = 1, time = '2012-01-17T18:15:04.543Z' },
				condition = "WHERE id = ?",
				"id2"
			}),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-01-17T18:15:04.543Z', 1 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestBulkUpdate( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
		{ 'id3', '2013-02-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsertOrReplace( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id3', '2013-02-17T18:15:04.543Z', 0 },
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:bulkUpdate( 'notifications', 
			{
				{
					values = { read = 1, time = '2011-01-17T18:15:04.543Z' },
					condition = "WHERE id = ?",
					"id1"
				},
				{
					values = { read = 1, time = '2012-01-17T18:15:04.543Z' },
					condition = "WHERE id = ?",
					"id2"
				}
			} ),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id3', '2013-02-17T18:15:04.543Z', 0 },
			{ 'id2', '2012-01-17T18:15:04.543Z', 1 },
			{ 'id1', '2011-01-17T18:15:04.543Z', 1 },
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestDeleteWhereIn( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
		{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
			{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:deleteWhereIn( 'notifications', 'id', { 'id1', 'id2' } ),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestDeleteFromWhere( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
		{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
			{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:deleteFromWhere( 'notifications', 'WHERE time < ?', { '2011-02-17T18:15:04.543Z' } ),
		':ignore:'
	)
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		}
	)
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestClearTable( rxTest )

	rxTest:setTimeLimit( 5 )

	rxDatabase = WFRxDatabase( ':memory:', 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
		{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', rows ),
		':ignore:'
	)

	local queryObserve = rxTest:observe( rxDatabase:query{
		sql = [[SELECT id, time, read FROM notifications ORDER BY time DESC]]
	} )
	
	queryObserve:expectData( 
		{
			{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
			{ 'id1', '2011-02-17T18:15:04.543Z', 0 },
			{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
		}
	)
	
	rxTest:expectSingleValue(
		rxDatabase:clearTable( 'notifications' ),
		':ignore:'
	)
	
	queryObserve:expectData( {} )
	
end

--------------------------------------------------------------------------------

function WFRxDatabaseTest.rxTestSchemaUpgrade( rxTest )

	rxTest:setTimeLimit( 240 )

	local path = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'carouselDocuments' ), 'rxTestSchemaUpgrade.notifydb' )

	WFFileUtils.deleteFile( path )

	rxDatabase = WFRxDatabase( path, 'RxTestNotifications.lua' )

	local rows = {
		{ 'id1', '2011-02-17T18:15:04.543Z', 1 },
		{ 'id2', '2012-02-17T18:15:04.543Z', 0 },
		{ 'id3', '2011-01-17T18:15:04.543Z', 0 }
	}

	rxTest:expectSingleValue(
		rxDatabase:bulkInsert( 'notifications', rows ),
		':ignore:'
	)

	rxTest:waitFor( rxDatabase:halt() )
	rxDatabase.close()

	rxDatabase = WFRxDatabase( path, 'RxTestNotifications_v1_1.lua', '1.1' )

	rxTest:expectSingleValue( rxDatabase:query{
			sql = [[SELECT id, time, read, visited, needsUpdateOnANS FROM notifications ORDER BY id ASC]],
			queryOnce = true
		}
		:take( 1 ),
		{
			{ 'id1', '2011-02-17T18:15:04.543Z', 1, 0, 0 },
			{ 'id2', '2012-02-17T18:15:04.543Z', 0, 0, 0 },
			{ 'id3', '2011-01-17T18:15:04.543Z', 0, 0, 0 }
		} )
end

--------------------------------------------------------------------------------
		
for k, v in pairs( WFRxDatabaseTest ) do
	if string.match( k, "^rxTest" ) then
		WFRxDatabaseTest[ k ] = function( rxTest )
			rxTest:finally( tearDown )
			v( rxTest )
		end
	end
end

--------------------------------------------------------------------------------

return WFRxTestCase.wrapSuite( 'WFRxDatabaseTest', WFRxDatabaseTest )
