epgsql_command.erl 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. %%% @doc Behaviour module for epgsql_sock commands.
  2. %%% @end
  3. %%% Copyright (C) 2017 - Sergey Prokhorov. All rights reserved.
  4. -module(epgsql_command).
  5. -export([init/2, execute/3, handle_message/5]).
  6. -export_type([command/0, state/0]).
  7. -type command() :: module().
  8. -type state() :: any().
  9. %% Initialize command's state. Called when command is received by epgsql_sock process.
  10. -callback init(any()) -> state().
  11. -type execute_return() ::
  12. {ok, epgsql_sock:pg_sock(), state()}
  13. | {send, epgsql_wire:packet_type(), PktData :: iodata(),
  14. epgsql_sock:pg_sock(), state()}
  15. | {send_multi, [{epgsql_wire:packet_type(), PktData :: iodata()}],
  16. epgsql_sock:pg_sock(), state()}
  17. | {stop, Reason :: any(), Response :: any(), epgsql_sock:pg_sock()}.
  18. %% Execute command. It should send commands to socket.
  19. %% May be called many times if 'handle_message' will return 'requeue'.
  20. -callback execute(epgsql_sock:pg_sock(), state()) -> execute_return().
  21. -type handle_message_return() ::
  22. {noaction, epgsql_sock:pg_sock()}
  23. %% Do nothing; remember changed state
  24. | {noaction, epgsql_sock:pg_sock(), state()}
  25. %% Add result to resultset (eg, `{ok, Count}' `{ok, Cols, Rows}', `{error, #error{}}'
  26. %% It may be returned many times for eg, `squery' with multiple
  27. %% queries separated by ';'
  28. %% See epgsql_sock:get_results/1
  29. | {add_result, Data :: any(), Notification :: any(), epgsql_sock:pg_sock(), state()}
  30. %% Add new row to current resultset;
  31. %% See epgsql_sock:get_rows/1
  32. | {add_row, tuple(), epgsql_sock:pg_sock(), state()}
  33. %% Finish command execution, reply to the client and go to next command
  34. | {finish, Result :: any(), Notification :: any(), epgsql_sock:pg_sock()}
  35. %% Stop `epgsql_sock' process
  36. | {stop, Reason :: any(), Response :: any(), epgsql_sock:pg_sock()}
  37. %% Call 'execute' and reschedule command.
  38. %% It's forbidden to call epgsql_sock:send from `handle_message'.
  39. %% If you need to do so, you should set some flag in state and
  40. %% reschedule command.
  41. %% See `epgsql_cmd_connect' for reference.
  42. | {requeue, epgsql_sock:pg_sock(), state()}
  43. %% Protocol synchronization error (eg, unexpected packet)
  44. %% Drop command queue and don't accept any command except 'sync'
  45. | {sync_required, Why :: any()}
  46. %% Unknown packet. Terminate `epgsql_sock' process
  47. | unknown.
  48. %% Handle incoming packet
  49. -callback handle_message(Type :: byte(), Payload :: binary() | epgsql:query_error(),
  50. epgsql_sock:pg_sock(), state()) -> handle_message_return().
  51. -spec init(command(), any()) -> state().
  52. init(Command, Args) ->
  53. Command:init(Args).
  54. -spec execute(command(), epgsql_sock:pg_sock(), state()) -> execute_return().
  55. execute(Command, PgSock, CmdState) ->
  56. Command:execute(PgSock, CmdState).
  57. -spec handle_message(command(), Type :: byte(), Payload :: binary() | epgsql:query_error(),
  58. epgsql_sock:pg_sock(), state()) -> handle_message_return().
  59. handle_message(Command, Type, Payload, PgSock, State) ->
  60. Command:handle_message(Type, Payload, PgSock, State).