@@ -411,4 +411,72 @@ defmodule Exqlite.Sqlite3Test do
411411 assert { :row , [ 1 , "hello" ] } = Sqlite3 . step ( conn , statement )
412412 end
413413 end
414+
415+ describe "set_update_hook/2" do
416+ defmodule ChangeListener do
417+ use GenServer
418+
419+ def start_link ( { parent , name } ) ,
420+ do: GenServer . start_link ( __MODULE__ , { parent , name } )
421+
422+ def init ( { parent , name } ) , do: { :ok , { parent , name } }
423+
424+ def handle_info ( { _action , _db , _table , _row_id } = change , { parent , name } ) do
425+ send ( parent , { change , name } )
426+ { :noreply , { parent , name } }
427+ end
428+ end
429+
430+ setup do
431+ { :ok , path } = Temp . path ( )
432+ { :ok , conn } = Sqlite3 . open ( path )
433+ :ok = Sqlite3 . execute ( conn , "create table test(num integer)" )
434+
435+ on_exit ( fn ->
436+ Sqlite3 . close ( conn )
437+ File . rm ( path )
438+ end )
439+
440+ [ conn: conn , path: path ]
441+ end
442+
443+ test "can listen to data change notifications" , context do
444+ { :ok , listener_pid } = ChangeListener . start_link ( { self ( ) , :listener } )
445+ Sqlite3 . set_update_hook ( context . conn , listener_pid )
446+
447+ :ok = Sqlite3 . execute ( context . conn , "insert into test(num) values (10)" )
448+ :ok = Sqlite3 . execute ( context . conn , "insert into test(num) values (11)" )
449+ :ok = Sqlite3 . execute ( context . conn , "update test set num = 1000" )
450+ :ok = Sqlite3 . execute ( context . conn , "delete from test where num = 1000" )
451+
452+ assert_receive { { :insert , "main" , "test" , 1 } , _ } , 1000
453+ assert_receive { { :insert , "main" , "test" , 2 } , _ } , 1000
454+ assert_receive { { :update , "main" , "test" , 1 } , _ } , 1000
455+ assert_receive { { :update , "main" , "test" , 2 } , _ } , 1000
456+ assert_receive { { :delete , "main" , "test" , 1 } , _ } , 1000
457+ assert_receive { { :delete , "main" , "test" , 2 } , _ } , 1000
458+ end
459+
460+ test "only one pid can listen at a time" , context do
461+ { :ok , listener1_pid } = ChangeListener . start_link ( { self ( ) , :listener1 } )
462+ { :ok , listener2_pid } = ChangeListener . start_link ( { self ( ) , :listener2 } )
463+
464+ Sqlite3 . set_update_hook ( context . conn , listener1_pid )
465+ :ok = Sqlite3 . execute ( context . conn , "insert into test(num) values (10)" )
466+ assert_receive { { :insert , "main" , "test" , 1 } , :listener1 } , 1000
467+
468+ Sqlite3 . set_update_hook ( context . conn , listener2_pid )
469+ :ok = Sqlite3 . execute ( context . conn , "insert into test(num) values (10)" )
470+ assert_receive { { :insert , "main" , "test" , 2 } , :listener2 } , 1000
471+ refute_receive { { :insert , "main" , "test" , 2 } , :listener1 } , 1000
472+ end
473+
474+ test "notifications don't cross connections" , context do
475+ { :ok , listener_pid } = ChangeListener . start_link ( { self ( ) , :listener } )
476+ { :ok , new_conn } = Sqlite3 . open ( context . path )
477+ Sqlite3 . set_update_hook ( new_conn , listener_pid )
478+ :ok = Sqlite3 . execute ( context . conn , "insert into test(num) values (10)" )
479+ refute_receive { { :insert , "main" , "test" , 1 } , _ } , 1000
480+ end
481+ end
414482end
0 commit comments