diff --git a/.formatter.exs b/.formatter.exs index 33ad900..6269b73 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,4 @@ # Used by "mix format" [ - inputs: ["mix.exs", "config/*.exs", "example.exs"], - subdirectories: ["apps/*"] + inputs: ["mix.exs", "example.exs", "{config,lib,test}/**/*.{ex,exs}", ".formatter.exs"] ] diff --git a/.github/workflows/nightly-integration.yml b/.github/workflows/nightly-integration.yml index 738af33..c59421f 100644 --- a/.github/workflows/nightly-integration.yml +++ b/.github/workflows/nightly-integration.yml @@ -10,9 +10,6 @@ jobs: integration_test: name: Integration Tests runs-on: ubuntu-latest - defaults: - run: - working-directory: ./apps/main_app env: MIX_ENV: test strategy: diff --git a/.gitignore b/.gitignore index dd7ba8f..728a1b9 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ erl_crash.dump # expert LSP .expert/ + +# elixir LSP +.elixir_ls/ diff --git a/README.md b/README.md index 269da35..d075286 100644 --- a/README.md +++ b/README.md @@ -11,22 +11,22 @@ Either start the application with iex console: iex -S mix run --no-halt ``` -Or use [example.exs](./example.exs) script to quickly startup PgSubscriber with FilePublisher: +Or use [example.exs](./example.exs) script to quickly startup Subscribers.Postgres with Publishers.File: ```bash iex -S mix run example.exs ``` -`PgSubscriber` requires running Postgres database. Checkout [postgres example](./apps/pg_subscriber/example/) for a quick setup. -Make sure that `FilePublisher` points to the existing location of your system (file does not need to exist, but parent +`Subscribers.Postgres` requires running Postgres database. Checkout [postgres example](./apps/pg_subscriber/example/) for a quick setup. +Make sure that `Publishers.File` points to the existing location of your system (file does not need to exist, but parent directories must). Finally, connect to a subscriber and execute INSERT/UPDATE/DELETE statement. The statement will be logged and saved by all publishers (in case of -FilePublisher the statement is saved to a file). +Publishers.File the statement is saved to a file). ## Subscribers -### PgSubscriber :rocket: +### Subscribers.Postgres :rocket: Subscriber for Postgres database. The subscriber creates logical replication connection to Postgres database. The replication connection makes database to push replication messages to the subscriber (push-based communication). @@ -52,7 +52,7 @@ connection makes database to push replication messages to the subscriber (push-b ## Publishers -### FilePublisher :rocket: +### Publishers.File :rocket: Publisher storing replication messages to files. #### Features diff --git a/apps/core/.formatter.exs b/apps/core/.formatter.exs deleted file mode 100644 index d2cda26..0000000 --- a/apps/core/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/apps/core/.gitignore b/apps/core/.gitignore deleted file mode 100644 index 17ce19a..0000000 --- a/apps/core/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -core-*.tar - -# Temporary files, for example, from tests. -/tmp/ diff --git a/apps/core/README.md b/apps/core/README.md deleted file mode 100644 index 4ea34af..0000000 --- a/apps/core/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Core - -**Core** is the shared library for defining the internal data representation and contracts used across the replication system. It provides: - -- Canonical schemas for replication messages received from databases (e.g., PostgreSQL, MySQL). -- Contracts (interfaces) that publisher apps can implement to handle replicated messages. -- Utilities for encoding, decoding, and working with messages in a uniform way. - -## Installation - -This app is designed to be used within the umbrella. - -## Usage - -### Using the message structs - -```elixir -alias Core.Messages.Insert - -%Insert{ - table: "users", - columns: %{"id" => 1, "name" => "Alice"} -} -``` - -### Implementing the publisher contract -In your custom publisher app, you can implement the Core.PublisherContract behaviour: -```elixir -defmodule MyCustomPublisher do - @behaviour Core.PublisherContract - - @impl true - def handle_message(message) do - # Do something with the message, e.g., send to a queue, update a cache, or update a database - IO.inspect(message, label: "Received replication message") - :ok - end -end -``` diff --git a/apps/core/lib/core.ex b/apps/core/lib/core.ex deleted file mode 100644 index 1c53942..0000000 --- a/apps/core/lib/core.ex +++ /dev/null @@ -1,18 +0,0 @@ -defmodule Core do - @moduledoc """ - Documentation for `Core`. - """ - - @doc """ - Hello world. - - ## Examples - - iex> Core.hello() - :world - - """ - def hello do - :world - end -end diff --git a/apps/core/mix.exs b/apps/core/mix.exs deleted file mode 100644 index 3a01864..0000000 --- a/apps/core/mix.exs +++ /dev/null @@ -1,33 +0,0 @@ -defmodule Core.MixProject do - use Mix.Project - - def project do - [ - app: :core, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.18", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger] - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - # {:dep_from_hexpm, "~> 0.3.0"}, - # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, - # {:sibling_app_in_umbrella, in_umbrella: true} - ] - end -end diff --git a/apps/core/test/core_test.exs b/apps/core/test/core_test.exs deleted file mode 100644 index 661aff1..0000000 --- a/apps/core/test/core_test.exs +++ /dev/null @@ -1,8 +0,0 @@ -defmodule CoreTest do - use ExUnit.Case - doctest Core - - test "greets the world" do - assert Core.hello() == :world - end -end diff --git a/apps/core/test/test_helper.exs b/apps/core/test/test_helper.exs deleted file mode 100644 index 869559e..0000000 --- a/apps/core/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() diff --git a/apps/file_publisher/.formatter.exs b/apps/file_publisher/.formatter.exs deleted file mode 100644 index d2cda26..0000000 --- a/apps/file_publisher/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/apps/file_publisher/.gitignore b/apps/file_publisher/.gitignore deleted file mode 100644 index 2c0df54..0000000 --- a/apps/file_publisher/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -file_publisher-*.tar - -# Temporary files, for example, from tests. -/tmp/ diff --git a/apps/file_publisher/README.md b/apps/file_publisher/README.md deleted file mode 100644 index 804f1f2..0000000 --- a/apps/file_publisher/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# FilePublisher - -**FilePublisher** is a library responsible for persisting replicated database change events to the filesystem. diff --git a/apps/file_publisher/mix.exs b/apps/file_publisher/mix.exs deleted file mode 100644 index 0a2741a..0000000 --- a/apps/file_publisher/mix.exs +++ /dev/null @@ -1,31 +0,0 @@ -defmodule FilePublisher.MixProject do - use Mix.Project - - def project do - [ - app: :file_publisher, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.18", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger] - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - {:core, in_umbrella: true} - ] - end -end diff --git a/apps/file_publisher/test/test_helper.exs b/apps/file_publisher/test/test_helper.exs deleted file mode 100644 index 869559e..0000000 --- a/apps/file_publisher/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() diff --git a/apps/main_app/.formatter.exs b/apps/main_app/.formatter.exs deleted file mode 100644 index d2cda26..0000000 --- a/apps/main_app/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/apps/main_app/.gitignore b/apps/main_app/.gitignore deleted file mode 100644 index 329b773..0000000 --- a/apps/main_app/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -main_app-*.tar - -# Temporary files, for example, from tests. -/tmp/ diff --git a/apps/main_app/README.md b/apps/main_app/README.md deleted file mode 100644 index 629b26b..0000000 --- a/apps/main_app/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# MainApp - -MainApp is the orchestrator that runs configured `Subscriber` and `Publisher`. - -If everything is properly configured, run the application: -```bash -mix run --no-halt -``` diff --git a/apps/main_app/mix.exs b/apps/main_app/mix.exs deleted file mode 100644 index f830dd7..0000000 --- a/apps/main_app/mix.exs +++ /dev/null @@ -1,39 +0,0 @@ -defmodule MainApp.MixProject do - use Mix.Project - - def project do - [ - app: :main_app, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.18", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger], - mod: {MainApp, []} - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - # Core - {:core, in_umbrella: true}, - - # Subscribers - {:pg_subscriber, in_umbrella: true}, - - # Publishers - {:file_publisher, in_umbrella: true} - ] - end -end diff --git a/apps/pg_subscriber/.formatter.exs b/apps/pg_subscriber/.formatter.exs deleted file mode 100644 index d2cda26..0000000 --- a/apps/pg_subscriber/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/apps/pg_subscriber/.gitignore b/apps/pg_subscriber/.gitignore deleted file mode 100644 index 071657a..0000000 --- a/apps/pg_subscriber/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -pg_subscriptor-*.tar - -# Temporary files, for example, from tests. -/tmp/ diff --git a/apps/pg_subscriber/README.md b/apps/pg_subscriber/README.md deleted file mode 100644 index 2493296..0000000 --- a/apps/pg_subscriber/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# PgSubscriptor - -## Howw to run -Currently the `pg_subscriptor` app is connecting to the Postgres instance running on `127.0.0.1:5432`. It expects that -the database is `postgres`, user `postgres`, and password `postgres`. You need to allow `replication` connection in -`pg_hba` file (checkout [example](./example) directory). - -The Postgres instance must be configured with `wal_level >= logical` and you need to install -[wal2json plugin](https://github.com/eulerto/wal2json) on the instance server. Note, you need to install the plugin -for the Postgres version 16. - -Upon start, the client opens connection to the Postgres database, configures so called `REPLICATION SLOT`, starts the -replication and listens on incoming changes. Simply execute insert/delete statement (you can use [pg_randomizer](https://github.com/revolko/pg-randomizer)) and incoming changes will be printed to the console in json format. - - -## Discussion -I am not sure if `wal2json` is the best plugin to use. By default, Postgres has `pgoutput` plugin for replication, but that yeilded not readable binary result. If we are able to figure out the binary encoding, `pgoutput` might be more efficient than using `json` format. diff --git a/apps/pg_subscriber/mix.exs b/apps/pg_subscriber/mix.exs deleted file mode 100644 index 2dc4540..0000000 --- a/apps/pg_subscriber/mix.exs +++ /dev/null @@ -1,32 +0,0 @@ -defmodule PgSubscriber.MixProject do - use Mix.Project - - def project do - [ - app: :pg_subscriber, - version: "0.1.0", - build_path: "../../_build", - config_path: "../../config/config.exs", - deps_path: "../../deps", - lockfile: "../../mix.lock", - elixir: "~> 1.18", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger] - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - {:core, in_umbrella: true}, - {:postgrex, "~> 0.20.0"} - ] - end -end diff --git a/apps/pg_subscriber/test/assets/pg_dump.sql b/apps/pg_subscriber/test/assets/pg_dump.sql deleted file mode 100644 index e1f26ee..0000000 --- a/apps/pg_subscriber/test/assets/pg_dump.sql +++ /dev/null @@ -1,258 +0,0 @@ --- --- PostgreSQL database dump --- - --- Dumped from database version 17.5 (Debian 17.5-1.pgdg120+1) --- Dumped by pg_dump version 17.5 (Debian 17.5-1.pgdg120+1) - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET idle_in_transaction_session_timeout = 0; -SET transaction_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); -SET check_function_bodies = false; -SET xmloption = content; -SET client_min_messages = warning; -SET row_security = off; - -SET default_tablespace = ''; - -SET default_table_access_method = heap; - --- --- Name: distributors; Type: TABLE; Schema: public; Owner: postgres --- - -CREATE TABLE public.distributors ( - did integer NOT NULL, - name character varying(255) NOT NULL -); - -ALTER TABLE ONLY public.distributors REPLICA IDENTITY FULL; - - -ALTER TABLE public.distributors OWNER TO postgres; - --- --- Name: films; Type: TABLE; Schema: public; Owner: postgres --- - -CREATE TABLE public.films ( - code integer NOT NULL, - title character varying(255) NOT NULL -); - -ALTER TABLE ONLY public.films REPLICA IDENTITY FULL; - - -ALTER TABLE public.films OWNER TO postgres; - --- --- Name: test_foreign; Type: TABLE; Schema: public; Owner: postgres --- - -CREATE TABLE public.test_foreign ( - id integer NOT NULL, - test_primary_id integer NOT NULL -); - - -ALTER TABLE public.test_foreign OWNER TO postgres; - --- --- Name: test_foreign_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres --- - -CREATE SEQUENCE public.test_foreign_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - -ALTER SEQUENCE public.test_foreign_id_seq OWNER TO postgres; - --- --- Name: test_foreign_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres --- - -ALTER SEQUENCE public.test_foreign_id_seq OWNED BY public.test_foreign.id; - - --- --- Name: test_primary; Type: TABLE; Schema: public; Owner: postgres --- - -CREATE TABLE public.test_primary ( - first_name character varying(255), - last_name character varying(255) NOT NULL, - id integer NOT NULL -); - - -ALTER TABLE public.test_primary OWNER TO postgres; - --- --- Name: test_primary_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres --- - -CREATE SEQUENCE public.test_primary_id_seq - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - - -ALTER SEQUENCE public.test_primary_id_seq OWNER TO postgres; - --- --- Name: test_primary_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres --- - -ALTER SEQUENCE public.test_primary_id_seq OWNED BY public.test_primary.id; - - --- --- Name: test_foreign id; Type: DEFAULT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.test_foreign ALTER COLUMN id SET DEFAULT nextval('public.test_foreign_id_seq'::regclass); - - --- --- Name: test_primary id; Type: DEFAULT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.test_primary ALTER COLUMN id SET DEFAULT nextval('public.test_primary_id_seq'::regclass); - - --- --- Data for Name: distributors; Type: TABLE DATA; Schema: public; Owner: postgres --- - -INSERT INTO public.distributors (did, name) VALUES (55, 'f033ab37c30201f73f142449d037028d'); -INSERT INTO public.distributors (did, name) VALUES (11, 'ea5d2f1c4608232e07d3aa3d998e5135'); -INSERT INTO public.distributors (did, name) VALUES (23, '17e62166fc8586dfa4d1bc0e1742c08b'); -INSERT INTO public.distributors (did, name) VALUES (1, 'e4da3b7fbbce2345d7772b0674a318d5'); -INSERT INTO public.distributors (did, name) VALUES (94, 'e2ef524fbf3d9fe611d5a8e90fefdc9c'); -INSERT INTO public.distributors (did, name) VALUES (10, 'a1d0c6e83f027327d8461063f4ac58a6'); -INSERT INTO public.distributors (did, name) VALUES (17, '26657d5ff9020d2abefe558796b99584'); -INSERT INTO public.distributors (did, name) VALUES (33, 'ac627ab1ccbdb62ec96e702f07f6425b'); -INSERT INTO public.distributors (did, name) VALUES (46, '8e296a067a37563370ded05f5a3bf3ec'); -INSERT INTO public.distributors (did, name) VALUES (29, 'c7e1249ffc03eb9ded908c236bd1996d'); - - --- --- Data for Name: films; Type: TABLE DATA; Schema: public; Owner: postgres --- - -INSERT INTO public.films (code, title) VALUES (74, 'd3d9446802a44259755d38e6d163e820'); -INSERT INTO public.films (code, title) VALUES (64, 'e2ef524fbf3d9fe611d5a8e90fefdc9c'); -INSERT INTO public.films (code, title) VALUES (36, 'ac627ab1ccbdb62ec96e702f07f6425b'); -INSERT INTO public.films (code, title) VALUES (71, '34173cb38f07f89ddbebc2ac9128303f'); -INSERT INTO public.films (code, title) VALUES (31, '093f65e080a295f8076b1c5722a46aa2'); -INSERT INTO public.films (code, title) VALUES (85, '19ca14e7ea6328a42e0eb13d585e4c22'); -INSERT INTO public.films (code, title) VALUES (74, '98f13708210194c475687be6106a3b84'); -INSERT INTO public.films (code, title) VALUES (69, 'f899139df5e1059396431415e770c6dd'); -INSERT INTO public.films (code, title) VALUES (65, '6364d3f0f495b6ab9dcf8d3b5c6e0b01'); -INSERT INTO public.films (code, title) VALUES (38, '8f14e45fceea167a5a36dedd4bea2543'); - - --- --- Data for Name: test_foreign; Type: TABLE DATA; Schema: public; Owner: postgres --- - - - --- --- Data for Name: test_primary; Type: TABLE DATA; Schema: public; Owner: postgres --- - -INSERT INTO public.test_primary (first_name, last_name, id) VALUES ('ja', 'on', 1); - - --- --- Name: test_foreign_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres --- - -SELECT pg_catalog.setval('public.test_foreign_id_seq', 1, false); - - --- --- Name: test_primary_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres --- - -SELECT pg_catalog.setval('public.test_primary_id_seq', 1, true); - - --- --- Name: test_foreign test_foreign_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.test_foreign - ADD CONSTRAINT test_foreign_pkey PRIMARY KEY (id); - - --- --- Name: test_primary test_primary_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.test_primary - ADD CONSTRAINT test_primary_pkey PRIMARY KEY (id); - - --- --- Name: test_foreign test_foreign_test_primary_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.test_foreign - ADD CONSTRAINT test_foreign_test_primary_id_fkey FOREIGN KEY (test_primary_id) REFERENCES public.test_primary(id) ON DELETE CASCADE; - - --- --- Name: postgrex_example; Type: PUBLICATION; Schema: -; Owner: postgres --- - -CREATE PUBLICATION postgrex_example WITH (publish = 'insert, update, delete, truncate'); - - -ALTER PUBLICATION postgrex_example OWNER TO postgres; - --- --- Name: postgrex_example distributors; Type: PUBLICATION TABLE; Schema: public; Owner: postgres --- - -ALTER PUBLICATION postgrex_example ADD TABLE ONLY public.distributors; - - --- --- Name: postgrex_example films; Type: PUBLICATION TABLE; Schema: public; Owner: postgres --- - -ALTER PUBLICATION postgrex_example ADD TABLE ONLY public.films; - - --- --- Name: postgrex_example test_foreign; Type: PUBLICATION TABLE; Schema: public; Owner: postgres --- - -ALTER PUBLICATION postgrex_example ADD TABLE ONLY public.test_foreign; - - --- --- Name: postgrex_example test_primary; Type: PUBLICATION TABLE; Schema: public; Owner: postgres --- - -ALTER PUBLICATION postgrex_example ADD TABLE ONLY public.test_primary; - - --- --- PostgreSQL database dump complete --- - diff --git a/apps/pg_subscriber/test/test_helper.exs b/apps/pg_subscriber/test/test_helper.exs deleted file mode 100644 index 869559e..0000000 --- a/apps/pg_subscriber/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() diff --git a/example.exs b/example.exs index c82cd1d..de4bb14 100644 --- a/example.exs +++ b/example.exs @@ -1,6 +1,6 @@ DynamicSupervisor.start_child( MainApp.DynamicSupervisor, - {PgSubscriber, + {Subscribers.Postgres, [ repl: [host: "localhost", username: "postgres", database: "postgres", password: "postgres"], handler: [] @@ -9,5 +9,5 @@ DynamicSupervisor.start_child( DynamicSupervisor.start_child( MainApp.DynamicSupervisor, - {FilePublisher, ["/tmp/replication.log"]} + {Publishers.File, ["/tmp/replication.log"]} ) diff --git a/apps/pg_subscriber/example/docker-compose.yml b/example/docker-compose.yml similarity index 100% rename from apps/pg_subscriber/example/docker-compose.yml rename to example/docker-compose.yml diff --git a/apps/pg_subscriber/example/init.sql b/example/init.sql similarity index 100% rename from apps/pg_subscriber/example/init.sql rename to example/init.sql diff --git a/apps/pg_subscriber/example/pg_hba.conf b/example/pg_hba.conf similarity index 100% rename from apps/pg_subscriber/example/pg_hba.conf rename to example/pg_hba.conf diff --git a/apps/pg_subscriber/example/postgresql.conf b/example/postgresql.conf similarity index 100% rename from apps/pg_subscriber/example/postgresql.conf rename to example/postgresql.conf diff --git a/lib/core/core.ex b/lib/core/core.ex new file mode 100644 index 0000000..3913ac2 --- /dev/null +++ b/lib/core/core.ex @@ -0,0 +1,8 @@ +defmodule Core do + @moduledoc """ + The root module of the Core lib. + Used to define boundary. + """ + use Boundary, + exports: [Messages.{Column, Insert, Update, Delete, MessageProtocol}, PublisherContract] +end diff --git a/apps/core/lib/core/messages/column.ex b/lib/core/messages/column.ex similarity index 100% rename from apps/core/lib/core/messages/column.ex rename to lib/core/messages/column.ex diff --git a/apps/core/lib/core/messages/delete.ex b/lib/core/messages/delete.ex similarity index 100% rename from apps/core/lib/core/messages/delete.ex rename to lib/core/messages/delete.ex diff --git a/apps/core/lib/core/messages/insert.ex b/lib/core/messages/insert.ex similarity index 100% rename from apps/core/lib/core/messages/insert.ex rename to lib/core/messages/insert.ex diff --git a/apps/core/lib/core/messages/message_protocol.ex b/lib/core/messages/message_protocol.ex similarity index 100% rename from apps/core/lib/core/messages/message_protocol.ex rename to lib/core/messages/message_protocol.ex diff --git a/apps/core/lib/core/messages/update.ex b/lib/core/messages/update.ex similarity index 100% rename from apps/core/lib/core/messages/update.ex rename to lib/core/messages/update.ex diff --git a/apps/core/lib/core/publisher_contract.ex b/lib/core/publisher_contract.ex similarity index 100% rename from apps/core/lib/core/publisher_contract.ex rename to lib/core/publisher_contract.ex diff --git a/apps/main_app/lib/main_app.ex b/lib/dbreplex.ex similarity index 92% rename from apps/main_app/lib/main_app.ex rename to lib/dbreplex.ex index f29f4e0..0f6feee 100644 --- a/apps/main_app/lib/main_app.ex +++ b/lib/dbreplex.ex @@ -1,7 +1,8 @@ -defmodule MainApp do +defmodule DBReplex do @moduledoc false use Application + use Boundary @impl true def start(_type, _args) do diff --git a/apps/file_publisher/lib/file_publisher.ex b/lib/publishers/file/publisher.ex similarity index 83% rename from apps/file_publisher/lib/file_publisher.ex rename to lib/publishers/file/publisher.ex index 89d0809..a568985 100644 --- a/apps/file_publisher/lib/file_publisher.ex +++ b/lib/publishers/file/publisher.ex @@ -1,12 +1,13 @@ -defmodule FilePublisher do +defmodule Publishers.File do @moduledoc """ - Documentation for `FilePublisher`. + Entry point for `Publishers.File`. """ alias Core.Messages.Delete alias Core.Messages.Update alias Core.Messages.Insert - alias FilePublisher.Serializer + alias Publishers.File.Serializer + use Boundary, deps: [Core] use GenServer require Logger @@ -23,7 +24,7 @@ defmodule FilePublisher do @impl true def init(file_path) do - Registry.register(PublisherRegistry, :publishers, {FilePublisher, :handle_message}) + Registry.register(PublisherRegistry, :publishers, {Publishers.File, :handle_message}) {:ok, file} = File.open(file_path, [:append]) {:ok, %{file: file}} end diff --git a/apps/file_publisher/lib/file_publisher/serializer.ex b/lib/publishers/file/serializer.ex similarity index 75% rename from apps/file_publisher/lib/file_publisher/serializer.ex rename to lib/publishers/file/serializer.ex index 125cd5e..64decb8 100644 --- a/apps/file_publisher/lib/file_publisher/serializer.ex +++ b/lib/publishers/file/serializer.ex @@ -1,6 +1,6 @@ -defprotocol FilePublisher.Serializer do +defprotocol Publishers.File.Serializer do @moduledoc """ - Protocol defining serialization for FilePublisher. + Protocol defining serialization for Publishers.File. """ @doc """ @@ -10,7 +10,7 @@ defprotocol FilePublisher.Serializer do def serialize(message) end -defimpl FilePublisher.Serializer, for: Core.Messages.Insert do +defimpl Publishers.File.Serializer, for: Core.Messages.Insert do def serialize(%Core.Messages.Insert{} = message) do "INSERT INTO #{message.table_name} VALUES " <> (Enum.map(message.columns, fn col -> "#{col.value}" end) @@ -18,7 +18,7 @@ defimpl FilePublisher.Serializer, for: Core.Messages.Insert do end end -defimpl FilePublisher.Serializer, for: Core.Messages.Update do +defimpl Publishers.File.Serializer, for: Core.Messages.Update do def serialize(%Core.Messages.Update{} = message) do "UPDATE #{message.table_name} VALUES " <> (Enum.map(message.columns, fn col -> "#{col.value}" end) |> Enum.join(" ")) <> @@ -27,7 +27,7 @@ defimpl FilePublisher.Serializer, for: Core.Messages.Update do end end -defimpl FilePublisher.Serializer, for: Core.Messages.Delete do +defimpl Publishers.File.Serializer, for: Core.Messages.Delete do def serialize(%Core.Messages.Delete{} = message) do "DELETE #{message.table_name} WHERE " <> (Enum.map(message.where, fn col -> "#{col.name}=#{col.value}" end) |> Enum.join(" ")) diff --git a/apps/pg_subscriber/lib/pg_subscriber/column.ex b/lib/subscribers/postgres/column.ex similarity index 97% rename from apps/pg_subscriber/lib/pg_subscriber/column.ex rename to lib/subscribers/postgres/column.ex index b477de6..28fe102 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/column.ex +++ b/lib/subscribers/postgres/column.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.Column do +defmodule Subscribers.Postgres.Column do alias __MODULE__ @type kind :: ?n | ?u | ?t | ?b diff --git a/apps/pg_subscriber/lib/pg_subscriber/column_meta.ex b/lib/subscribers/postgres/column_meta.ex similarity index 88% rename from apps/pg_subscriber/lib/pg_subscriber/column_meta.ex rename to lib/subscribers/postgres/column_meta.ex index bf9538b..157c4b1 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/column_meta.ex +++ b/lib/subscribers/postgres/column_meta.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.ColumnMeta do +defmodule Subscribers.Postgres.ColumnMeta do @moduledoc """ Struct containing metadata about Postgres columns. """ diff --git a/apps/pg_subscriber/lib/pg_subscriber/handler.ex b/lib/subscribers/postgres/handler.ex similarity index 85% rename from apps/pg_subscriber/lib/pg_subscriber/handler.ex rename to lib/subscribers/postgres/handler.ex index 5b7a94a..7a60f3d 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/handler.ex +++ b/lib/subscribers/postgres/handler.ex @@ -1,13 +1,13 @@ -defmodule PgSubscriber.Handler do +defmodule Subscribers.Postgres.Handler do use GenServer require Logger - alias PgSubscriber.Messages.Insert, as: PgInsert - alias PgSubscriber.RelationStore - alias PgSubscriber.Messages.Relation, as: PgRelation - alias PgSubscriber.Messages.Delete, as: PgDelete + alias Subscribers.Postgres.Messages.Insert, as: PgInsert + alias Subscribers.Postgres.RelationStore + alias Subscribers.Postgres.Messages.Relation, as: PgRelation + alias Subscribers.Postgres.Messages.Delete, as: PgDelete alias Core.Messages.MessageProtocol - alias PgSubscriber.Messages.Update, as: PgUpdate + alias Subscribers.Postgres.Messages.Update, as: PgUpdate def start_link(default) do GenServer.start_link(__MODULE__, default, name: __MODULE__) diff --git a/apps/pg_subscriber/lib/pg_subscriber/messages/delete.ex b/lib/subscribers/postgres/messages/delete.ex similarity index 83% rename from apps/pg_subscriber/lib/pg_subscriber/messages/delete.ex rename to lib/subscribers/postgres/messages/delete.ex index 454ebc7..2fb3419 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/messages/delete.ex +++ b/lib/subscribers/postgres/messages/delete.ex @@ -1,12 +1,12 @@ -defmodule PgSubscriber.Messages.Delete do +defmodule Subscribers.Postgres.Messages.Delete do @moduledoc """ Helper module providing utility functions for handling of DELETE messages. """ require Logger - alias PgSubscriber.Column - alias PgSubscriber.TupleData - alias PgSubscriber.Messages.MessageBehaviour - alias PgSubscriber.Utils + alias Subscribers.Postgres.Column + alias Subscribers.Postgres.TupleData + alias Subscribers.Postgres.Messages.MessageBehaviour + alias Subscribers.Postgres.Utils @behaviour MessageBehaviour @@ -51,11 +51,11 @@ defmodule PgSubscriber.Messages.Delete do end end -defimpl Core.Messages.MessageProtocol, for: PgSubscriber.Messages.Delete do - alias PgSubscriber.RelationStore +defimpl Core.Messages.MessageProtocol, for: Subscribers.Postgres.Messages.Delete do + alias Subscribers.Postgres.RelationStore alias Core.Messages.Delete, as: CoreDelete alias Core.Messages.Column, as: CoreColumn - alias PgSubscriber.Messages.Delete, as: PgDelete + alias Subscribers.Postgres.Messages.Delete, as: PgDelete def to_core_message(%PgDelete{ relation_oid: relation_oid, diff --git a/apps/pg_subscriber/lib/pg_subscriber/messages/insert.ex b/lib/subscribers/postgres/messages/insert.ex similarity index 78% rename from apps/pg_subscriber/lib/pg_subscriber/messages/insert.ex rename to lib/subscribers/postgres/messages/insert.ex index e8ec226..8120b1a 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/messages/insert.ex +++ b/lib/subscribers/postgres/messages/insert.ex @@ -1,12 +1,12 @@ -defmodule PgSubscriber.Messages.Insert do +defmodule Subscribers.Postgres.Messages.Insert do @moduledoc """ Represents Postgres INSERT operation in the database replication stream. """ require Logger - alias PgSubscriber.Messages.MessageBehaviour - alias PgSubscriber.Column - alias PgSubscriber.Utils - alias PgSubscriber.TupleData + alias Subscribers.Postgres.Messages.MessageBehaviour + alias Subscribers.Postgres.Column + alias Subscribers.Postgres.Utils + alias Subscribers.Postgres.TupleData @behaviour MessageBehaviour @@ -39,8 +39,8 @@ defmodule PgSubscriber.Messages.Insert do end end -defimpl Core.Messages.MessageProtocol, for: PgSubscriber.Messages.Insert do - alias PgSubscriber.RelationStore +defimpl Core.Messages.MessageProtocol, for: Subscribers.Postgres.Messages.Insert do + alias Subscribers.Postgres.RelationStore alias Core.Messages.Insert def to_core_message(insert) do diff --git a/apps/pg_subscriber/lib/pg_subscriber/messages/message_behaviour.ex b/lib/subscribers/postgres/messages/message_behaviour.ex similarity index 81% rename from apps/pg_subscriber/lib/pg_subscriber/messages/message_behaviour.ex rename to lib/subscribers/postgres/messages/message_behaviour.ex index 0a71606..4fb2667 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/messages/message_behaviour.ex +++ b/lib/subscribers/postgres/messages/message_behaviour.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.Messages.MessageBehaviour do +defmodule Subscribers.Postgres.Messages.MessageBehaviour do @doc """ Converts binary data to the Postgres-specific representation of a message (struct). """ diff --git a/apps/pg_subscriber/lib/pg_subscriber/messages/relation.ex b/lib/subscribers/postgres/messages/relation.ex similarity index 87% rename from apps/pg_subscriber/lib/pg_subscriber/messages/relation.ex rename to lib/subscribers/postgres/messages/relation.ex index fec7c44..ef4a38d 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/messages/relation.ex +++ b/lib/subscribers/postgres/messages/relation.ex @@ -1,13 +1,13 @@ -defmodule PgSubscriber.Messages.Relation do +defmodule Subscribers.Postgres.Messages.Relation do @moduledoc """ Helper module providing utility functions for handling of RELATION messages. """ require Logger - alias PgSubscriber.Messages.Relation - alias PgSubscriber.Messages.MessageBehaviour - alias PgSubscriber.Utils - alias PgSubscriber.ColumnMeta + alias Subscribers.Postgres.Messages.Relation + alias Subscribers.Postgres.Messages.MessageBehaviour + alias Subscribers.Postgres.Utils + alias Subscribers.Postgres.ColumnMeta @behaviour MessageBehaviour diff --git a/apps/pg_subscriber/lib/pg_subscriber/messages/update.ex b/lib/subscribers/postgres/messages/update.ex similarity index 91% rename from apps/pg_subscriber/lib/pg_subscriber/messages/update.ex rename to lib/subscribers/postgres/messages/update.ex index 44fcd12..c719d85 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/messages/update.ex +++ b/lib/subscribers/postgres/messages/update.ex @@ -1,11 +1,11 @@ -defmodule PgSubscriber.Messages.Update do +defmodule Subscribers.Postgres.Messages.Update do @moduledoc """ Helper module providing utility functions for proper work with UPDATE messages. """ - alias PgSubscriber.Messages.MessageBehaviour - alias PgSubscriber.Column - alias PgSubscriber.TupleData - alias PgSubscriber.Utils + alias Subscribers.Postgres.Messages.MessageBehaviour + alias Subscribers.Postgres.Column + alias Subscribers.Postgres.TupleData + alias Subscribers.Postgres.Utils require Logger @behaviour MessageBehaviour @@ -82,12 +82,12 @@ defmodule PgSubscriber.Messages.Update do end end -defimpl Core.Messages.MessageProtocol, for: PgSubscriber.Messages.Update do +defimpl Core.Messages.MessageProtocol, for: Subscribers.Postgres.Messages.Update do require Logger alias Core.Messages.Update alias Core.Messages.Column - alias PgSubscriber.RelationStore - alias PgSubscriber.Messages.Update, as: PgpUpdate + alias Subscribers.Postgres.RelationStore + alias Subscribers.Postgres.Messages.Update, as: PgpUpdate def to_core_message(%PgpUpdate{ relation_oid: relation_oid, diff --git a/apps/pg_subscriber/lib/pg_subscriber/pg_dump_parser.ex b/lib/subscribers/postgres/pg_dump_parser.ex similarity index 98% rename from apps/pg_subscriber/lib/pg_subscriber/pg_dump_parser.ex rename to lib/subscribers/postgres/pg_dump_parser.ex index 864ad11..9009e17 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/pg_dump_parser.ex +++ b/lib/subscribers/postgres/pg_dump_parser.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.PgDumpParser do +defmodule Subscribers.Postgres.PgDumpParser do @moduledoc """ Utility module providing functions for parsing pg_dump output. """ diff --git a/apps/pg_subscriber/lib/pg_subscriber/pg_repl.ex b/lib/subscribers/postgres/pg_repl.ex similarity index 93% rename from apps/pg_subscriber/lib/pg_subscriber/pg_repl.ex rename to lib/subscribers/postgres/pg_repl.ex index 64f6d10..2fa61ad 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/pg_repl.ex +++ b/lib/subscribers/postgres/pg_repl.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.Repl do +defmodule Subscribers.Postgres.Repl do use Postgrex.ReplicationConnection def start_link(opts) do @@ -32,7 +32,7 @@ defmodule PgSubscriber.Repl do @impl true # https://www.postgresql.org/docs/14/protocol-replication.html def handle_data(<>, state) do - GenServer.cast(PgSubscriber.Handler, {:handle, rest}) + GenServer.cast(Subscribers.Postgres.Handler, {:handle, rest}) {:noreply, state} end diff --git a/apps/pg_subscriber/lib/pg_subscriber/relation_store.ex b/lib/subscribers/postgres/relation_store.ex similarity index 89% rename from apps/pg_subscriber/lib/pg_subscriber/relation_store.ex rename to lib/subscribers/postgres/relation_store.ex index b2d2960..ab1f244 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/relation_store.ex +++ b/lib/subscribers/postgres/relation_store.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.RelationStore do +defmodule Subscribers.Postgres.RelationStore do @moduledoc """ Agent storing information about known relations. The replication client receives RELATION message everytime @@ -9,8 +9,8 @@ defmodule PgSubscriber.RelationStore do use Agent - alias PgSubscriber.Utils - alias PgSubscriber.Messages.Relation + alias Subscribers.Postgres.Utils + alias Subscribers.Postgres.Messages.Relation @spec start_link(map()) :: Agent.on_start() def start_link(init_state) do diff --git a/apps/pg_subscriber/lib/subscriber.ex b/lib/subscribers/postgres/supervisor.ex similarity index 51% rename from apps/pg_subscriber/lib/subscriber.ex rename to lib/subscribers/postgres/supervisor.ex index 1ddcc90..04668a9 100644 --- a/apps/pg_subscriber/lib/subscriber.ex +++ b/lib/subscribers/postgres/supervisor.ex @@ -1,7 +1,8 @@ -defmodule PgSubscriber do +defmodule Subscribers.Postgres do @moduledoc """ - Supervisor for Postgres subscriber. + Entry point for Postgres subscriber. """ + use Boundary, deps: [Core] use Supervisor def start_link(init_arg) do @@ -10,9 +11,9 @@ defmodule PgSubscriber do def init(repl: repl_config, handler: handler_config) do children = [ - {PgSubscriber.RelationStore, %{}}, - {PgSubscriber.Handler, handler_config}, - {PgSubscriber.Repl, repl_config} + {Subscribers.Postgres.RelationStore, %{}}, + {Subscribers.Postgres.Handler, handler_config}, + {Subscribers.Postgres.Repl, repl_config} ] Supervisor.init(children, strategy: :one_for_one) diff --git a/apps/pg_subscriber/lib/pg_subscriber/tuple_data.ex b/lib/subscribers/postgres/tuple_data.ex similarity index 90% rename from apps/pg_subscriber/lib/pg_subscriber/tuple_data.ex rename to lib/subscribers/postgres/tuple_data.ex index aedf941..eaf2162 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/tuple_data.ex +++ b/lib/subscribers/postgres/tuple_data.ex @@ -1,6 +1,6 @@ -defmodule PgSubscriber.TupleData do +defmodule Subscribers.Postgres.TupleData do alias __MODULE__ - alias PgSubscriber.Column + alias Subscribers.Postgres.Column @type t :: %__MODULE__{ num_of_cols: integer, diff --git a/apps/pg_subscriber/lib/pg_subscriber/utils.ex b/lib/subscribers/postgres/utils.ex similarity index 96% rename from apps/pg_subscriber/lib/pg_subscriber/utils.ex rename to lib/subscribers/postgres/utils.ex index 5c034e8..cdbf4f6 100644 --- a/apps/pg_subscriber/lib/pg_subscriber/utils.ex +++ b/lib/subscribers/postgres/utils.ex @@ -1,4 +1,4 @@ -defmodule PgSubscriber.Utils do +defmodule Subscribers.Postgres.Utils do @moduledoc """ Collection of PG helper functions. """ diff --git a/mix.exs b/mix.exs index 0610efd..ca7fcde 100644 --- a/mix.exs +++ b/mix.exs @@ -3,10 +3,19 @@ defmodule DbSubscriptor.MixProject do def project do [ - apps_path: "apps", + app: :dbreplex, version: "0.1.0", start_permanent: Mix.env() == :prod, - deps: deps() + name: "DBReplex", + deps: deps(), + compilers: [:boundary] ++ Mix.compilers() + ] + end + + def application do + [ + extra_applications: [:logger], + mod: {DBReplex, []} ] end @@ -17,7 +26,9 @@ defmodule DbSubscriptor.MixProject do # Run "mix help deps" for examples and options. defp deps do [ - {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false} + {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, + {:postgrex, "~> 0.20.0"}, + {:boundary, "~> 0.10", runtime: false} ] end end diff --git a/mix.lock b/mix.lock index 2c72a68..865e8e7 100644 --- a/mix.lock +++ b/mix.lock @@ -1,4 +1,5 @@ %{ + "boundary": {:hex, :boundary, "0.10.4", "5fec5d2736c12f9bfe1720c3a2bd8c48c3547c24d6002ebf8e087570afd5bd2f", [:mix], [], "hexpm", "8baf6f23987afdb1483033ed0bde75c9c703613c22ed58d5f23bf948f203247c"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, diff --git a/apps/main_app/test/assets/expected_file_publisher_content.txt b/test/assets/expected_file_publisher_content.txt similarity index 100% rename from apps/main_app/test/assets/expected_file_publisher_content.txt rename to test/assets/expected_file_publisher_content.txt diff --git a/apps/main_app/test/assets/init.sql b/test/assets/init.sql similarity index 100% rename from apps/main_app/test/assets/init.sql rename to test/assets/init.sql diff --git a/apps/main_app/test/assets/pg_dump.sql b/test/assets/pg_dump.sql similarity index 100% rename from apps/main_app/test/assets/pg_dump.sql rename to test/assets/pg_dump.sql diff --git a/apps/main_app/test/main_app_test.exs b/test/dbreplex_test.exs similarity index 84% rename from apps/main_app/test/main_app_test.exs rename to test/dbreplex_test.exs index 88b6361..9d4f3ba 100644 --- a/apps/main_app/test/main_app_test.exs +++ b/test/dbreplex_test.exs @@ -1,24 +1,24 @@ -defmodule MainAppTest do - alias PgSubscriber.PgDumpParser +defmodule DBReplexTest do + alias Subscribers.Postgres.PgDumpParser use ExUnit.Case - doctest MainApp + doctest DBReplex @file_publisher_target "/tmp/dbreplex-integration.txt" @expected_file_publisher_content "./test/assets/expected_file_publisher_content.txt" @tag integration: true - test "PgSubscriber to FilePublisher" do + test "Subscribers.Postgres to Publishers.File" do # initialization {:ok, file_publisher} = DynamicSupervisor.start_child( MainApp.DynamicSupervisor, - {FilePublisher, [@file_publisher_target]} + {Publishers.File, [@file_publisher_target]} ) {:ok, pg_subscriber} = DynamicSupervisor.start_child( MainApp.DynamicSupervisor, - {PgSubscriber, + {Subscribers.Postgres, [ repl: [ host: "localhost", @@ -32,7 +32,7 @@ defmodule MainAppTest do [{_, pg_handler, _, _}] = Enum.filter(Supervisor.which_children(pg_subscriber), fn {module, pid, _, _} -> - module == PgSubscriber.Handler + module == Subscribers.Postgres.Handler end) # test diff --git a/apps/file_publisher/test/file_publisher_test.exs b/test/file_publisher_test.exs similarity index 66% rename from apps/file_publisher/test/file_publisher_test.exs rename to test/file_publisher_test.exs index 56f0d68..5a38346 100644 --- a/apps/file_publisher/test/file_publisher_test.exs +++ b/test/file_publisher_test.exs @@ -1,10 +1,10 @@ -defmodule FilePublisherTest do +defmodule Publishers.FileTest do alias Core.Messages.Insert use ExUnit.Case - doctest FilePublisher + doctest Publishers.File test "receive INSERT message" do - {:ok, pid} = FilePublisher.start_link("/tmp/replication.log") + {:ok, pid} = Publishers.File.start_link("/tmp/replication.log") save_message(pid, 5) Process.sleep(100) end @@ -18,7 +18,7 @@ defmodule FilePublisherTest do columns: [%{kind: 1, value: "Juraj"}] } - FilePublisher.handle_message(pid, message) + Publishers.File.handle_message(pid, message) save_message(pid, num - 1) end end diff --git a/apps/pg_subscriber/test/handler.exs b/test/handler.exs similarity index 82% rename from apps/pg_subscriber/test/handler.exs rename to test/handler.exs index a1fe3cd..c57af5b 100644 --- a/apps/pg_subscriber/test/handler.exs +++ b/test/handler.exs @@ -1,6 +1,6 @@ -defmodule PgSubscriber.HandlerTest do +defmodule Subscribers.Postgres.HandlerTest do use ExUnit.Case - alias PgSubscriber.Handler + alias Subscribers.Postgres.Handler doctest Handler test "insert message" do diff --git a/apps/pg_subscriber/test/pg_dump_parser_test.exs b/test/pg_dump_parser_test.exs similarity index 90% rename from apps/pg_subscriber/test/pg_dump_parser_test.exs rename to test/pg_dump_parser_test.exs index 0edad71..b389a52 100644 --- a/apps/pg_subscriber/test/pg_dump_parser_test.exs +++ b/test/pg_dump_parser_test.exs @@ -1,6 +1,6 @@ -defmodule PgSubscriber.PgDumpParserTest do +defmodule Subscribers.Postgres.PgDumpParserTest do use ExUnit.Case - alias PgSubscriber.PgDumpParser + alias Subscribers.Postgres.PgDumpParser alias Core.Messages.Insert doctest PgDumpParser @@ -13,12 +13,12 @@ defmodule PgSubscriber.PgDumpParserTest do test "filter insert", state do inserts = PgDumpParser.filter_inserts(state.pg_dump) - assert(length(inserts) === 21) + assert(length(inserts) === 4) end test "convert to core many inserts", state do inserts = PgDumpParser.filter_inserts(state.pg_dump) |> PgDumpParser.to_core_insert() - assert(length(inserts) === 21) + assert(length(inserts) === 4) assert( Enum.all?(inserts, fn %type{} = insert -> diff --git a/apps/main_app/test/test_helper.exs b/test/test_helper.exs similarity index 100% rename from apps/main_app/test/test_helper.exs rename to test/test_helper.exs diff --git a/apps/pg_subscriber/test/tuple_data_test.exs b/test/tuple_data_test.exs similarity index 96% rename from apps/pg_subscriber/test/tuple_data_test.exs rename to test/tuple_data_test.exs index 6017996..ef43635 100644 --- a/apps/pg_subscriber/test/tuple_data_test.exs +++ b/test/tuple_data_test.exs @@ -1,7 +1,7 @@ defmodule TupleDataTest do use ExUnit.Case - alias PgSubscriber.TupleData - alias PgSubscriber.Column + alias Subscribers.Postgres.TupleData + alias Subscribers.Postgres.Column doctest TupleData