-module(testcontainer_formulas@mongo). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/testcontainer_formulas/mongo.gleam"). -export([new/0, with_image/2, with_version/2, with_database/2, with_username/2, with_password/2, with_secret_password/2, with_auth_database/2, with_extra_wait/2, on_network/2, on_network_name/2, with_name/2, formula/1]). -export_type([mongo_container/0, mongo_config/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Mongo formula. Defaults to `mongo:7` with root auth.\n" "\n" " use db <- testcontainer.with_formula(\n" " mongo.new()\n" " |> mongo.with_database(\"app_test\")\n" " |> mongo.with_username(\"app\")\n" " |> mongo.with_password(\"secret\")\n" " |> mongo.formula(),\n" " )\n" "\n" " // db.connection_url, db.host, db.port, db.database, db.username\n" ). -type mongo_container() :: {mongo_container, testcontainer@container:container(), binary(), binary(), integer(), binary(), binary()}. -opaque mongo_config() :: {mongo_config, binary(), binary(), binary(), cowl:secret(binary()), binary(), gleam@option:option(testcontainer@wait:wait_strategy()), gleam@option:option(binary()), gleam@option:option(binary())}. -file("src/testcontainer_formulas/mongo.gleam", 52). ?DOC(" Sensible defaults: `mongo:7` / db `app` / user `root` / pass `root`.\n"). -spec new() -> mongo_config(). new() -> {mongo_config, <<"mongo:7"/utf8>>, <<"app"/utf8>>, <<"root"/utf8>>, cowl:secret(<<"root"/utf8>>), <<"admin"/utf8>>, none, none, none}. -file("src/testcontainer_formulas/mongo.gleam", 66). ?DOC(" Replaces the image entirely.\n"). -spec with_image(mongo_config(), binary()) -> mongo_config(). with_image(C, Image) -> {mongo_config, Image, erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 71). ?DOC(" Shorthand: keep `mongo:` prefix, override only the tag.\n"). -spec with_version(mongo_config(), binary()) -> mongo_config(). with_version(C, Version) -> {mongo_config, <<"mongo:"/utf8, Version/binary>>, erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 78). ?DOC( " Sets `MONGO_INITDB_DATABASE`. The image creates this database during\n" " bootstrap, but `mongosh` will still connect through `auth_database`\n" " (default `\"admin\"`).\n" ). -spec with_database(mongo_config(), binary()) -> mongo_config(). with_database(C, Db) -> {mongo_config, erlang:element(2, C), Db, erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 84). ?DOC( " Sets `MONGO_INITDB_ROOT_USERNAME`. This is the **root** user the image\n" " creates at startup, used by the returned `connection_url`.\n" ). -spec with_username(mongo_config(), binary()) -> mongo_config(). with_username(C, User) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), User, erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 89). ?DOC(" Sets `MONGO_INITDB_ROOT_PASSWORD` for the root user.\n"). -spec with_password(mongo_config(), binary()) -> mongo_config(). with_password(C, Pass) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), cowl:secret(Pass), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 94). ?DOC(" Same as `with_password/2` when the value is already a `cowl.Secret`.\n"). -spec with_secret_password(mongo_config(), cowl:secret(binary())) -> mongo_config(). with_secret_password(C, Pass) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), Pass, erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 102). ?DOC(" Authentication database used in the returned Mongo URI.\n"). -spec with_auth_database(mongo_config(), binary()) -> mongo_config(). with_auth_database(C, Db) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), Db, erlang:element(7, C), erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 113). ?DOC( " Adds an extra wait strategy on top of the default\n" " `all_of([port(27017), log_times(\"Waiting for connections\", 2)])`.\n" " The `log_times(_, 2)` matches the second emission of that line, which\n" " is the post-bootstrap restart with `--auth` enabled — earlier, clients\n" " using `MONGO_INITDB_ROOT_USERNAME` race the auth-bootstrap and fail\n" " with \"Authentication failed\". Stays image-agnostic (no dependency on\n" " `mongosh` being present in the image).\n" ). -spec with_extra_wait(mongo_config(), testcontainer@wait:wait_strategy()) -> mongo_config(). with_extra_wait(C, S) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), {some, S}, erlang:element(8, C), erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 117). -spec on_network(mongo_config(), testcontainer@network:network()) -> mongo_config(). on_network(C, Net) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), {some, testcontainer@network:name(Net)}, erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 122). ?DOC(" Same as `on_network/2` when you already have the Docker network name.\n"). -spec on_network_name(mongo_config(), binary()) -> mongo_config(). on_network_name(C, Net) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), {some, Net}, erlang:element(9, C)}. -file("src/testcontainer_formulas/mongo.gleam", 126). -spec with_name(mongo_config(), binary()) -> mongo_config(). with_name(C, N) -> {mongo_config, erlang:element(2, C), erlang:element(3, C), erlang:element(4, C), erlang:element(5, C), erlang:element(6, C), erlang:element(7, C), erlang:element(8, C), {some, N}}. -file("src/testcontainer_formulas/mongo.gleam", 132). ?DOC( " Builds the `Formula(MongoContainer)` ready to pass to\n" " `testcontainer.with_formula/2`.\n" ). -spec formula(mongo_config()) -> testcontainer@formula:formula(mongo_container()). formula(C) -> Mongo_port = testcontainer@port:tcp(27017), Base_wait = testcontainer@wait:all_of( [testcontainer@wait:port(27017), testcontainer@wait:log_times(<<"Waiting for connections"/utf8>>, 2)] ), Wait_strategy = case erlang:element(7, C) of none -> Base_wait; {some, Extra} -> testcontainer@wait:all_of([Base_wait, Extra]) end, With_auth = begin _pipe = testcontainer@container:new(erlang:element(2, C)), _pipe@1 = testcontainer@container:expose_port(_pipe, Mongo_port), _pipe@2 = testcontainer@container:with_env( _pipe@1, <<"MONGO_INITDB_DATABASE"/utf8>>, erlang:element(3, C) ), _pipe@3 = testcontainer@container:with_env( _pipe@2, <<"MONGO_INITDB_ROOT_USERNAME"/utf8>>, erlang:element(4, C) ), _pipe@4 = testcontainer@container:with_secret_env( _pipe@3, <<"MONGO_INITDB_ROOT_PASSWORD"/utf8>>, erlang:element(5, C) ), testcontainer@container:wait_for(_pipe@4, Wait_strategy) end, With_net = case erlang:element(8, C) of none -> With_auth; {some, N} -> _pipe@5 = With_auth, testcontainer@container:on_network(_pipe@5, N) end, Final_spec = case erlang:element(9, C) of none -> With_net; {some, N@1} -> _pipe@6 = With_net, testcontainer@container:with_name(_pipe@6, N@1) end, testcontainer@formula:new( Final_spec, fun(Running) -> gleam@result:'try'( testcontainer@container:host_port(Running, Mongo_port), fun(Mapped_port) -> Host = testcontainer@container:host(Running), Pass = cowl:reveal(erlang:element(5, C)), {ok, {mongo_container, Running, <<<<<<<<<<<<<<<<<<<<<<"mongodb://"/utf8, (gleam_stdlib:percent_encode( erlang:element( 4, C ) ))/binary>>/binary, ":"/utf8>>/binary, (gleam_stdlib:percent_encode( Pass ))/binary>>/binary, "@"/utf8>>/binary, Host/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary( Mapped_port ))/binary>>/binary, "/"/utf8>>/binary, (gleam_stdlib:percent_encode( erlang:element(3, C) ))/binary>>/binary, "?authSource="/utf8>>/binary, (gleam_stdlib:percent_encode( erlang:element(6, C) ))/binary>>, Host, Mapped_port, erlang:element(3, C), erlang:element(4, C)}} end ) end ).