diff --git a/apps/csv2sql/.env.test.sample b/apps/csv2sql/.env.test.sample
deleted file mode 100644
index 3520086..0000000
--- a/apps/csv2sql/.env.test.sample
+++ /dev/null
@@ -1,4 +0,0 @@
-export DB_URL="username:password@localhost/mysql"
-export DB_TYPE="mysql"
-export LOG_LEVEL="debug"
-export SOURCE_DIRECTORY="priv/src/"
diff --git a/apps/csv2sql/.formatter.exs b/apps/csv2sql/.formatter.exs
deleted file mode 100644
index d2cda26..0000000
--- a/apps/csv2sql/.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/csv2sql/.gitignore b/apps/csv2sql/.gitignore
deleted file mode 100644
index 49a69b0..0000000
--- a/apps/csv2sql/.gitignore
+++ /dev/null
@@ -1,41 +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/
-
-# Ignore .fetch files in case you like to edit your project deps locally.
-/.fetch
-
-# 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").
-csv2sql-*.tar
-
-# linter
-/.elixir_ls/
-
-# schema file
-schema.sql
-
-# Formatting file
-.formatter.exs
-
-# Env files
-.env*
-
-# Keep sample files in version control
-!.env*.sample
-
-# Test csv files
-test/support/csv_src/*
diff --git a/apps/csv2sql/.iex.exs b/apps/csv2sql/.iex.exs
deleted file mode 100644
index 33f37fb..0000000
--- a/apps/csv2sql/.iex.exs
+++ /dev/null
@@ -1,26 +0,0 @@
-measure2 = fn fn1, fn2 ->
- Benchee.run(
- %{
- "func_1" => fn1,
- "func_2" => fn2
- },
- warmup: 1,
- time: 5,
- memory_time: 2,
- reduction_time: 2
-)
-end
-
-measure1 = fn func ->
- Benchee.run(
- %{
- "func" => func
- }
-)
-end
-
-# iex(3)> x="/home/arpan/dev/csv2sql/apps/csv2sql/priv/src/test.csv"
-# "/home/arpan/dev/csv2sql/apps/csv2sql/priv/src/test.csv"
-# iex(4)> measure2.(fn -> Csv2sql.SchemaMaker.get_types end, fn -> Csv2sql.TypeDeducer.get_types(x) end)
-
-# measure2.(fn -> Csv2sql.SchemaMaker.get_types end, fn -> Csv2sql.TypeDeducer.get_types end)
diff --git a/apps/csv2sql/mix.exs b/apps/csv2sql/mix.exs
deleted file mode 100644
index 0c2669e..0000000
--- a/apps/csv2sql/mix.exs
+++ /dev/null
@@ -1,87 +0,0 @@
-defmodule Csv2sql.MixProject do
- use Mix.Project
-
- @app :csv2sql
-
- def project do
- [
- app: :csv2sql,
- version: "0.1.0",
- elixir: "~> 1.13",
- # directories to find source files
- elixirc_path: elixirc_paths(Mix.env()),
- start_permanent: Mix.env() == :prod,
- deps: deps(),
- aliases: aliases(),
- compilers: Mix.compilers(),
- test_coverage: [tool: ExCoveralls],
- releases: [{@app, release()}]
- ]
- end
-
- # Run "mix help compile.app" to learn about applications.
- def application do
- [
- extra_applications: [:logger],
- mod: {Csv2sql.Application, []}
- # mod: {Csv2sql, []}
- ]
- end
-
- # Run "mix help deps" to learn about dependencies.
- defp deps do
- [
- {:nimble_csv, "~> 1.2"},
- {:myxql, "~> 0.6.4"},
- {:postgrex, "~> 0.17.5"},
- {:ecto, "~> 3.11.2"},
- {:ecto_sql, "~> 3.11.1"},
- {:sizeable, "~> 1.0"},
- {:timex, "~> 3.7.11"},
- {:typed_struct, "~> 0.3.0"},
- {:flow, "~> 1.2.4"},
- {:stream_split, "~> 0.1.7"},
- {:codepagex, "~> 0.1.6"},
- {:bakeware, "~> 0.2.4"},
-
- # For dev and/or test
- {:dotenv, github: "avdi/dotenv_elixir", only: [:test]},
- {:benchee, "~> 1.3.0", only: :dev},
- {:excoveralls, "~> 0.18.1", only: [:dev, :test]},
- {:credo, "~> 1.7.2", only: [:dev, :test], runtime: false},
- {:dialyxir, "~> 1.4.3", only: [:dev, :test], runtime: false},
- {:mix_unused, "~> 0.4.1", only: [:dev, :test], runtime: false}
- ]
- end
-
- defp elixirc_paths(:test), do: ["lib", "test/support"]
- defp elixirc_paths(_), do: ["lib"]
-
- defp aliases do
- [
- ctest: &custom_test_command/1
- ]
- end
-
- def custom_test_command(_) do
- # System.shell("source .env.test && MIX_ENV=test mix test --trace --warnings-as-errors --cover", into: IO.stream())
- System.cmd("mix", ["coveralls.html", "--trace", "--warnings-as-errors"],
- env: [{"MIX_ENV", "test"}],
- into: IO.stream()
- )
- end
-
- def release do
- [
- # keeps only significant chunks necessary for the VM operation
- strip_beams: Mix.env() == :prod,
- overwrite: true,
- steps: [:assemble, &Bakeware.assemble/1],
- bakeware: [
- # Highest compression level
- compression_level: 1,
- start_command: "start"
- ]
- ]
- end
-end
diff --git a/apps/csv2sql/mix.lock b/apps/csv2sql/mix.lock
deleted file mode 100644
index 5ab53fd..0000000
--- a/apps/csv2sql/mix.lock
+++ /dev/null
@@ -1,48 +0,0 @@
-%{
- "bakeware": {:hex, :bakeware, "0.2.4", "0aaf49b34f4bab2aa433f9ff1485d9401e421603160abd6d269c469fc7b65212", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "7b97bcf6fbeee53bb32441d6c495bf478d26f9575633cfef6831e421e86ada6d"},
- "benchee": {:hex, :benchee, "1.3.0", "f64e3b64ad3563fa9838146ddefb2d2f94cf5b473bdfd63f5ca4d0657bf96694", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "34f4294068c11b2bd2ebf2c59aac9c7da26ffa0068afdf3419f1b176e16c5f81"},
- "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
- "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
- "cli_spinners": {:hex, :cli_spinners, "0.1.0", "08d89c6f1840a8927daed48c675ecb2f20c05c855dc2b4b58c2933d393d5e0c9", [:mix], [], "hexpm", "3b8ccad722e518309d8b92230960ca4775a761164514f78a89c4f04d5a25c97f"},
- "codepagex": {:hex, :codepagex, "0.1.6", "49110d09a25ee336a983281a48ef883da4c6190481e0b063afe2db481af6117e", [:mix], [], "hexpm", "1521461097dde281edf084062f525a4edc6a5e49f4fd1f5ec41c9c4955d5bd59"},
- "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
- "credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"},
- "db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
- "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
- "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
- "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
- "dir_walker": {:hex, :dir_walker, "0.0.8", "5332225074e4887e6e60ca0242af490215f296511ded4df18d554ae25394f727", [:mix], [], "hexpm", "2f4fb16e6427523700df9eb12eece5679ad4459aaefb1ca3cb580184bfc8d173"},
- "dotenv": {:git, "https://github.com/avdi/dotenv_elixir.git", "d6fd3f327173fe18a455203987da95ef9f6cd4c5", []},
- "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
- "ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
- "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
- "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
- "excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"},
- "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
- "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
- "flow": {:hex, :flow, "1.2.4", "1dd58918287eb286656008777cb32714b5123d3855956f29aa141ebae456922d", [:mix], [{:gen_stage, "~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm", "874adde96368e71870f3510b91e35bc31652291858c86c0e75359cbdd35eb211"},
- "gen_stage": {:hex, :gen_stage, "1.2.1", "19d8b5e9a5996d813b8245338a28246307fd8b9c99d1237de199d21efc4c76a1", [:mix], [], "hexpm", "83e8be657fa05b992ffa6ac1e3af6d57aa50aace8f691fcf696ff02f8335b001"},
- "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
- "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
- "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
- "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
- "libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"},
- "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
- "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
- "mix_unused": {:hex, :mix_unused, "0.4.1", "9f8d759a300a79d2077d6baf617f3a5af6935d50b0f113c09295b265afc3e411", [:mix], [{:libgraph, ">= 0.0.0", [hex: :libgraph, repo: "hexpm", optional: false]}], "hexpm", "fa21f688a88e0710e3d96ac1c8e5a6181aea8a75c8a4214f0edcfeb069b831a3"},
- "myxql": {:hex, :myxql, "0.6.4", "1502ea37ee23c31b79725b95d4cc3553693c2bda7421b1febc50722fd988c918", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a3307f4671f3009d3708283649adf205bfe280f7e036fc8ef7f16dbf821ab8e9"},
- "nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"},
- "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
- "postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
- "shorter_maps": {:git, "https://github.com/boyzwj/shorter_maps.git", "787c3447e48c74cf3224f35aba03c84f4c6a3c13", []},
- "sizeable": {:hex, :sizeable, "1.0.2", "625fe06a5dad188b52121a140286f1a6ae1adf350a942cf419499ecd8a11ee29", [:mix], [], "hexpm", "4bab548e6dfba777b400ca50830a9e3a4128e73df77ab1582540cf5860601762"},
- "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
- "statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
- "stream_split": {:hex, :stream_split, "0.1.7", "2d3fd1fd21697da7f91926768d65f79409086052c9ec7ae593987388f52425f8", [:mix], [], "hexpm", "1dc072ff507a64404a0ad7af90df97096183fee8eeac7b300320cea7c4679147"},
- "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
- "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
- "typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"},
- "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
- "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
-}
diff --git a/apps/csv2sql/todos.md b/apps/csv2sql/todos.md
deleted file mode 100644
index f984dd2..0000000
--- a/apps/csv2sql/todos.md
+++ /dev/null
@@ -1,93 +0,0 @@
-SG DB load times: "2022-06-11 05:52:10.243225Z analyzing files" -> "2022-06-11 06:03:39.411448
-
-gracefully termination of producers
-benchmarking against previous solution and "load in file" (previous point is pre-requisite) - test with and without preload in producer
-db connect required?
-observer module
-validator
-error tracker module and gracefull termination in case of various type of errors
-fix csv - dup col names, invalid col names, encoding issue, etc
-tests, docs, comments, dialyzer
-
-Benchmarking results:
- Old vs new csv2sql:
- Single file: faster 1.5x
- Bulk test: 5~7 sec faster
- preloading in producer had no affect; removed it
-
- Comparison with load in file query like:
- set session sql_mode = '';
- LOAD DATA INFILE "/var/lib/mysql-files/test2.csv" INTO TABLE test2 COLUMNS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\n' IGNORE 1 LINES;
-
- For a single 818MB file
-
- CSV2SQL:
- Analyze - ~2min 10sec
- Parse and Insert - ~8min 38sec
-
- Load infile query, only insert - 10 min 54.89 sec
- Considering only insertion time csv2sql was ~20.7% faster than a load infile query
- even if the analysis time is considered csv2sql is still faster.
- This will especially be more noticeable with large file sizes and multiple files
-
-# Todo List
-
-* Move the config parsing into a separate testable module, setup proper default values
-
-* INFER SCHEMA Stage:
- - After kick off use Flow to read ahead chunks of data and feed it into a flow stage to parse csv string.
- - Send csv string to a flow stage to map the type for every row
- - Finally send a flow stream to reduce to get the final type
-
-* INSERT INTO DB GenStage pipeline:
- - Prepare a genStage pipeline on application start.
- - Pipeline has 1 producer for every csv file.
- - Producers are sitting idly
- - After inferring schema kick-off the respective producer by sending it the schema.
- - Before kickoff table is created.
- - Producer reads data from file stream in chunks and send it to the next consumer-producer stage
- - A DynamicConsumerSupervisor in-between produces multiple consumer-producers subscribed to every producer.
- - Each consumer-producer receives a chunk and encodes it in the format suitable for db insertion and sends it to the next consumer stage.
- - A DynamicConsumerSupervisor produces min(cpu-cores * 2, db pool) number of consumers, which insert a chunk into the correct table
-
-* Validation
- - A separate GenStage/Flow pipeline to validate the data.
-
-
-Tag test with DB and test these tests for both postgres and mysql.
-
-
-Done:
-
-* Config Management
-Better config parsing, use separate config structs, better code organization in modules, typespecs, 90%+ test coverage
-
-* TODO configs:
- * Auto drop table if exists
-
-* Csv Type inference
- Better type inference and cpu utilization(10% increased cpu usage), using Flow
- For 818 MB csv with 34959673 rows with older apporoach it took 126 seconds vs 120 seconds with new approach.
- Introduced flow and parallalized reduction of types maps for different chunks
- better code organization, typespecs and 90%+ test coverage.
-
- The little improvement in peroformance becomes significant for larger csv files
-
- Details:
- Name ips average deviation median 99th %
- func_2 0.00831 2.01 min ±0.00% 2.01 min 2.01 min
- func_1 0.00788 2.12 min ±0.00% 2.12 min 2.12 min
-
- Comparison:
- func_2 0.00831
- func_1 0.00788 - 1.06x slower +0.110 min
-
- Memory usage statistics:
-
- Name Memory usage
- func_2 0.00001 GB
- func_1 38.00 GB - 3284106.23x memory usage +38.00 GB
-
-Windows terminal with nmake:
-
-from run: cmd /K "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64
diff --git a/apps/dashboard/.formatter.exs b/apps/dashboard/.formatter.exs
deleted file mode 100644
index 858bbbb..0000000
--- a/apps/dashboard/.formatter.exs
+++ /dev/null
@@ -1,5 +0,0 @@
-[
- plugins: [Phoenix.LiveView.HTMLFormatter],
- import_deps: [:phoenix],
- inputs: ["*.{heex,ex,exs}", "{config,lib,test}/**/*.{heex,ex,exs}"]
-]
diff --git a/apps/dashboard/.gitignore b/apps/dashboard/.gitignore
deleted file mode 100644
index 6bdcf87..0000000
--- a/apps/dashboard/.gitignore
+++ /dev/null
@@ -1,34 +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 3rd-party dependencies like ExDoc output generated docs.
-/doc/
-
-# Ignore .fetch files in case you like to edit your project deps locally.
-/.fetch
-
-# 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").
-dashboard-*.tar
-
-# Ignore assets that are produced by build tools.
-/priv/static/assets/
-
-# Ignore digested assets cache.
-/priv/static/cache_manifest.json
-
-# In case you use Node.js/npm, you want to ignore these.
-npm-debug.log
-/assets/node_modules/
-
diff --git a/apps/dashboard/README.md b/apps/dashboard/README.md
deleted file mode 100644
index af2a1af..0000000
--- a/apps/dashboard/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-* Refs
-
-Windows installer creation: https://docs.microsoft.com/en-us/windows/msix/app-installer/how-to-create-appinstaller-file
-
-Live book installers: https://github.com/livebook-dev/livebook/tree/main/app_bundler/lib/app_bundler
-
-CI setup:
-https://curiosum.com/blog/mastering-elixir-ci-pipeline?utm_medium=email&utm_source=elixir-radar
-https://github.com/livebook-dev/livebook/blob/main/.github/workflows/test.yaml
-
-Docker file refs: https://github.com/livebook-dev/livebook/blob/main/Dockerfile
diff --git a/apps/dashboard/assets/css/about_live.scss b/apps/dashboard/assets/css/about_live.scss
deleted file mode 100644
index ffc1cc1..0000000
--- a/apps/dashboard/assets/css/about_live.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-a {
- text-decoration: none;
-}
-
-.about-container {
- display: flex;
- justify-content: center;
- margin-top: 80px;
- flex-direction: column;
- align-items: center;
-}
-
-.header-wrapper {
- text-align: center;
- h1 {
- color: #fff;
- font-size: 3em;
- font-family: "ubuntu";
- text-transform: uppercase;
- font-weight: 700;
- font-family: "Josefin Sans", sans-serif;
- background: linear-gradient(to right, #e72a3a 10%, #fff 50%, #5bdaff 60%);
- background-size: auto auto;
- background-clip: border-box;
- background-size: 200% auto;
- color: #fff;
- background-clip: text;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- animation: textclip 1.5s linear infinite;
- display: inline-block;
- font-style: italic;
- }
-}
-
-@keyframes textclip {
- to {
- background-position: 200% center;
- }
-}
\ No newline at end of file
diff --git a/apps/dashboard/assets/css/app.scss b/apps/dashboard/assets/css/app.scss
deleted file mode 100644
index cdaea2c..0000000
--- a/apps/dashboard/assets/css/app.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-@import '../node_modules/bootstrap/scss/bootstrap';
-@import 'live_view';
-@import 'custom';
-@import 'start_live';
-@import 'about_live';
\ No newline at end of file
diff --git a/apps/dashboard/assets/css/custom.scss b/apps/dashboard/assets/css/custom.scss
deleted file mode 100644
index 95e4acd..0000000
--- a/apps/dashboard/assets/css/custom.scss
+++ /dev/null
@@ -1,181 +0,0 @@
-// Varaibles
-$light-grey: #f0f0f0;
-
-.bg-light-grey {
- background-color: $light-grey !important;
-}
-
-// Disable horizontal scrollbar
-html,
-body {
- overflow-x: hidden;
- background: blanchedalmond;
-
- // Custom scrollbar styles
- * {
- scrollbar-width: thin;
- }
-
- ::-webkit-scrollbar-thumb {
- border-radius: 10px !important;
- }
-}
-
-.csv2sql-logo {
- display: block;
- min-width: 80px;
- margin-top: 1rem;
-
- img {
- height: 35px;
- width: auto;
- display: block;
- }
-}
-
-.top-navbar {
- background-color: #4a4473;
- display: flex;
- justify-content: center;
- height: 70px;
-
- .nav-header {
- color: white;
- font-size: 1rem;
- font-variant: small-caps;
- font-weight: bold;
- margin-top: 1.3rem;
- margin-left: 0.2rem;
- }
-}
-
-.custom-navbar {
- max-width: 100%;
- font-variant: small-caps;
- font-weight: bold;
- font-style: italic;
-}
-
-.grow {
- transition: all 0.04s ease-in-out;
-}
-
-.grow:hover {
- transform: scale(1.05);
-}
-
-.tool-tip-wrapper {
- width: fit-content;
- position: relative;
- top: -4px;
- padding-right: 2px;
- cursor: pointer;
-}
-
-.mysql-label {
- position: relative;
- top: -14px;
-}
-
-.postgres-label {
- svg {
- display: block;
- position: relative;
- left: 30%;
- }
-
- div {
- font-family: "Roboto", sans-serif;
- font-size: 1.2rem;
-
- .inner-text {
- color: #336791;
- }
- }
-}
-
-.add-link {
- cursor: pointer;
- margin-top: 20px;
-
- span {
- position: relative;
- top: -4px;
- color: darkgreen;
- font-weight: bold;
- font-style: italic;
- text-decoration: underline;
- }
-}
-
-.opacity-transition {
- transition: opacity 0.25s ease-in-out;
-}
-
-.live-modal {
- position: absolute;
- width: 900px;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- z-index: 9999;
- margin: auto;
-}
-
-.db-connect-check {
- height: 72px;
-}
-
-.db-url-text {
- width: 500px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
-}
-
-// Custom scroll bar implementation
-.scrollable-container {
- padding: 10px;
- overflow-y: auto;
- scroll-behavior: smooth;
- scrollbar-gutter: stable; // Reserve space for scrollbar to avoid UI shifting when scrollbar appears
- scrollbar-color: #d4aa70 #e4e4e4; // Works for non-chromium (tested on firfox)
-
- // Custom Scrollbar css works only for chromium based browser
- &::-webkit-scrollbar {
- width: 10px;
- }
-
- &::-webkit-scrollbar-track {
- background-color: #e4e4e4;
- border-radius: 100px;
- }
-
- &::-webkit-scrollbar-thumb {
- border-radius: 100px;
- background-color: #d4aa70;
- box-shadow: inset 2px 2px 5px 0 rgba(#fff, 0.5);
- }
-}
-
-#db-attrs-container {
- height: 300px;
-
- li {
- display: list-item;
- }
-
- .db-attr-index {
- padding: 2px;
- }
-}
-
-#date-patterns-container, #date-time-patterns-container {
- height: 250px;
-}
-
-// Matched Custom Date/DateTime pattern input glow
-.matched-input {
- border-color: green;
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px green;
-}
diff --git a/apps/dashboard/assets/css/live_view.scss b/apps/dashboard/assets/css/live_view.scss
deleted file mode 100644
index dc46ad1..0000000
--- a/apps/dashboard/assets/css/live_view.scss
+++ /dev/null
@@ -1,102 +0,0 @@
-
-/* LiveView specific classes for your customizations */
-.invalid-feedback {
- color: #a94442;
- display: block;
-}
-
-/*
- Any DOM container with the phx-feedback-for attribute will receive a phx-no-feedback class in cases where the
- form fields has yet to receive user input/focus, in such cases we hide the error.
-
- In our case if still show the errors always
-*/
-// .phx-no-feedback.invalid-feedback, .phx-no-feedback .invalid-feedback {
-// display: none;
-// }
-
-.phx-click-loading {
- opacity: 0.5;
- transition: opacity 1s ease-out;
-}
-
-.phx-disconnected{
- cursor: wait;
-}
-
-.phx-disconnected *{
- pointer-events: none;
-}
-
-.phx-modal {
- opacity: 1!important;
- position: fixed;
- z-index: 1;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- overflow: auto;
- background-color: rgb(0,0,0);
- background-color: rgba(0,0,0,0.4);
-}
-
-.phx-modal-content {
- background-color: #fefefe;
- margin: 15% auto;
- padding: 20px;
- border: 1px solid #888;
- width: 80%;
-}
-
-.phx-modal-close {
- color: #aaa;
- float: right;
- font-size: 28px;
- font-weight: bold;
-}
-
-.phx-modal-close:hover,
-.phx-modal-close:focus {
- color: black;
- text-decoration: none;
- cursor: pointer;
-}
-
-/* Alerts and form errors */
-.alert {
- padding: 15px;
- margin-bottom: 20px;
- border: 1px solid transparent;
- border-radius: 4px;
-}
-
-.alert-info {
- color: #31708f;
- background-color: #d9edf7;
- border-color: #bce8f1;
-}
-
-.alert-warning {
- color: #8a6d3b;
- background-color: #fcf8e3;
- border-color: #faebcc;
-}
-
-.alert-danger {
- color: #a94442;
- background-color: #f2dede;
- border-color: #ebccd1;
-}
-
-.alert p {
- margin-bottom: 0;
-}
-
-.alert:empty {
- display: none;
-}
-
-.config-page {
- background-color: #f8f9fa;
-}
\ No newline at end of file
diff --git a/apps/dashboard/assets/css/start_live.scss b/apps/dashboard/assets/css/start_live.scss
deleted file mode 100644
index ed998e9..0000000
--- a/apps/dashboard/assets/css/start_live.scss
+++ /dev/null
@@ -1,189 +0,0 @@
-spinner.loading {
- display: none;
- text-align: center;
- position: relative;
- display: flex;
- justify-content: center;
- align-items: center;
- width: 106px;
- height: 106px;
-}
-.spinner.loading:before {
- content: "";
- height: 120px;
- width: 120px;
- position: absolute;
- top: 0;
- left: 0;
- border-width: 8px;
- border-style: solid;
- border-color: #770505 #ccc #ccc;
- border-radius: 100%;
- animation: rotation .7s infinite linear;
-}
-@keyframes rotation {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(359deg);
- }
-}
-
-.required-config{
- color: red;
- font-size: 1em;
-}
-
-#spinnerText{
- font-size: 1em;
- font-weight: bolder;
- font-variant: small-caps;
- padding-top: 35%;
- text-align: center;
- vertical-align: middle;
-}
-
-#error_stage {
- font-size: 0.7em;
-}
-
-
-.main-footer {
- height: 70px;
- background-color: rebeccapurple;
- opacity: 0.8;
-}
-
-.main-footer .container {
- height: 120px;
- width: 120px;
- position: absolute;
- bottom: 5px;
- border-radius: 50%;
- background-image: linear-gradient(red, yellow);
- border: 1px solid rgb(168, 159, 159);
- box-shadow: 0 2px 5px rgba(201,209,230,.5), 0 7px 20px rgba(201,209,230,.75);
- // center item
- left: 0;
- right: 0;
- margin-left: auto;
- margin-right: auto;
-}
-
-.button-enabled{
- cursor: pointer;
- opacity: 1;
-}
-
-.button-disabled{
- cursor: not-allowed;
- opacity: 0.8;
-}
-
-.current-stats{
- display: flex;
- flex-wrap: wrap;
- border-radius: 10px;
- width: 90%;
- min-height: 150px;
- box-shadow: 0 2px 5px rgba(201,209,230,.5), 0 7px 20px rgba(201,209,230,.75);
- margin: auto;
- margin-bottom: 50px;
- margin-top: 20px;
- padding: 10px;
- font-size: 1em;
- background-color: #f8f9fa;
-}
-
-.current-stats > div {
- width: 50%;
-}
-
-.finish-check {
- color: #cc00ff;
-}
-
-.file-list {
- margin: auto;
- width: 90%;
- box-shadow: 0 2px 5px rgba(201,209,230,.5), 0 7px 20px rgba(201,209,230,.75);
- margin-bottom: 100px;
-}
-
-.file-list-item {
- min-height: 100px;
- font-size: 1em;
-}
-
-.file-name, .file-path, .file-size, .row_count, .records_inserted, .status {
- display: block;
-}
-
-.progress {
- height: 25px !important;
-}
-
-.progress-percentage{
- color: black;
- font-size: 1em;
- font-weight: bold;
-}
-
-.stage_pending,
-.stage_infer_schema,
-.stage_loading_schema,
-.stage_insert_data,
-.stage_finished {
- border-radius: 10px;
- border: 1px solid black;
- padding: 5px;
- font-weight: bold;
-}
-
-.stage_pending {
- background-color: #FFA07A;
-}
-
-.stage_infer_schema {
- background-color: #8A2BE2;
- color: white;
-}
-
-.stage_loading_schema {
- background-color: #BDB76B;
-}
-
-.stage_insert_data {
- background-color: #0000FF;
- color: white;
-}
-
-.stage_finished {
-background-color: #3CB371;
-}
-
-.status {
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
-.overall-status, .validation-status {
- text-transform: capitalize;
- border: 1px solid #FAEBD7;
- background-color: #FAEBD7;
- border-radius: 15px;
- padding: 5px;
- font-variant: small-caps;
- font-weight: bold;
- font-style: italic;
- box-shadow: rgba(17, 17, 26, 0.1) 0px 8px 24px, rgba(17, 17, 26, 0.1) 0px 16px 56px, rgba(17, 17, 26, 0.1) 0px 24px 80px;
-}
-
-.validation-status {
- background-color: #3CB371;
-}
-
-.error-status {
- background-color: rgb(214, 29, 29);
-}
diff --git a/apps/dashboard/assets/js/app.js b/apps/dashboard/assets/js/app.js
deleted file mode 100644
index 2c06761..0000000
--- a/apps/dashboard/assets/js/app.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import * as bootstrap from 'bootstrap';
-window.bootstrap = bootstrap;
-import "phoenix_html";
-// Establish Phoenix Socket and LiveView configuration.
-import { Socket } from "phoenix";
-import { LiveSocket } from "phoenix_live_view";
-
-let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
-let hooks = {
- // When ever a new tooltip is mounted, initialize it
- initTooltipPopup: {
- mounted() {
- // Initialize bootstrap tooltips
- // Ref: https://getbootstrap.com/docs/5.2/components/tooltips/#enable-tooltips
- new bootstrap.Tooltip(this.el);
-
- this.handleEvent("save-config", ({ config }) => {
- localStorage.setItem("config", JSON.stringify(config));
- }
- )
- }
- }
-};
-
-let liveSocket = new LiveSocket(
- "/live",
- Socket,
- {
- hooks,
- params: {
- _csrf_token: csrfToken,
- localConfig: (JSON.parse(localStorage.getItem('config') || '{}'))
- }
- });
-
-liveSocket.connect();
-window.liveSocket = liveSocket;
-
-// Listen for phx "scroll-to-bottom" events and scroll to end of given element id
-window.addEventListener(
- "phx:scroll-to-bottom",
- e => {
- const element = document.getElementById(e.detail.id);
- element.scrollTop = element.scrollHeight;
- }
-)
-
-// Listen for phx "scroll-into-view" events and scroll the given element id into view
-window.addEventListener(
- "phx:scroll-into-view",
- e => {
- const element = document.getElementById(e.detail.id);
- element.scrollIntoView({ behavior: "smooth", block: "nearest" });
- }
-)
diff --git a/apps/dashboard/assets/package.json b/apps/dashboard/assets/package.json
deleted file mode 100644
index 0e0cd1c..0000000
--- a/apps/dashboard/assets/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "devDependencies": {
- "@popperjs/core": "^2.11.5",
- "bootstrap": "5.2.0-beta1"
- }
-}
diff --git a/apps/dashboard/assets/yarn.lock b/apps/dashboard/assets/yarn.lock
deleted file mode 100644
index ecf7889..0000000
--- a/apps/dashboard/assets/yarn.lock
+++ /dev/null
@@ -1,13 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@popperjs/core@^2.11.5":
- version "2.11.5"
- resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz"
- integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
-
-bootstrap@5.2.0-beta1:
- version "5.2.0-beta1"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.0-beta1.tgz#75647ff7327c2cac9b8e1cb6728a790a5be4cefc"
- integrity sha512-6qbgs177WZEFY4SLQUq3tEHayYG80nfDmyTpdKi0MJqRMdS+HAoq24+YKfx6wf+nHY0rx8zrh477J1lFu4WzOA==
diff --git a/apps/dashboard/config/config.exs b/apps/dashboard/config/config.exs
deleted file mode 100644
index 66a06ef..0000000
--- a/apps/dashboard/config/config.exs
+++ /dev/null
@@ -1,37 +0,0 @@
-import Config
-
-# Configures the endpoint
-config :dashboard, DashboardWeb.Endpoint,
- url: [host: "localhost"],
- render_errors: [view: DashboardWeb.ErrorView, accepts: ~w(html json), layout: false],
- pubsub_server: Dashboard.PubSub,
- live_view: [signing_salt: "m3U44H+L"]
-
-# Configure esbuild (the version is required)
-config :esbuild,
- version: "0.14.29",
- default: [
- args:
- ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
- cd: Path.expand("../assets", __DIR__),
- env: %{"NODE_PATH" => Path.expand("../../../deps", __DIR__)}
- ]
-
-config :dart_sass,
- version: "1.53.0",
- default: [
- args: ~w(css/app.scss ../priv/static/assets/app.css),
- cd: Path.expand("../assets", __DIR__)
- ]
-
-# Configures Elixir's Logger
-config :logger, :console,
- format: "$time $metadata[$level] $message\n",
- metadata: [:request_id]
-
-# Use Jason for JSON parsing in Phoenix
-config :phoenix, :json_library, Jason
-
-# Import environment specific config. This must remain at the bottom
-# of this file so it overrides the configuration defined above.
-import_config "#{config_env()}.exs"
diff --git a/apps/dashboard/config/dev.exs b/apps/dashboard/config/dev.exs
deleted file mode 100644
index 3d53953..0000000
--- a/apps/dashboard/config/dev.exs
+++ /dev/null
@@ -1,74 +0,0 @@
-import Config
-
-# For development, we disable any cache and enable
-# debugging and code reloading.
-#
-# The watchers configuration can be used to run external
-# watchers to your application. For example, we use it
-# with esbuild to bundle .js and .css sources.
-config :dashboard, DashboardWeb.Endpoint,
- # Binding to loopback ipv4 address prevents access from other machines.
- # Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
- http: [ip: {127, 0, 0, 1}, port: 4000],
- check_origin: false,
- code_reloader: true,
- debug_errors: true,
- secret_key_base: "SB0LWzWbkJdBpnbm7sH3yIaAZO1oUSIhxIi2zNTpJVq+aht7BUJXAyCc2l8plWvg",
- watchers: [
- # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
- esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
- sass: {
- DartSass,
- :install_and_run,
- [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
- }
- ]
-
-# ## SSL Support
-#
-# In order to use HTTPS in development, a self-signed
-# certificate can be generated by running the following
-# Mix task:
-#
-# mix phx.gen.cert
-#
-# Note that this task requires Erlang/OTP 20 or later.
-# Run `mix help phx.gen.cert` for more information.
-#
-# The `http:` config above can be replaced with:
-#
-# https: [
-# port: 4001,
-# cipher_suite: :strong,
-# keyfile: "priv/cert/selfsigned_key.pem",
-# certfile: "priv/cert/selfsigned.pem"
-# ],
-#
-# If desired, both `http:` and `https:` keys can be
-# configured to run both http and https servers on
-# different ports.
-
-# Watch static and templates for browser reloading.
-config :dashboard, DashboardWeb.Endpoint,
- live_reload: [
- patterns: [
- ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
- ~r"lib/dashboard_web/(live|views)/.*(ex)$",
- ~r"lib/dashboard_web/templates/.*(eex)$"
- ]
- ],
- sass: {
- DartSass,
- :install_and_run,
- [:default, ~w(--embed-source-map --source-map-urls=absolute --watch)]
- }
-
-# Do not include metadata nor timestamps in development logs
-config :logger, :console, format: "[$level] $message\n"
-
-# Set a higher stacktrace during development. Avoid configuring such
-# in production as building large stacktraces may be expensive.
-config :phoenix, :stacktrace_depth, 20
-
-# Initialize plugs at runtime for faster development compilation
-config :phoenix, :plug_init_mode, :runtime
diff --git a/apps/dashboard/config/prod.exs b/apps/dashboard/config/prod.exs
deleted file mode 100644
index d5f5070..0000000
--- a/apps/dashboard/config/prod.exs
+++ /dev/null
@@ -1,49 +0,0 @@
-import Config
-
-# For production, don't forget to configure the url host
-# to something meaningful, Phoenix uses this information
-# when generating URLs.
-#
-# Note we also include the path to a cache manifest
-# containing the digested version of static files. This
-# manifest is generated by the `mix phx.digest` task,
-# which you should run after static files are built and
-# before starting your production server.
-config :dashboard, DashboardWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
-
-# Do not print debug messages in production
-config :logger, level: :info
-
-# ## SSL Support
-#
-# To get SSL working, you will need to add the `https` key
-# to the previous section and set your `:url` port to 443:
-#
-# config :dashboard, DashboardWeb.Endpoint,
-# ...,
-# url: [host: "example.com", port: 443],
-# https: [
-# ...,
-# port: 443,
-# cipher_suite: :strong,
-# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
-# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
-# ]
-#
-# The `cipher_suite` is set to `:strong` to support only the
-# latest and more secure SSL ciphers. This means old browsers
-# and clients may not be supported. You can set it to
-# `:compatible` for wider support.
-#
-# `:keyfile` and `:certfile` expect an absolute path to the key
-# and cert in disk or a relative path inside priv, for example
-# "priv/ssl/server.key". For all supported SSL configuration
-# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
-#
-# We also recommend setting `force_ssl` in your endpoint, ensuring
-# no data is ever sent via http, always redirecting to https:
-#
-# config :dashboard, DashboardWeb.Endpoint,
-# force_ssl: [hsts: true]
-#
-# Check `Plug.SSL` for all available options in `force_ssl`.
diff --git a/apps/dashboard/config/runtime.exs b/apps/dashboard/config/runtime.exs
deleted file mode 100644
index 4866b4e..0000000
--- a/apps/dashboard/config/runtime.exs
+++ /dev/null
@@ -1,50 +0,0 @@
-import Config
-
-# config/runtime.exs is executed for all environments, including
-# during releases. It is executed after compilation and before the
-# system starts, so it is typically used to load production configuration
-# and secrets from environment variables or elsewhere. Do not define
-# any compile-time configuration in here, as it won't be applied.
-# The block below contains prod specific runtime configuration.
-
-# ## Using releases
-#
-# If you use `mix release`, you need to explicitly enable the server
-# by passing the PHX_SERVER=true when you start it:
-#
-# PHX_SERVER=true bin/dashboard start
-#
-# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server`
-# script that automatically sets the env var above.
-if System.get_env("PHX_SERVER") do
- config :dashboard, DashboardWeb.Endpoint, server: true
-end
-
-if config_env() == :prod do
- # The secret key base is used to sign/encrypt cookies and other secrets.
- # A default value is used in config/dev.exs and config/test.exs but you
- # want to use a different value for prod and you most likely don't want
- # to check this value into version control, so we use an environment
- # variable instead.
- secret_key_base =
- System.get_env("SECRET_KEY_BASE") ||
- raise """
- environment variable SECRET_KEY_BASE is missing.
- You can generate one by calling: mix phx.gen.secret
- """
-
- host = System.get_env("PHX_HOST") || "example.com"
- port = String.to_integer(System.get_env("PORT") || "4000")
-
- config :dashboard, DashboardWeb.Endpoint,
- url: [host: host, port: 443, scheme: "https"],
- http: [
- # Enable IPv6 and bind on all interfaces.
- # Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
- # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html
- # for details about using IPv6 vs IPv4 and loopback vs public addresses.
- ip: {0, 0, 0, 0, 0, 0, 0, 0},
- port: port
- ],
- secret_key_base: secret_key_base
-end
diff --git a/apps/dashboard/config/test.exs b/apps/dashboard/config/test.exs
deleted file mode 100644
index c87f630..0000000
--- a/apps/dashboard/config/test.exs
+++ /dev/null
@@ -1,14 +0,0 @@
-import Config
-
-# We don't run a server during test. If one is required,
-# you can enable the server option below.
-config :dashboard, DashboardWeb.Endpoint,
- http: [ip: {127, 0, 0, 1}, port: 4002],
- secret_key_base: "pYynG2vS41aV9IF+H/nexIqwuWGvQ5q6OtGkfyB7XLpX7oqj5RW0ClgL3G4sHw++",
- server: false
-
-# Print only warnings and errors during test
-config :logger, level: :warn
-
-# Initialize plugs at runtime for faster test compilation
-config :phoenix, :plug_init_mode, :runtime
diff --git a/apps/dashboard/lib/dashboard.ex b/apps/dashboard/lib/dashboard.ex
deleted file mode 100644
index b1fe868..0000000
--- a/apps/dashboard/lib/dashboard.ex
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Dashboard do
- @moduledoc """
- Dashboard keeps the contexts that define your domain
- and business logic.
-
- Contexts are also responsible for managing your data, regardless
- if it comes from the database, an external API or others.
- """
-end
diff --git a/apps/dashboard/lib/dashboard/application.ex b/apps/dashboard/lib/dashboard/application.ex
deleted file mode 100644
index fe31661..0000000
--- a/apps/dashboard/lib/dashboard/application.ex
+++ /dev/null
@@ -1,23 +0,0 @@
-defmodule Dashboard.Application do
- @moduledoc false
-
- use Application
-
- @impl true
- def start(_type, _args) do
- children = [
- DashboardWeb.Telemetry,
- {Phoenix.PubSub, name: Dashboard.PubSub},
- DashboardWeb.Endpoint
- ]
-
- opts = [strategy: :one_for_one, name: Dashboard.Supervisor]
- Supervisor.start_link(children, opts)
- end
-
- @impl true
- def config_change(changed, _new, removed) do
- DashboardWeb.Endpoint.config_change(changed, removed)
- :ok
- end
-end
diff --git a/apps/dashboard/lib/dashboard/config.ex b/apps/dashboard/lib/dashboard/config.ex
deleted file mode 100644
index 9b0217f..0000000
--- a/apps/dashboard/lib/dashboard/config.ex
+++ /dev/null
@@ -1,154 +0,0 @@
-# This is required so that changesets can be serialized and stored in browser local storage
-# We are using only changes on a changeset
-defimpl Jason.Encoder, for: Ecto.Changeset do
- def encode(changeset, opts) do
- Jason.Encode.map(changeset.changes, opts)
- end
-end
-
-defmodule DashBoard.Config do
- use Ecto.Schema
- import Ecto.Changeset
-
- @primary_key false
- embedded_schema do
- field(:source_directory)
- field(:schema_path, :string)
- field(:insert_schema, :boolean)
- field(:insert_data, :boolean)
- field(:ordered, :boolean)
- field(:schema_infer_chunk_size, :integer)
- field(:worker_count, :integer)
- field(:parse_datetime, :boolean)
- field(:remove_illegal_characters, :boolean)
-
- # Database related configs
- field(:db_type, Ecto.Enum, values: [:mysql, :postgres])
- field(:db_name, :string)
- field(:db_username, :string)
- field(:db_password, :string)
- field(:db_host, :string)
-
- # Other Database configs
- field(:drop_existing_tables, :boolean)
- field(:varchar_limit, :integer)
- field(:db_worker_count, :integer)
- field(:insertion_chunk_size, :integer)
- field(:log, :boolean)
-
- # Misc
- field(:csv_count, :integer)
- field(:date_time_trial, :string)
-
- embeds_many(:db_attrs, DashBoard.DbAttribute, on_replace: :delete)
- embeds_many(:date_patterns, DashBoard.DatePattern, on_replace: :delete)
- embeds_many(:date_time_patterns, DashBoard.DateTimePattern, on_replace: :delete)
- end
-
- def get_defaults do
- Csv2sql.Config.Loader.get_defaults()
- |> Map.merge(%{
- source_directory: get_source_directory(),
- worker_count: System.schedulers_online()
- })
- end
-
- def changeset(params), do: changeset(%__MODULE__{}, params)
-
- def changeset(%__MODULE__{} = config, params) do
- attrs_to_cast =
- :fields
- |> __MODULE__.__schema__()
- # Reject nested attributes from cast, they will be loaded via cast_embed/2
- |> Enum.reject(fn
- field when field in ~w[db_attrs date_patterns date_time_patterns]a -> true
- _field -> false
- end)
-
- changeset =
- config
- |> cast(params, attrs_to_cast)
- |> validate_limit_constraints(Csv2sql.Config.Loader.get_constraints())
- |> validate_source_directory()
- |> validate_path(:schema_path, true)
- |> cast_embed(:db_attrs)
- |> cast_embed(:date_patterns)
- |> cast_embed(:date_time_patterns)
-
- # Phoenix uses the value of changeset.action to decide if errors should be shown or not on a given form
- %{changeset | action: :insert}
- end
-
- defp validate_limit_constraints(changeset, constants) do
- Enum.reduce(
- constants,
- changeset,
- fn {key, %{min: min, max: max}}, changeset ->
- validate_number(
- changeset,
- key,
- greater_than_or_equal_to: min,
- less_than_or_equal_to: max
- )
- end
- )
- end
-
- defp validate_source_directory(changeset) do
- changeset
- |> validate_path(:source_directory)
- |> add_csv_count()
- end
-
- defp validate_path(changeset, field, allow_blank \\ false) do
- value = get_change(changeset, field, "")
-
- if allow_blank && value == "" do
- changeset
- else
- value
- |> File.dir?()
- |> if(
- do: changeset,
- else: add_error(changeset, field, "Invalid path, enter a path to a valid directory")
- )
- end
- end
-
- defp add_csv_count(changeset) do
- source_directory = get_change(changeset, :source_directory)
-
- if File.dir?(source_directory) do
- csv_count =
- source_directory
- |> File.ls!()
- |> Enum.filter(&is_csv?/1)
- |> Enum.count()
-
- if csv_count == 0,
- do: add_error(changeset, :source_directory, "No CSVs found at path"),
- else: put_change(changeset, :csv_count, csv_count)
- else
- changeset
- end
- end
-
- defp is_csv?(filepath) do
- filepath
- |> String.trim()
- |> String.slice(-4..-1)
- |> String.downcase() == ".csv"
- end
-
- defp get_source_directory() do
- case :os.type() do
- {:win32, _} ->
- username = System.shell("echo %USERNAME%") |> elem(0) |> String.trim()
- "C:/Users/#{username}/Desktop"
-
- {:unix, _} ->
- {op, _exit_code} = System.shell("eval echo \"~$USER\"")
- String.trim(op)
- end
- end
-end
diff --git a/apps/dashboard/lib/dashboard/date_pattern.ex b/apps/dashboard/lib/dashboard/date_pattern.ex
deleted file mode 100644
index 0619463..0000000
--- a/apps/dashboard/lib/dashboard/date_pattern.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule DashBoard.DatePattern do
- use Ecto.Schema
- import Ecto.Changeset
-
- @primary_key false
- embedded_schema do
- field(:id, :string)
- field(:pattern, :string)
- end
-
- def changeset(params), do: changeset(%__MODULE__{}, params)
-
- def changeset(struct, params) do
- struct
- |> cast(params, [:id, :pattern])
- |> validate_required([:id])
- end
-end
diff --git a/apps/dashboard/lib/dashboard/date_time_pattern.ex b/apps/dashboard/lib/dashboard/date_time_pattern.ex
deleted file mode 100644
index a9d3677..0000000
--- a/apps/dashboard/lib/dashboard/date_time_pattern.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule DashBoard.DateTimePattern do
- use Ecto.Schema
- import Ecto.Changeset
-
- @primary_key false
- embedded_schema do
- field(:id, :string)
- field(:pattern, :string)
- end
-
- def changeset(params), do: changeset(%__MODULE__{}, params)
-
- def changeset(struct, params) do
- struct
- |> cast(params, [:id, :pattern])
- |> validate_required([:id])
- end
-end
diff --git a/apps/dashboard/lib/dashboard/db_attribute.ex b/apps/dashboard/lib/dashboard/db_attribute.ex
deleted file mode 100644
index 333e178..0000000
--- a/apps/dashboard/lib/dashboard/db_attribute.ex
+++ /dev/null
@@ -1,17 +0,0 @@
-defmodule DashBoard.DbAttribute do
- use Ecto.Schema
- import Ecto.Changeset
-
- @primary_key false
- embedded_schema do
- field(:id, :string)
- field(:name, :string)
- field(:value, :string)
- end
-
- def changeset(struct, params) do
- struct
- |> cast(params, [:id, :name, :value])
- |> validate_required([:id])
- end
-end
diff --git a/apps/dashboard/lib/dashboard/helpers.ex b/apps/dashboard/lib/dashboard/helpers.ex
deleted file mode 100644
index 4b9d4dd..0000000
--- a/apps/dashboard/lib/dashboard/helpers.ex
+++ /dev/null
@@ -1,69 +0,0 @@
-defmodule Dashboard.Helpers do
- defguard present?(value) when value != nil and value != ""
-
- def match_date_time(changeset, date_time_sample) do
- date_index =
- changeset
- |> Ecto.Changeset.get_field(:date_patterns, [])
- |> get_matching_pattern_index(date_time_sample)
-
- if is_nil(date_index) do
- date_time_index =
- changeset
- |> Ecto.Changeset.get_field(:date_time_patterns, [])
- |> get_matching_pattern_index(date_time_sample)
-
- if is_nil(date_time_index), do: false, else: {:date_time, date_time_index}
- else
- if is_nil(date_index), do: false, else: {:date, date_index}
- end
- end
-
- def create_db_url(configs, opts \\ [])
-
- def create_db_url(
- %{db_username: db_username, db_password: db_password, db_host: db_host, db_name: db_name} =
- config,
- opts
- )
- when present?(db_username) and present?(db_password) and
- present?(db_name) and present?(db_host) do
- hide_password? = Keyword.get(opts, :hide_password, false)
- password = if hide_password?, do: hide_password(db_password), else: db_password
-
- "ecto://#{db_username}:#{password}@#{db_host}/#{db_name}?#{make_query_params(config)}"
- |> String.trim_trailing("?")
- end
-
- def create_db_url(_configs, _hide_password), do: "NA"
-
- # == Private helpers ==
- defp make_query_params(%{db_attrs: db_attrs}) when is_list(db_attrs) do
- db_attrs
- |> Enum.map(& &1.changes)
- |> Enum.reject(fn
- %value{name: name, value: value} when present?(name) and present?(value) -> false
- _ -> true
- end)
- |> Enum.into(%{}, fn %{name: name, value: value} -> {name, value} end)
- |> URI.encode_query()
- end
-
- defp make_query_params(_config), do: ""
-
- defp hide_password(password) do
- password
- |> String.split("")
- |> Enum.map(fn _ -> "•" end)
- |> Enum.join("")
- end
-
- defp get_matching_pattern_index(patterns, string) do
- Enum.find_index(patterns, fn pattern_struct ->
- case Timex.parse(string, pattern_struct.pattern) do
- {:ok, _} -> true
- {:error, _} -> false
- end
- end)
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web.ex b/apps/dashboard/lib/dashboard_web.ex
deleted file mode 100644
index 9e1524f..0000000
--- a/apps/dashboard/lib/dashboard_web.ex
+++ /dev/null
@@ -1,120 +0,0 @@
-defmodule DashboardWeb do
- @moduledoc """
- The entrypoint for defining your web interface, such
- as controllers, views, channels and so on.
-
- This can be used in your application as:
-
- use DashboardWeb, :controller
- use DashboardWeb, :view
-
- The definitions below will be executed for every view,
- controller, etc, so keep them short and clean, focused
- on imports, uses and aliases.
-
- Do NOT define functions inside the quoted expressions
- below. Instead, define any helper function in modules
- and import those modules here.
- """
-
- def controller do
- quote do
- use Phoenix.Controller, namespace: DashboardWeb
-
- import Plug.Conn
- alias DashboardWeb.Router.Helpers, as: Routes
- end
- end
-
- def view do
- quote do
- use Phoenix.View,
- root: "lib/dashboard_web/templates",
- namespace: DashboardWeb
-
- import Phoenix.Component
-
- # Import convenience functions from controllers
- import Phoenix.Controller,
- only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
-
- # Include shared imports and aliases for views
- unquote(view_helpers())
- end
- end
-
- def live_view do
- quote do
- use Phoenix.LiveView,
- layout: {DashboardWeb.LayoutView, :live}
-
- unquote(view_helpers())
-
- import DashboardWeb.LiveHelpers
- import DashboardWeb.Live.UI
- alias DashboardWeb.Live.IconSvg
- alias Phoenix.LiveView.JS
- end
- end
-
- def live_component do
- quote do
- use Phoenix.LiveComponent
-
- unquote(view_helpers())
-
- import DashboardWeb.LiveHelpers
- import DashboardWeb.Live.UI
- alias DashboardWeb.Live.IconSvg
- alias Phoenix.LiveView.JS
- end
- end
-
- def component do
- quote do
- use Phoenix.Component
-
- unquote(view_helpers())
-
- import DashboardWeb.LiveHelpers
- import DashboardWeb.Live.UI
- alias DashboardWeb.Live.IconSvg
- alias Phoenix.LiveView.JS
- end
- end
-
- def router do
- quote do
- use Phoenix.Router
-
- import Plug.Conn
- import Phoenix.Controller
- import Phoenix.LiveView.Router
- end
- end
-
- def channel do
- quote do
- use Phoenix.Channel
- end
- end
-
- defp view_helpers do
- quote do
- # Use all HTML functionality (forms, tags, etc)
- use Phoenix.HTML
-
- # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc)
- import Phoenix.LiveView.Helpers
-
- alias DashboardWeb.Router.Helpers, as: Routes
- end
- end
-
- @doc """
- When used, dispatch to the appropriate controller/view/etc.
- """
- defmacro __using__(which) when is_atom(which) do
- apply(__MODULE__, which, [])
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/controllers/page_controller.ex b/apps/dashboard/lib/dashboard_web/controllers/page_controller.ex
deleted file mode 100644
index a0cf65e..0000000
--- a/apps/dashboard/lib/dashboard_web/controllers/page_controller.ex
+++ /dev/null
@@ -1,7 +0,0 @@
-defmodule DashboardWeb.PageController do
- use DashboardWeb, :controller
-
- def index(conn, _params) do
- render(conn, "index.html")
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/endpoint.ex b/apps/dashboard/lib/dashboard_web/endpoint.ex
deleted file mode 100644
index 5248224..0000000
--- a/apps/dashboard/lib/dashboard_web/endpoint.ex
+++ /dev/null
@@ -1,45 +0,0 @@
-defmodule DashboardWeb.Endpoint do
- use Phoenix.Endpoint, otp_app: :dashboard
-
- # The session will be stored in the cookie and signed,
- # this means its contents can be read but not tampered with.
- # Set :encryption_salt if you would also like to encrypt it.
- @session_options [
- store: :cookie,
- key: "_dashboard_key",
- signing_salt: "nrBwdLbK"
- ]
-
- socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
-
- # Serve at "/" the static files from "priv/static" directory.
- #
- # You should set gzip to true if you are running phx.digest
- # when deploying your static files in production.
- plug Plug.Static,
- at: "/",
- from: :dashboard,
- gzip: false,
- only: ~w(assets fonts images favicon.ico robots.txt)
-
- # Code reloading can be explicitly enabled under the
- # :code_reloader configuration of your endpoint.
- if code_reloading? do
- socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
- plug Phoenix.LiveReloader
- plug Phoenix.CodeReloader
- end
-
- plug Plug.RequestId
- plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
-
- plug Plug.Parsers,
- parsers: [:urlencoded, :multipart, :json],
- pass: ["*/*"],
- json_decoder: Phoenix.json_library()
-
- plug Plug.MethodOverride
- plug Plug.Head
- plug Plug.Session, @session_options
- plug DashboardWeb.Router
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/about_live.ex b/apps/dashboard/lib/dashboard_web/live/about_live.ex
deleted file mode 100644
index bf024a0..0000000
--- a/apps/dashboard/lib/dashboard_web/live/about_live.ex
+++ /dev/null
@@ -1,12 +0,0 @@
-defmodule DashboardWeb.Live.AboutLive do
- use DashboardWeb, :live_view
-
- def about_page(assigns) do
- ~H"""
-
- """
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/config_live.ex b/apps/dashboard/lib/dashboard_web/live/config_live.ex
deleted file mode 100644
index d0a662d..0000000
--- a/apps/dashboard/lib/dashboard_web/live/config_live.ex
+++ /dev/null
@@ -1,392 +0,0 @@
-defmodule DashboardWeb.Live.ConfigLive do
- use DashboardWeb, :component
- import DashboardWeb.Live.Modal.DbAttributesModal
- import DashboardWeb.Live.Modal.DateTimePatternsModal
-
- # TODO: Break this in simple components and remove any unneeded classes and cleanup the markup
- def config_page(assigns) do
- assigns = assign(assigns, :form, to_form(assigns.changeset))
-
- ~H"""
- <.form for={@form} phx-change="validate-and-save">
- <.flow_card form={@form} />
-
-
-
- Configurations marked with * are required
-
-
-
- <.config_item
- form={@form}
- id="source_directory_config"
- title="Source directory"
- tooltip="The source directory where the csvs are located, Example: /home/user/Desktop/csvs"
- required_input={true}
- placeholder="CSV source directory path"
- >
- <:input let={@form}>
- <%= text_input(@form, :source_directory,
- "phx-debounce": "1000",
- class: "form-control",
- placeholder: "CSV source directory path"
- ) %>
- <%= if (csv_count = Ecto.Changeset.get_field(@changeset, :csv_count)) && !is_nil(csv_count) && csv_count > 0 do %>
-
Found <%= csv_count %> csvs at given path
- <% end %>
- <%= error_tag(@form, :source_directory) %>
-
-
-
- <.config_item
- form={@form}
- id="schema_path_config"
- title="Schema file path"
- tooltip="The path were the generated schema file will be created, defaults to the csv source directory, Example: /home/user/Desktop/schema"
- placeholder="Schema file path"
- >
- <:input let={@form}>
- <%= text_input(@form, :schema_path,
- "phx-debounce": "1000",
- class: "form-control",
- placeholder: "Schema file path"
- ) %>
- <%= error_tag(@form, :schema_path) %>
-
-
-
- <.config_item
- form={@form}
- id="worker_count_config"
- title="Worker Count"
- tooltip="The number of workers used. Increasing worker count may result in better performance but may lead to errors, decreasing worker count to 1 means, csv2sql will process one file at a time. The number of workers is directly related to the number of files processed simultaneously."
- placeholder="Worker count"
- >
- <:input let={@form}>
- <%= text_input(@form, :worker_count,
- type: "number",
- class: "form-control",
- placeholder: "Worker count",
- max: @constraints.worker_count.max,
- min: @constraints.worker_count.min
- ) %>
- <%= error_tag(@form, :worker_count) %>
-
-
-
- <.config_item
- form={@form}
- id="schema_infer_chunk_size"
- title="Chunk Size"
- tooltip="The chunk size to use when the schema for a csv will be infered parallely .
- For example: A chunk size 100 means the csv will be read 100 rows at a time
- and separate processes will be used to infer the schema of each 100 row chunk"
- placeholder="Chunk Size"
- >
- <:input let={@form}>
- <%= text_input(@form, :schema_infer_chunk_size,
- type: "number",
- class: "form-control",
- placeholder: "Chunk Size",
- max: @constraints.schema_infer_chunk_size.max,
- min: @constraints.schema_infer_chunk_size.min
- ) %>
- <%= error_tag(@form, :schema_infer_chunk_size) %>
-
-
-
-
- <.config_item
- form={@form}
- checkbox_input={true}
- id="parse_datetime_config"
- class="pb-2"
- title="Parse Datetime"
- tooltip="TODO: popup title"
- >
- <:input let={@form}>
- <%= checkbox(@form, :parse_datetime, class: "form-check-input") %>
-
-
-
- <.config_item
- form={@form}
- checkbox_input={true}
- id="remove_illegal_characters_config"
- class="pt-0"
- title="Remove illegal characters"
- tooltip="TODO: popup title"
- >
- <:input let={@form}>
- <%= checkbox(@form, :remove_illegal_characters, class: "form-check-input") %>
-
-
-
- <%= if Ecto.Changeset.get_field(@changeset, :parse_datetime) do %>
-
-
-
- Add date time patterns
-
-
- <% end %>
-
-
-
-
-
-
-
- Database Configurations
-
-
-
-
-
- <.config_item
- form={@form}
- id="db_type_config"
- class="pb-0"
- title="DB Type"
- required_input={true}
- tooltip="Set wether to use MySQL or PostgreSQL"
- >
- <:input let={@form}>
-
-
- <%= radio_button(@form, :db_type, :mysql,
- class: "form-check-input mt-4",
- id: "mysql_db_type",
- checked: "checked",
- disable: !db_needed(@changeset)
- ) %>
-
-
-
-
-
-
-
-
-
-
-
- <.config_item
- form={@form}
- checkbox_input={true}
- id="drop_existing_tables_config"
- class="pb-2"
- title="Drop existing tables"
- tooltip="TODO: popup title"
- >
- <:input let={@form}>
- <%= checkbox(@form, :drop_existing_tables, class: "form-check-input") %>
-
-
-
- <.config_item
- form={@form}
- checkbox_input={true}
- id="log_config_config"
- class="pt-0"
- title="Verbose Logging"
- tooltip="TODO: popup title"
- >
- <:input let={@form}><%= checkbox(@form, :log, class: "form-check-input") %>
-
-
-
-
-
- <.db_connection_check
- changeset={@changeset}
- db_connection_established={@db_connection_established}
- />
-
-
- <.config_item
- form={@form}
- id="db_name_config"
- class="pb-0"
- title="Database name"
- tooltip="This is the name of the database which will be created (if not present already), required field if database access is required"
- required_input={true}
- placeholder="Database name"
- >
- <:input let={@form}>
- <%= text_input(@form, :db_name, class: "form-control", placeholder: "Database name") %>
-
-
-
- <.config_item
- form={@form}
- id="db_host_config"
- title="Database Host"
- tooltip="database host, required field if database access is required"
- required_input={true}
- placeholder="Database host"
- >
- <:input let={@form}>
- <%= text_input(@form, :db_host, class: "form-control", placeholder: "Database host") %>
-
-
-
-
-
- <.config_item
- form={@form}
- id="db_username_config"
- title="Database username"
- tooltip="database username, required field if database access is required"
- required_input={true}
- placeholder="Database username"
- >
- <:input let={@form}>
- <%= text_input(@form, :db_username,
- class: "form-control",
- placeholder: "Database username"
- ) %>
-
-
-
- <.config_item
- form={@form}
- id="db_password_config"
- title="Database password"
- tooltip="database password, required field if database access is required"
- required_input={true}
- placeholder="Database password"
- >
- <:input let={@form}>
- <%= text_input(@form, :db_password,
- type: "password",
- class: "form-control",
- placeholder: "Database password"
- ) %>
-
-
-
-
-
-
-
- Add more database configurations
-
-
-
-
-
- <.config_item
- form={@form}
- id="varchar_limit_config"
- class="pb-0"
- title="Varchar size"
- tooltip="The character limit after which a db field becomes a text from a varchar"
- placeholder="Varchar size"
- >
- <:input let={@form}>
- <%= text_input(@form, :varchar_limit,
- type: "number",
- class: "form-control",
- placeholder: "Varchar size",
- max: @constraints.varchar_limit.max,
- min: @constraints.varchar_limit.min
- ) %>
- <%= error_tag(@form, :varchar_limit) %>
-
-
-
- <.config_item
- form={@form}
- id="db_worker_count_config"
- class="pb-0"
- title="DB Worker Count"
- tooltip="The number of database workers, the max number of processes writing to the database at once"
- placeholder="DB Worker count"
- >
- <:input let={@form}>
- <%= text_input(@form, :db_worker_count,
- type: "number",
- class: "form-control",
- placeholder: "DB Worker count",
- max: @constraints.db_worker_count.max,
- min: @constraints.db_worker_count.min
- ) %>
- <%= error_tag(@form, :db_worker_count) %>
-
-
-
- <.config_item
- form={@form}
- id="insertion_chunk_size_config"
- title="Insertion Chunk Size"
- tooltip="number of records to insert into the database at once Increasing this may result in database errors for too many placeholders"
- placeholder="Insertion Chunk Size"
- >
- <:input let={@form}>
- <%= text_input(@form, :insertion_chunk_size,
- type: "number",
- class: "form-control",
- placeholder: "Insertion Chunk size",
- max: @constraints.insertion_chunk_size.max,
- min: @constraints.insertion_chunk_size.min
- ) %>
- <%= error_tag(@form, :insertion_chunk_size) %>
-
-
-
-
-
-
- <%= if @modal != "add-more-db-attrs" do %>
- <%= inputs_for @form, :db_attrs, fn assoc_form -> %>
- <%= hidden_input(assoc_form, :id) %>
- <%= hidden_input(assoc_form, :name) %>
- <%= hidden_input(assoc_form, :value) %>
- <% end %>
- <% end %>
-
- <%= if @modal != "add-date-time-patterns" do %>
- <%= inputs_for @form, :date_time_patterns, fn assoc_form -> %>
- <%= hidden_input(assoc_form, :id) %>
- <%= hidden_input(assoc_form, :pattern) %>
- <% end %>
-
- <%= inputs_for @form, :date_patterns, fn assoc_form -> %>
- <%= hidden_input(assoc_form, :id) %>
- <%= hidden_input(assoc_form, :pattern) %>
- <% end %>
- <% end %>
-
- <%= case @modal do %>
- <% "add-more-db-attrs" -> %>
- <.db_attrs_modal id="db_attrs_modal" form={@form} changeset={@changeset} />
- <% "add-date-time-patterns" -> %>
- <.date_time_patterns_modal
- id="date_time_patterns_modal"
- form={@form}
- changeset={@changeset}
- matching_date_time={@matching_date_time}
- />
- <% _ -> %>
- <% end %>
-
- """
- end
-
- defp db_needed(changeset) do
- Ecto.Changeset.get_field(changeset, :insert_schema) ||
- Ecto.Changeset.get_field(changeset, :insert_data)
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/helpers.ex b/apps/dashboard/lib/dashboard_web/live/helpers.ex
deleted file mode 100644
index c4dfd4a..0000000
--- a/apps/dashboard/lib/dashboard_web/live/helpers.ex
+++ /dev/null
@@ -1,15 +0,0 @@
-defmodule DashboardWeb.LiveHelpers do
- # import Phoenix.LiveView
- # import Phoenix.LiveView.Helpers
- # alias Phoenix.LiveView.JS
-
- def get_nav_item_attrs(%{page: page}, curr_page) when page == curr_page,
- do: %{class: "nav-link active", "aria-current": "page"}
-
- def get_nav_item_attrs(_assigns, _curr_page), do: %{class: "nav-link bg-light-grey"}
-
- def get_config_item_attrs(status) when status not in [:working, :imported, :validating],
- do: %{"phx-click" => "page-change", "phx-value-page" => "config"}
-
- def get_config_item_attrs(_status), do: %{}
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/icon_svg.ex b/apps/dashboard/lib/dashboard_web/live/icon_svg.ex
deleted file mode 100644
index 398cb21..0000000
--- a/apps/dashboard/lib/dashboard_web/live/icon_svg.ex
+++ /dev/null
@@ -1,455 +0,0 @@
-defmodule DashboardWeb.Live.IconSvg do
- use DashboardWeb, :component
- # https://www.reshot.com/free-svg-icons/
-
- @dimensions %{width: 33, height: 33}
-
- def args(assigns) do
- %{
- class: Map.get(assigns, :class, ""),
- width: Map.get(assigns, :width, @dimensions[:width]),
- height: Map.get(assigns, :height, @dimensions[:height])
- }
- end
-
- def settings(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def start(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def about(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def infer_schema(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def insert_schema(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def insert_data(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def db_settings(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def bulb(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
- """
- end
-
- def right_arrow(assigns \\ %{}) do
- ~H"""
-
-
-
- """
- end
-
- def mysql_icon(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
- """
- end
-
- def postgresql_icon(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- """
- end
-
- def add_icon(assigns \\ %{}) do
- ~H"""
-
-
-
- """
- end
-
- def check_icon(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
- """
- end
-
- def warn_icon(assigns \\ %{}) do
- ~H"""
-
-
-
-
- """
- end
-
- def remove_icon(assigns \\ %{}) do
- ~H"""
-
-
-
- """
- end
-
- def empty_icon(assigns \\ %{}) do
- ~H"""
-
-
-
- """
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/main_live.ex b/apps/dashboard/lib/dashboard_web/live/main_live.ex
deleted file mode 100644
index 07440f1..0000000
--- a/apps/dashboard/lib/dashboard_web/live/main_live.ex
+++ /dev/null
@@ -1,327 +0,0 @@
-defmodule DashboardWeb.Live.MainLive do
- use DashboardWeb, :live_view
- import Dashboard.Helpers
- alias DashBoard.Config
- alias DashBoard.DbAttribute
- alias Csv2sql.Database.ConnectionTest
- alias DashboardWeb.Live.{ConfigLive, StartLive, AboutLive}
-
- @debounce_time 1000
-
- @impl true
- def mount(_params, _session, socket) do
- local_storage_config = (get_connect_params(socket) || %{}) |> Map.get("localConfig", %{})
-
- local_storage_config =
- for {key, val} <- local_storage_config, into: %{}, do: {String.to_atom(key), val}
-
- # Check for DB connection on config load from local storage
- timer_ref = Process.send_after(self(), :check_db_connection, @debounce_time)
-
- {:ok,
- assign(socket,
- page: "config",
- modal: false,
- path_validator_debouncer: nil,
- db_connection_debouncer: timer_ref,
- db_connection_established: false,
- changeset: Config.get_defaults() |> Map.merge(local_storage_config) |> Config.changeset(),
- matching_date_time: nil,
- constraints: Csv2sql.Config.Loader.get_constraints(),
- time_spend: 0,
- state: %Csv2sql.ProgressTracker.State{
- status: :init,
- start_time: nil,
- validation_status: nil
- },
- memory_usage: 0,
- cpu_usage: 0
- )}
- end
-
- @impl true
- def handle_event("start", _unsigned_params, %{assigns: assigns} = socket) do
- socket_state = assigns.state
-
- cond do
- assigns.changeset.valid? and socket_state.status == :init ->
- Csv2sql.ProgressTracker.add_subscriber()
-
- Task.start(fn ->
- socket.assigns.changeset
- |> prepare_args()
- |> Csv2sql.Config.Loader.load()
-
- Csv2sql.Stages.Analyze.analyze_files()
- end)
-
- send(self(), :update_state)
-
- {:noreply, socket}
-
- socket_state.status in [:working, :imported, :validating] ->
- {:noreply, socket}
-
- true ->
- Csv2sql.ProgressTracker.reset_state()
-
- {:noreply,
- assign(socket,
- state: %Csv2sql.ProgressTracker.State{
- status: :init,
- start_time: nil,
- validation_status: nil
- },
- time_spend: 0,
- memory_usage: 0,
- cpu_usage: 0
- )}
- end
- end
-
- @impl true
- def handle_event("page-change", %{"page" => page}, socket) do
- {:noreply, assign(socket, %{page: page})}
- end
-
- @impl true
- def handle_event("open-modal", %{"modal" => modal}, socket) do
- {:noreply, assign(socket, :modal, modal)}
- end
-
- @impl true
- def handle_event("close-modal", _attrs, socket) do
- {:noreply, assign(socket, :modal, false)}
- end
-
- @impl true
- def handle_event("validate-and-save", attrs, socket) do
- args = Map.get(attrs, "config", %{})
-
- socket =
- socket
- |> assign(
- page: "config",
- changeset: Config.changeset(args)
- )
- # DB connection checker is expensive and returns result to caller process with delay
- # so we don't do this validation on changeset level
- |> db_connection_checker(args)
- |> update_matching_date_time(attrs)
-
- {:noreply, socket |> push_event("save-config", %{config: socket.assigns.changeset})}
- end
-
- @impl true
- def handle_event("add-new-" <> field, _attrs, %{assigns: assigns} = socket)
- when field in ~w[db-attr date-pattern date-time-pattern] do
- new_field =
- field
- |> String.replace("-", "_")
- |> String.to_atom()
- |> case do
- :db_attr -> %DbAttribute{id: Nanoid.generate(), name: "", value: ""}
- :date_pattern -> %DashBoard.DatePattern{id: Nanoid.generate()}
- :date_time_pattern -> %DashBoard.DateTimePattern{id: Nanoid.generate()}
- end
-
- association = "#{field}s" |> String.replace("-", "_") |> String.to_atom()
-
- updated_association =
- assigns.changeset
- |> Ecto.Changeset.get_field(association, [])
- |> Enum.concat([new_field])
-
- updated_changeset =
- Ecto.Changeset.put_embed(assigns.changeset, association, updated_association)
-
- {:noreply,
- socket
- |> assign(changeset: updated_changeset)
- |> push_event("scroll-to-bottom", %{id: "#{field}s-container"})}
- end
-
- @impl true
- def handle_event("remove-" <> field, %{"attrid" => attrid}, %{assigns: assigns} = socket)
- when field in ~w[db-attr date-pattern date-time-pattern] do
- association = "#{field}s" |> String.replace("-", "_") |> String.to_atom()
-
- updated_association =
- assigns.changeset
- # For relations get_change/2 return the original changeset data with changes applied, fetch_change!/2 returns raw db_config changesets
- |> Ecto.Changeset.fetch_change!(association)
- |> Enum.reject(fn embed_changeset ->
- Ecto.Changeset.get_field(embed_changeset, :id) == attrid
- end)
-
- updated_changeset =
- Ecto.Changeset.put_embed(assigns.changeset, association, updated_association)
-
- {:noreply,
- socket
- |> assign(changeset: updated_changeset)
- |> update_matching_date_time()}
- end
-
- @impl true
- def handle_info(:finish, socket) do
- {:noreply, assign(socket, state: Csv2sql.ProgressTracker.get_state())}
- end
-
- @impl true
- def handle_info(:update_state, socket) do
- state = socket.assigns.state
-
- time_taken =
- if is_nil(state.start_time) do
- 0
- else
- DateTime.utc_now()
- |> Time.diff(state.start_time, :millisecond)
- |> Kernel./(1000)
- |> Float.round()
- end
-
- if state.status in [:init, :working, :imported, :validating] do
- Process.send_after(self(), :update_state, 200)
- end
-
- {:noreply,
- assign(socket,
- state: Csv2sql.ProgressTracker.get_state(),
- time_spend: time_taken,
- cpu_usage: :cpu_sup.util() |> Float.round(2),
- memory_usage: :erlang.memory(:total) |> Sizeable.filesize()
- )}
- end
-
- @impl true
- def handle_info(:check_db_connection, %{assigns: assigns} = socket) do
- with(
- db_url = create_db_url(assigns.changeset.changes, hide_password: false),
- true <- not ("NA" == db_url),
- db_type <- Ecto.Changeset.get_field(assigns.changeset, :db_type),
- false <- is_nil(db_type),
- args = %{db_type: db_type, db_url: db_url},
- resp = ConnectionTest.check_db_connection(self(), args),
- :ok <- resp
- ) do
- socket
- else
- {:error, :on_going} ->
- Process.send_after(self(), :check_db_connection, @debounce_time)
- socket
-
- _ ->
- assign(socket, db_connection_established: false)
- end
-
- {:noreply, socket}
- end
-
- # DB connection callbacks
- @impl true
- def handle_info({:connected, _}, socket),
- do: {:noreply, assign(socket, db_connection_established: true)}
-
- @impl true
- def handle_info({:error, _}, %{assigns: assigns} = socket) do
- {:noreply,
- assign(
- socket,
- changeset:
- Ecto.Changeset.add_error(assigns.changeset, :db_url, "Could not connect to database"),
- db_connection_established: false
- )}
- end
-
- @impl true
- def handle_info({:report_error, reason}, socket) do
- IO.inspect("Reported Error #{inspect(reason)}")
- {:noreply, socket}
- end
-
- defp render_page(assigns) do
- case assigns.page do
- "config" ->
- ConfigLive.config_page(assigns)
-
- "start" ->
- StartLive.start_page(assigns)
-
- "about" ->
- AboutLive.about_page(assigns)
- end
- end
-
- defp db_connection_checker(%{assigns: assigns} = socket, args) do
- if db_config_updated?(assigns, args) do
- if assigns.db_connection_debouncer,
- do: Process.cancel_timer(assigns.db_connection_debouncer)
-
- timer_ref = Process.send_after(self(), :check_db_connection, @debounce_time)
- assign(socket, :db_connection_debouncer, timer_ref)
- else
- socket
- end
- end
-
- defp db_config_updated?(%{changeset: changeset}, args) do
- # TODO: Take into account custom db params
- Ecto.Changeset.get_field(changeset, :db_type) != Map.get(args, "db_type") ||
- Ecto.Changeset.get_field(changeset, :db_username) != Map.get(args, "db_username") ||
- Ecto.Changeset.get_field(changeset, :db_password) != Map.get(args, "db_password") ||
- Ecto.Changeset.get_field(changeset, :db_host) != Map.get(args, "db_host") ||
- Ecto.Changeset.get_field(changeset, :db_name) != Map.get(args, "db_name")
- end
-
- defp update_matching_date_time(%{assigns: assigns} = socket, attrs \\ %{}) do
- date_time_sample =
- get_in(attrs, ["config", "date_time_trial"]) ||
- Ecto.Changeset.get_field(assigns.changeset, :date_time_trial)
-
- case match_date_time(assigns.changeset, date_time_sample) do
- {type, index} ->
- socket
- |> assign(matching_date_time: {type, index})
- |> push_event("scroll-into-view", %{
- id: "config_#{type}_patterns_#{index}_pattern"
- })
-
- false ->
- assign(socket, matching_date_time: nil)
- end
- end
-
- defp prepare_args(changeset) do
- config = Ecto.Changeset.apply_changes(changeset)
-
- %{
- source_directory: config.source_directory,
- schema_path: config.schema_path,
- insert_schema: config.insert_schema,
- insert_data: config.insert_data,
- ordered: config.ordered,
- date_patterns: prepare_date_patterns(config.date_patterns),
- datetime_patterns: prepare_date_patterns(config.date_time_patterns),
- schema_infer_chunk_size: config.schema_infer_chunk_size,
- worker_count: config.worker_count,
- parse_datetime: config.parse_datetime,
- remove_illegal_characters: config.remove_illegal_characters,
- db_type: config.db_type,
- db_name: config.db_name,
- db_url: create_db_url(changeset.changes),
- drop_existing_tables: config.drop_existing_tables,
- varchar_limit: config.varchar_limit,
- db_worker_count: config.db_worker_count,
- insertion_chunk_size: config.insertion_chunk_size,
- log: config.log
- }
- end
-
- defp prepare_date_patterns(date_patterns) do
- date_patterns
- |> Enum.reject(&is_nil(&1.pattern))
- |> Enum.map(&%{id: &1.id, pattern: &1.pattern})
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/main_live.html.heex b/apps/dashboard/lib/dashboard_web/live/main_live.html.heex
deleted file mode 100644
index 4d099d2..0000000
--- a/apps/dashboard/lib/dashboard_web/live/main_live.html.heex
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-<.render_page {assigns} />
diff --git a/apps/dashboard/lib/dashboard_web/live/modals/date_time_patterns_modal.ex b/apps/dashboard/lib/dashboard_web/live/modals/date_time_patterns_modal.ex
deleted file mode 100644
index d0c23f5..0000000
--- a/apps/dashboard/lib/dashboard_web/live/modals/date_time_patterns_modal.ex
+++ /dev/null
@@ -1,187 +0,0 @@
-defmodule DashboardWeb.Live.Modal.DateTimePatternsModal do
- use DashboardWeb, :component
- import Dashboard.Helpers
-
- @date_time_pattern_hints [
- {"{YYYY}", "full year number (0..9999)"},
- {"{YY}", "the last two digits of the year number (0.99)"},
- {"{M}", "month number (1..12)"},
- {"{Mshort}", "abbreviated month name (Jan..Dec, no padding)"},
- {"{Mfull}", "full month name (January..December, no padding)"},
- {"{D}", "day number (1..31)"},
- {"{Dord}", "ordinal day of the year (1..366)"},
- {"{h24}", "hour of the day (00..23)"},
- {"{h12}", "hour of the day (1..12)"},
- {"{m}", "minutes of the hour (00..59)"},
- {"{s}", "seconds of the minute (00..60)"},
- {"{am}", "lowercase am or pm (no padding)"},
- {"{AM}", "uppercase AM or PM (no padding)"}
- ]
-
- def date_time_patterns_modal(assigns) do
- custom_date_time_patterns_added =
- assigns.changeset |> Ecto.Changeset.get_field(:date_time_patterns, []) |> length() != 0
-
- custom_date_patterns_added =
- assigns.changeset |> Ecto.Changeset.get_field(:date_patterns, []) |> length() != 0
-
- assigns =
- assigns
- |> assign(:custom_date_patterns_added, custom_date_patterns_added)
- |> assign(:custom_date_time_patterns_added, custom_date_time_patterns_added)
-
- ~H"""
-
-
-
- Add date patterns
-
-
-
-
-
- >
-
-
-
-
-
-
-
-
-
- Add datetime pattern
-
-
-
-
-
-
- Add datetime pattern
-
-
-
-
-
- Add custom date time patterns
- Some commonly used pattern symbols are given below:
-
-
- <%= for {pattern, description} <- date_time_pattern_hints() do %>
-
-
<%= pattern %>
-
-
-
<%= description %>
-
- <% end %>
-
-
*Fractional seconds and timezones are not supported.
-
-
-
-
- <.popup
- title="Enter a sample date or date time to check if it matches any added custom patterns"
- id="date-time-try-it-hint"
- />
- Enter sample date time
-
- <%= if present?(Ecto.Changeset.get_field(@changeset, :date_time_trial)) && is_nil(@matching_date_time) do %>
-
No matching patterns found
- <% end %>
- <%= text_input(@form, :date_time_trial,
- class: "form-control",
- placeholder: "Pattern",
- id: "date-time-trial"
- ) %>
-
-
-
-
-
-
- """
- end
-
- defp date_time_pattern_hints, do: @date_time_pattern_hints
-
- defp input_class(index, type, {match_type, match_index})
- when type == match_type and index == match_index + 1,
- do: "form-control matched-input"
-
- defp input_class(_index, _type, _), do: "form-control"
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/modals/db_attrs_modal.ex b/apps/dashboard/lib/dashboard_web/live/modals/db_attrs_modal.ex
deleted file mode 100644
index 98a15bf..0000000
--- a/apps/dashboard/lib/dashboard_web/live/modals/db_attrs_modal.ex
+++ /dev/null
@@ -1,76 +0,0 @@
-defmodule DashboardWeb.Live.Modal.DbAttributesModal do
- use DashboardWeb, :component
-
- def db_attrs_modal(assigns) do
- db_attrs_added =
- assigns.changeset |> Ecto.Changeset.get_field(:db_attrs, []) |> length() != 0
-
- assigns = assign(assigns, :db_attrs_added, db_attrs_added)
-
- ~H"""
-
-
-
- Add additional database attributes, click here to
-
learn
- more
-
- (Duplicate and empty attributes will be ignored)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Add more database configurations
-
-
-
- """
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/modals/modal.ex b/apps/dashboard/lib/dashboard_web/live/modals/modal.ex
deleted file mode 100644
index 716e35b..0000000
--- a/apps/dashboard/lib/dashboard_web/live/modals/modal.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule DashboardWeb.Live.Modals do
- use DashboardWeb, :component
-
- def modal(assigns) do
- ~H"""
-
-
-
-
-
-
-
<%= render_slot(@inner_block) %>
-
-
-
- """
- end
-
- defp hide_modal(js \\ %JS{}) do
- js
- |> JS.hide(to: ".live-modal", transition: "opacity-0")
- |> JS.hide(to: ".modal-backdrop", transition: "opacity-0")
- |> JS.push("close-modal")
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/start_live.ex b/apps/dashboard/lib/dashboard_web/live/start_live.ex
deleted file mode 100644
index 71908e0..0000000
--- a/apps/dashboard/lib/dashboard_web/live/start_live.ex
+++ /dev/null
@@ -1,124 +0,0 @@
-defmodule DashboardWeb.Live.StartLive do
- use DashboardWeb, :live_view
-
- def start_page(assigns) do
- ~H"""
-
-
-
- Status:
-
- <%= cond do %>
- <% not @changeset.valid? -> %>
- Invalid Configurations!
-
- <% is_tuple(@state.status) -> %>
- Error! check logs
-
- <% true -> %>
- <%= show_status(@state.status) %>
- <% end %>
-
-
- <%= if not is_nil(@state.validation_status) do %>
-
- Validation Status:
- <%= @state.validation_status %>!
-
- <% end %>
- <%= if @state.status != :init do %>
-
Total Files: <%= Enum.count(Map.values(@state.files)) %>
-
Files Imported: <%= Enum.count(Map.values(@state.files), fn %{status: status} -> status == :done end) %>
-
CPU Usage: <%= @cpu_usage %>%
-
Memory Usage of Application: <%= @memory_usage %>
-
Time Elapsed: <%= @time_spend %> seconds
- <% end %>
-
-
-
-
- <%= Enum.map Map.values(@state.files), fn %{name: name, path: path, size: size, row_count: row_count, rows_processed: rows_processed, status: status} -> %>
-
-
Name:
- <%= name %>
-
-
Path:
- <%= path %>
-
-
Size:
- <%= size %>
-
-
Total Number of Records:
- <%= row_count %>
-
-
- Status:
- <%= case status do %>
- <% :pending -> %> Pending
-
- <% :analyze -> %> Infering Schema
-
- <% :loading -> %>
- Inserting Data
- Record Inserted:
- <%= rows_processed %>
-
-
- <% percentage_progress=if(row_count==0, do: 100, else: (rows_processed / row_count) * 100) %>
-
-
- <%= Float.round(percentage_progress * 1.0 , 2) %>%
-
-
-
-
- <% :done -> %> Finished
- <% end %>
-
-
- <% end %>
-
-
-
-
-
-
-
-
- <%= cond do %>
- <% @state.status == :init -> %> Start!
- <% @state.status in [:working, :imported] -> %> Working..
- <% @state.status == :validating -> %> Validating..
- <% @state.status == :finish -> %> Finished! Reset?
- <% true -> %> ERROR! Reset?
- <% end %>
-
-
-
-
- """
- end
-
- defp item_success_class(status) do
- if status == :done, do: "list-group-item-success", else: ""
- end
-
- defp error_status_class(status) do
- if is_tuple(status) or status == :failed, do: "error-status", else: ""
- end
-
- defp spinner_loading_class(status) do
- if status in [:working, :imported, :validating],
- do: "spinner loading",
- else: ""
- end
-
- defp show_status(:imported), do: :working
-
- defp show_status(status), do: status
-
- defp button_class(changeset) do
- if not changeset.valid?, do: "button-disabled", else: "button-enabled"
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/live/ui.ex b/apps/dashboard/lib/dashboard_web/live/ui.ex
deleted file mode 100644
index 1c960d7..0000000
--- a/apps/dashboard/lib/dashboard_web/live/ui.ex
+++ /dev/null
@@ -1,138 +0,0 @@
-defmodule DashboardWeb.Live.UI do
- import Phoenix.HTML.Form
- import Phoenix.Component
- alias DashboardWeb.Live.IconSvg
-
- def db_connection_check(assigns \\ %{}) do
- db_url = Dashboard.Helpers.create_db_url(assigns.changeset.changes)
- assigns = assign(assigns, :db_url, db_url)
-
- # TODO: Maybe add loader for indicating on going db connect check
- ~H"""
-
-
- <%= if @db_connection_established do %>
-
- CAN CONNECT TO DATABASE!
- <% else %>
-
-
- COULD NOT CONNECT TO DATABASE!
-
- <% end %>
-
-
-
-
DATABASE URL: <%= @db_url %>
-
-
- """
- end
-
- def popup(assigns \\ %{}) do
- ~H"""
-
-
-
- """
- end
-
- def config_item(assigns \\ %{}) do
- ~H"""
-
-
- <.popup title={@tooltip} id={@id} />
-
- <%= if assigns[:checkbox_input] do %>
-
- <%= render_slot(@input, @form) %>
-
- <% end %>
-
-
- <%= if assigns[:required_input] do %>
- *
- <% end %>
- <%= @title %>
-
-
-
- <%= if !assigns[:checkbox_input] do %>
-
<%= render_slot(@input, @form) %>
- <% end %>
-
- """
- end
-
- def flow_card(assigns \\ %{}) do
- ~H"""
-
-
-
-
-
-
-
-
-
-
-
<.popup title="Set whether to create database schema" id="insert_schema_popup" />
-
- <%= checkbox(@form, :insert_schema, class: "form-check-input") %>
- <%= label(@form, :insert_schema, "Create Tables", class: "form-check-label") %>
-
-
-
-
-
-
-
-
-
-
-
-
<.popup title="Set whether to insert the CSVs into the database" id="insert_data_popup" />
-
- <%= checkbox(@form, :insert_data, class: "form-check-input") %>
- <%= label(@form, :insert_data, class: "form-check-label") %>
-
-
-
-
- """
- end
-
- @doc """
- Generates tag for inlined form input errors.
- """
- def error_tag(form, field) do
- Enum.map(Keyword.get_values(form.errors, field), fn error ->
- Phoenix.HTML.Tag.content_tag(:span, translate_error(error),
- class: "invalid-feedback",
- phx_feedback_for: input_name(form, field)
- )
- end)
- end
-
- @doc """
- Translates an error message.
- """
- def translate_error({msg, opts}) do
- Enum.reduce(opts, msg, fn {key, value}, acc ->
- String.replace(acc, "%{#{key}}", fn _ -> to_string(value) end)
- end)
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/router.ex b/apps/dashboard/lib/dashboard_web/router.ex
deleted file mode 100644
index 6d9dacf..0000000
--- a/apps/dashboard/lib/dashboard_web/router.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule DashboardWeb.Router do
- use DashboardWeb, :router
-
- pipeline :browser do
- plug :accepts, ["html"]
- plug :fetch_session
- plug :fetch_live_flash
- plug :put_root_layout, {DashboardWeb.LayoutView, :root}
- plug :protect_from_forgery
- plug :put_secure_browser_headers
- end
-
- scope "/", DashboardWeb do
- pipe_through :browser
-
- live "/", Live.MainLive, :index
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/telemetry.ex b/apps/dashboard/lib/dashboard_web/telemetry.ex
deleted file mode 100644
index 59cb1b2..0000000
--- a/apps/dashboard/lib/dashboard_web/telemetry.ex
+++ /dev/null
@@ -1,48 +0,0 @@
-defmodule DashboardWeb.Telemetry do
- use Supervisor
- import Telemetry.Metrics
-
- def start_link(arg) do
- Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
- end
-
- @impl true
- def init(_arg) do
- children = [
- # Telemetry poller will execute the given period measurements
- # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics
- {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}
- # Add reporters as children of your supervision tree.
- # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()}
- ]
-
- Supervisor.init(children, strategy: :one_for_one)
- end
-
- def metrics do
- [
- # Phoenix Metrics
- summary("phoenix.endpoint.stop.duration",
- unit: {:native, :millisecond}
- ),
- summary("phoenix.router_dispatch.stop.duration",
- tags: [:route],
- unit: {:native, :millisecond}
- ),
-
- # VM Metrics
- summary("vm.memory.total", unit: {:byte, :kilobyte}),
- summary("vm.total_run_queue_lengths.total"),
- summary("vm.total_run_queue_lengths.cpu"),
- summary("vm.total_run_queue_lengths.io")
- ]
- end
-
- defp periodic_measurements do
- [
- # A module, function and arguments to be invoked periodically.
- # This function must call :telemetry.execute/3 and a metric must be added above.
- # {DashboardWeb, :count_users, []}
- ]
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/templates/layout/live.html.heex b/apps/dashboard/lib/dashboard_web/templates/layout/live.html.heex
deleted file mode 100644
index 0543398..0000000
--- a/apps/dashboard/lib/dashboard_web/templates/layout/live.html.heex
+++ /dev/null
@@ -1 +0,0 @@
-<%= @inner_content %>
diff --git a/apps/dashboard/lib/dashboard_web/templates/layout/root.html.heex b/apps/dashboard/lib/dashboard_web/templates/layout/root.html.heex
deleted file mode 100644
index 2e1e612..0000000
--- a/apps/dashboard/lib/dashboard_web/templates/layout/root.html.heex
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
- <.live_title>CSV2SQL - Dashboard
-
-
-
-
- <%= @inner_content %>
-
-
diff --git a/apps/dashboard/lib/dashboard_web/views/error_view.ex b/apps/dashboard/lib/dashboard_web/views/error_view.ex
deleted file mode 100644
index 0bd0648..0000000
--- a/apps/dashboard/lib/dashboard_web/views/error_view.ex
+++ /dev/null
@@ -1,7 +0,0 @@
-defmodule DashboardWeb.ErrorView do
- use DashboardWeb, :view
-
- def template_not_found(template, _assigns) do
- Phoenix.Controller.status_message_from_template(template)
- end
-end
diff --git a/apps/dashboard/lib/dashboard_web/views/layout_view.ex b/apps/dashboard/lib/dashboard_web/views/layout_view.ex
deleted file mode 100644
index 5104427..0000000
--- a/apps/dashboard/lib/dashboard_web/views/layout_view.ex
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule DashboardWeb.LayoutView do
- use DashboardWeb, :view
-end
diff --git a/apps/dashboard/lib/dashboard_web/views/page_view.ex b/apps/dashboard/lib/dashboard_web/views/page_view.ex
deleted file mode 100644
index 07e4875..0000000
--- a/apps/dashboard/lib/dashboard_web/views/page_view.ex
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule DashboardWeb.PageView do
- use DashboardWeb, :view
-end
diff --git a/apps/dashboard/mix.exs b/apps/dashboard/mix.exs
deleted file mode 100644
index 19fdc85..0000000
--- a/apps/dashboard/mix.exs
+++ /dev/null
@@ -1,71 +0,0 @@
-defmodule Dashboard.MixProject do
- use Mix.Project
-
- def project do
- [
- app: :dashboard,
- version: "0.1.0",
- build_path: "../../_build",
- config_path: "../../config/config.exs",
- deps_path: "../../deps",
- lockfile: "../../mix.lock",
- elixir: "~> 1.12",
- elixirc_paths: elixirc_paths(Mix.env()),
- compilers: Mix.compilers(),
- start_permanent: Mix.env() == :prod,
- aliases: aliases(),
- deps: deps()
- ]
- end
-
- # Configuration for the OTP application.
- #
- # Type `mix help compile.app` for more information.
- def application do
- [
- mod: {Dashboard.Application, []},
- extra_applications: [:logger, :runtime_tools, :os_mon]
- ]
- end
-
- # Specifies which paths to compile per environment.
- defp elixirc_paths(:test), do: ["lib", "test/support"]
- defp elixirc_paths(_), do: ["lib"]
-
- # Specifies your project dependencies.
- #
- # Type `mix help deps` for examples and options.
- defp deps do
- [
- {:phoenix, "~> 1.7"},
- {:phoenix_html, "~> 3.0"},
- {:phoenix_view, "~> 2.0"},
- {:phoenix_live_view, "~> 0.20.2"},
- {:telemetry_metrics, "~> 1.0"},
- {:telemetry_poller, "~> 1.1.0"},
- {:jason, "~> 1.2"},
- {:plug_cowboy, "~> 2.5"},
- {:ecto, "~> 3.11.2"},
- {:phoenix_ecto, "~> 4.4"},
- {:csv2sql, in_umbrella: true},
- {:nanoid, "~> 2.1.0"},
-
- # Development Deps
- {:phoenix_live_reload, "~> 1.5.3", only: :dev},
- {:dart_sass, "~> 0.2", runtime: Mix.env() == :dev},
- {:esbuild, "~> 0.8.1", runtime: Mix.env() == :dev},
- {:floki, ">= 0.36.1", only: :test}
- ]
- end
-
- defp aliases do
- [
- setup: ["deps.get"],
- "assets.deploy": [
- "esbuild default --minify",
- "sass default --no-source-map --style=compressed",
- "phx.digest"
- ]
- ]
- end
-end
diff --git a/apps/dashboard/priv/static/favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico b/apps/dashboard/priv/static/favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico
deleted file mode 100644
index 73de524..0000000
Binary files a/apps/dashboard/priv/static/favicon-a8ca4e3a2bb8fea46a9ee9e102e7d3eb.ico and /dev/null differ
diff --git a/apps/dashboard/priv/static/favicon.ico b/apps/dashboard/priv/static/favicon.ico
deleted file mode 100644
index 73de524..0000000
Binary files a/apps/dashboard/priv/static/favicon.ico and /dev/null differ
diff --git a/apps/dashboard/priv/static/images/logo.png b/apps/dashboard/priv/static/images/logo.png
deleted file mode 100644
index 362c694..0000000
Binary files a/apps/dashboard/priv/static/images/logo.png and /dev/null differ
diff --git a/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt b/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt
deleted file mode 100644
index 26e06b5..0000000
--- a/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
-#
-# To ban all spiders from the entire site uncomment the next two lines:
-# User-agent: *
-# Disallow: /
diff --git a/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt.gz b/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt.gz
deleted file mode 100644
index 24de2e1..0000000
Binary files a/apps/dashboard/priv/static/robots-9e2c81b0855bbff2baa8371bc4a78186.txt.gz and /dev/null differ
diff --git a/apps/dashboard/priv/static/robots.txt b/apps/dashboard/priv/static/robots.txt
deleted file mode 100644
index 26e06b5..0000000
--- a/apps/dashboard/priv/static/robots.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
-#
-# To ban all spiders from the entire site uncomment the next two lines:
-# User-agent: *
-# Disallow: /
diff --git a/apps/dashboard/priv/static/robots.txt.gz b/apps/dashboard/priv/static/robots.txt.gz
deleted file mode 100644
index 24de2e1..0000000
Binary files a/apps/dashboard/priv/static/robots.txt.gz and /dev/null differ
diff --git a/apps/dashboard/test/dashboard_web/controllers/page_controller_test.exs b/apps/dashboard/test/dashboard_web/controllers/page_controller_test.exs
deleted file mode 100644
index 76a419f..0000000
--- a/apps/dashboard/test/dashboard_web/controllers/page_controller_test.exs
+++ /dev/null
@@ -1,8 +0,0 @@
-defmodule DashboardWeb.PageControllerTest do
- use DashboardWeb.ConnCase
-
- test "GET /", %{conn: conn} do
- conn = get(conn, "/")
- assert html_response(conn, 200) =~ "Welcome to Phoenix!"
- end
-end
diff --git a/apps/dashboard/test/dashboard_web/views/error_view_test.exs b/apps/dashboard/test/dashboard_web/views/error_view_test.exs
deleted file mode 100644
index ed1b1ce..0000000
--- a/apps/dashboard/test/dashboard_web/views/error_view_test.exs
+++ /dev/null
@@ -1,14 +0,0 @@
-defmodule DashboardWeb.ErrorViewTest do
- use DashboardWeb.ConnCase, async: true
-
- # Bring render/3 and render_to_string/3 for testing custom views
- import Phoenix.View
-
- test "renders 404.html" do
- assert render_to_string(DashboardWeb.ErrorView, "404.html", []) == "Not Found"
- end
-
- test "renders 500.html" do
- assert render_to_string(DashboardWeb.ErrorView, "500.html", []) == "Internal Server Error"
- end
-end
diff --git a/apps/dashboard/test/dashboard_web/views/layout_view_test.exs b/apps/dashboard/test/dashboard_web/views/layout_view_test.exs
deleted file mode 100644
index a00b9dd..0000000
--- a/apps/dashboard/test/dashboard_web/views/layout_view_test.exs
+++ /dev/null
@@ -1,8 +0,0 @@
-defmodule DashboardWeb.LayoutViewTest do
- use DashboardWeb.ConnCase, async: true
-
- # When testing helpers, you may want to import Phoenix.HTML and
- # use functions such as safe_to_string() to convert the helper
- # result into an HTML string.
- # import Phoenix.HTML
-end
diff --git a/apps/dashboard/test/dashboard_web/views/page_view_test.exs b/apps/dashboard/test/dashboard_web/views/page_view_test.exs
deleted file mode 100644
index 6e4c0ee..0000000
--- a/apps/dashboard/test/dashboard_web/views/page_view_test.exs
+++ /dev/null
@@ -1,3 +0,0 @@
-defmodule DashboardWeb.PageViewTest do
- use DashboardWeb.ConnCase, async: true
-end
diff --git a/apps/dashboard/test/support/conn_case.ex b/apps/dashboard/test/support/conn_case.ex
deleted file mode 100644
index 22e9fc1..0000000
--- a/apps/dashboard/test/support/conn_case.ex
+++ /dev/null
@@ -1,37 +0,0 @@
-defmodule DashboardWeb.ConnCase do
- @moduledoc """
- This module defines the test case to be used by
- tests that require setting up a connection.
-
- Such tests rely on `Phoenix.ConnTest` and also
- import other functionality to make it easier
- to build common data structures and query the data layer.
-
- Finally, if the test case interacts with the database,
- we enable the SQL sandbox, so changes done to the database
- are reverted at the end of every test. If you are using
- PostgreSQL, you can even run database tests asynchronously
- by setting `use DashboardWeb.ConnCase, async: true`, although
- this option is not recommended for other databases.
- """
-
- use ExUnit.CaseTemplate
-
- using do
- quote do
- # Import conveniences for testing with connections
- import Plug.Conn
- import Phoenix.ConnTest
- import DashboardWeb.ConnCase
-
- alias DashboardWeb.Router.Helpers, as: Routes
-
- # The default endpoint for testing
- @endpoint DashboardWeb.Endpoint
- end
- end
-
- setup _tags do
- {:ok, conn: Phoenix.ConnTest.build_conn()}
- end
-end
diff --git a/apps/dashboard/test/test_helper.exs b/apps/dashboard/test/test_helper.exs
deleted file mode 100644
index 869559e..0000000
--- a/apps/dashboard/test/test_helper.exs
+++ /dev/null
@@ -1 +0,0 @@
-ExUnit.start()
diff --git a/config/config.exs b/config/config.exs
deleted file mode 100644
index 6608f48..0000000
--- a/config/config.exs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Config
-import_config "../apps/dashboard/config/config.exs"
diff --git a/apps/csv2sql/lib/csv2sql.ex b/lib/csv2sql.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql.ex
rename to lib/csv2sql.ex
diff --git a/apps/csv2sql/lib/csv2sql/application.ex b/lib/csv2sql/application.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/application.ex
rename to lib/csv2sql/application.ex
diff --git a/apps/csv2sql/lib/csv2sql/config/config.ex b/lib/csv2sql/config/config.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/config/config.ex
rename to lib/csv2sql/config/config.ex
diff --git a/apps/csv2sql/lib/csv2sql/config/loader.ex b/lib/csv2sql/config/loader.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/config/loader.ex
rename to lib/csv2sql/config/loader.ex
diff --git a/apps/csv2sql/lib/csv2sql/database/connection_test.ex b/lib/csv2sql/database/connection_test.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/database/connection_test.ex
rename to lib/csv2sql/database/connection_test.ex
diff --git a/apps/csv2sql/lib/csv2sql/database/database.ex b/lib/csv2sql/database/database.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/database/database.ex
rename to lib/csv2sql/database/database.ex
diff --git a/apps/csv2sql/lib/csv2sql/database/mysql.ex b/lib/csv2sql/database/mysql.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/database/mysql.ex
rename to lib/csv2sql/database/mysql.ex
diff --git a/apps/csv2sql/lib/csv2sql/database/postgres.ex b/lib/csv2sql/database/postgres.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/database/postgres.ex
rename to lib/csv2sql/database/postgres.ex
diff --git a/apps/csv2sql/lib/csv2sql/db_loader/consumer.ex b/lib/csv2sql/db_loader/consumer.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/db_loader/consumer.ex
rename to lib/csv2sql/db_loader/consumer.ex
diff --git a/apps/csv2sql/lib/csv2sql/db_loader/consumer_supervisor.ex b/lib/csv2sql/db_loader/consumer_supervisor.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/db_loader/consumer_supervisor.ex
rename to lib/csv2sql/db_loader/consumer_supervisor.ex
diff --git a/apps/csv2sql/lib/csv2sql/db_loader/producer.ex b/lib/csv2sql/db_loader/producer.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/db_loader/producer.ex
rename to lib/csv2sql/db_loader/producer.ex
diff --git a/apps/csv2sql/lib/csv2sql/file.ex b/lib/csv2sql/file.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/file.ex
rename to lib/csv2sql/file.ex
diff --git a/apps/csv2sql/lib/csv2sql/helpers/helpers.ex b/lib/csv2sql/helpers/helpers.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/helpers/helpers.ex
rename to lib/csv2sql/helpers/helpers.ex
diff --git a/apps/csv2sql/lib/csv2sql/import_validator/import_validator.ex b/lib/csv2sql/import_validator/import_validator.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/import_validator/import_validator.ex
rename to lib/csv2sql/import_validator/import_validator.ex
diff --git a/apps/csv2sql/lib/csv2sql/progress_tracker/progress_tracker.ex b/lib/csv2sql/progress_tracker/progress_tracker.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/progress_tracker/progress_tracker.ex
rename to lib/csv2sql/progress_tracker/progress_tracker.ex
diff --git a/apps/csv2sql/lib/csv2sql/progress_tracker/state.ex b/lib/csv2sql/progress_tracker/state.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/progress_tracker/state.ex
rename to lib/csv2sql/progress_tracker/state.ex
diff --git a/apps/csv2sql/lib/csv2sql/repos.ex b/lib/csv2sql/repos.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/repos.ex
rename to lib/csv2sql/repos.ex
diff --git a/apps/csv2sql/lib/csv2sql/stages/analyze.ex b/lib/csv2sql/stages/analyze.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/stages/analyze.ex
rename to lib/csv2sql/stages/analyze.ex
diff --git a/apps/csv2sql/lib/csv2sql/type_deducer/type_checker.ex b/lib/csv2sql/type_deducer/type_checker.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/type_deducer/type_checker.ex
rename to lib/csv2sql/type_deducer/type_checker.ex
diff --git a/apps/csv2sql/lib/csv2sql/type_deducer/type_deducer.ex b/lib/csv2sql/type_deducer/type_deducer.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/type_deducer/type_deducer.ex
rename to lib/csv2sql/type_deducer/type_deducer.ex
diff --git a/apps/csv2sql/lib/csv2sql/types/types.ex b/lib/csv2sql/types/types.ex
similarity index 100%
rename from apps/csv2sql/lib/csv2sql/types/types.ex
rename to lib/csv2sql/types/types.ex
diff --git a/mix.exs b/mix.exs
index 9e8f61f..0c2669e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -1,49 +1,87 @@
-defmodule Csv2sql.Umbrella.MixProject do
+defmodule Csv2sql.MixProject do
use Mix.Project
+ @app :csv2sql
+
def project do
[
- apps_path: "apps",
- version: "4.0.0",
- build_embedded: Mix.env() == :prod,
+ app: :csv2sql,
+ version: "0.1.0",
+ elixir: "~> 1.13",
+ # directories to find source files
+ elixirc_path: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
deps: deps(),
- releases: [
- csv2sql_and_dashboard: [
- applications: [
- csv2sql: :permanent,
- dashboard: :permanent
- ]
- ],
- csv2sql_only: [
- applications: [csv2sql: :permanent]
- ]
- ],
- name: "Csv2sql",
- description: "Csv2Sql is a blazing fast fully automated tool to load huge CSV files into a RDBMS.",
- package: package(),
- source_url: "https://github.com/kreeti/csv2sql"
+ aliases: aliases(),
+ compilers: Mix.compilers(),
+ test_coverage: [tool: ExCoveralls],
+ releases: [{@app, release()}]
]
end
- defp package() do
+ # Run "mix help compile.app" to learn about applications.
+ def application do
[
- name: "csv2sql",
- licenses: ["MIT"],
- links: %{
- "GitHub" => "https://github.com/kreeti/csv2sql"
- }
+ extra_applications: [:logger],
+ mod: {Csv2sql.Application, []}
+ # mod: {Csv2sql, []}
]
end
- def application do
- [extra_applications: [:logger]]
+ # Run "mix help deps" to learn about dependencies.
+ defp deps do
+ [
+ {:nimble_csv, "~> 1.2"},
+ {:myxql, "~> 0.6.4"},
+ {:postgrex, "~> 0.17.5"},
+ {:ecto, "~> 3.11.2"},
+ {:ecto_sql, "~> 3.11.1"},
+ {:sizeable, "~> 1.0"},
+ {:timex, "~> 3.7.11"},
+ {:typed_struct, "~> 0.3.0"},
+ {:flow, "~> 1.2.4"},
+ {:stream_split, "~> 0.1.7"},
+ {:codepagex, "~> 0.1.6"},
+ {:bakeware, "~> 0.2.4"},
+
+ # For dev and/or test
+ {:dotenv, github: "avdi/dotenv_elixir", only: [:test]},
+ {:benchee, "~> 1.3.0", only: :dev},
+ {:excoveralls, "~> 0.18.1", only: [:dev, :test]},
+ {:credo, "~> 1.7.2", only: [:dev, :test], runtime: false},
+ {:dialyxir, "~> 1.4.3", only: [:dev, :test], runtime: false},
+ {:mix_unused, "~> 0.4.1", only: [:dev, :test], runtime: false}
+ ]
end
- defp deps do
+ defp elixirc_paths(:test), do: ["lib", "test/support"]
+ defp elixirc_paths(_), do: ["lib"]
+
+ defp aliases do
+ [
+ ctest: &custom_test_command/1
+ ]
+ end
+
+ def custom_test_command(_) do
+ # System.shell("source .env.test && MIX_ENV=test mix test --trace --warnings-as-errors --cover", into: IO.stream())
+ System.cmd("mix", ["coveralls.html", "--trace", "--warnings-as-errors"],
+ env: [{"MIX_ENV", "test"}],
+ into: IO.stream()
+ )
+ end
+
+ def release do
[
- {:credo, "~> 1.7"},
- {:ex_doc, "~> 0.33.0"}
+ # keeps only significant chunks necessary for the VM operation
+ strip_beams: Mix.env() == :prod,
+ overwrite: true,
+ steps: [:assemble, &Bakeware.assemble/1],
+ bakeware: [
+ # Highest compression level
+ compression_level: 1,
+ start_command: "start"
+ ]
]
end
end
diff --git a/mix.lock b/mix.lock
index b0889e9..5ab53fd 100644
--- a/mix.lock
+++ b/mix.lock
@@ -2,84 +2,47 @@
"bakeware": {:hex, :bakeware, "0.2.4", "0aaf49b34f4bab2aa433f9ff1485d9401e421603160abd6d269c469fc7b65212", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "7b97bcf6fbeee53bb32441d6c495bf478d26f9575633cfef6831e421e86ada6d"},
"benchee": {:hex, :benchee, "1.3.0", "f64e3b64ad3563fa9838146ddefb2d2f94cf5b473bdfd63f5ca4d0657bf96694", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "34f4294068c11b2bd2ebf2c59aac9c7da26ffa0068afdf3419f1b176e16c5f81"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
- "cachex": {:hex, :cachex, "3.4.0", "868b2959ea4aeb328c6b60ff66c8d5123c083466ad3c33d3d8b5f142e13101fb", [:mix], [{:eternal, "~> 1.2", [hex: :eternal, repo: "hexpm", optional: false]}, {:jumper, "~> 1.0", [hex: :jumper, repo: "hexpm", optional: false]}, {:sleeplocks, "~> 1.1", [hex: :sleeplocks, repo: "hexpm", optional: false]}, {:unsafe, "~> 1.0", [hex: :unsafe, repo: "hexpm", optional: false]}], "hexpm", "370123b1ab4fba4d2965fb18f87fd758325709787c8c5fce35b3fe80645ccbe5"},
- "castore": {:hex, :castore, "1.0.6", "ffc42f110ebfdafab0ea159cd43d31365fa0af0ce4a02ecebf1707ae619ee727", [:mix], [], "hexpm", "374c6e7ca752296be3d6780a6d5b922854ffcc74123da90f2f328996b962d33a"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"cli_spinners": {:hex, :cli_spinners, "0.1.0", "08d89c6f1840a8927daed48c675ecb2f20c05c855dc2b4b58c2933d393d5e0c9", [:mix], [], "hexpm", "3b8ccad722e518309d8b92230960ca4775a761164514f78a89c4f04d5a25c97f"},
"codepagex": {:hex, :codepagex, "0.1.6", "49110d09a25ee336a983281a48ef883da4c6190481e0b063afe2db481af6117e", [:mix], [], "hexpm", "1521461097dde281edf084062f525a4edc6a5e49f4fd1f5ec41c9c4955d5bd59"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
- "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
- "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
- "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
- "credo": {:hex, :credo, "1.7.2", "fdee3a7cb553d8f2e773569181f0a4a2bb7d192e27e325404cc31b354f59d68c", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "dd15d6fbc280f6cf9b269f41df4e4992dee6615939653b164ef951f60afcb68e"},
- "dart_sass": {:hex, :dart_sass, "0.5.0", "c52ad951d9bf611399b6d5efbf404f58dc3a699753662081fbcd4752c6ddeed0", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "bb76938174af8e047e855d3bb83e84ceca17e9acbf1ac6429f9d18171da4a911"},
+ "credo": {:hex, :credo, "1.7.5", "643213503b1c766ec0496d828c90c424471ea54da77c8a168c725686377b9545", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f799e9b5cd1891577d8c773d245668aa74a2fcd15eb277f51a0131690ebfb3fd"},
"db_connection": {:hex, :db_connection, "2.6.0", "77d835c472b5b67fc4f29556dee74bf511bbafecdcaf98c27d27fa5918152086", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c2f992d15725e721ec7fbc1189d4ecdb8afef76648c746a8e1cad35e3b8a35f3"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
"dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"},
+ "dir_walker": {:hex, :dir_walker, "0.0.8", "5332225074e4887e6e60ca0242af490215f296511ded4df18d554ae25394f727", [:mix], [], "hexpm", "2f4fb16e6427523700df9eb12eece5679ad4459aaefb1ca3cb580184bfc8d173"},
"dotenv": {:git, "https://github.com/avdi/dotenv_elixir.git", "d6fd3f327173fe18a455203987da95ef9f6cd4c5", []},
- "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"},
"ecto_sql": {:hex, :ecto_sql, "3.11.1", "e9abf28ae27ef3916b43545f9578b4750956ccea444853606472089e7d169470", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ce14063ab3514424276e7e360108ad6c2308f6d88164a076aac8a387e1fea634"},
- "elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
+ "elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
- "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
- "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"},
- "ex_doc": {:hex, :ex_doc, "0.33.0", "690562b153153c7e4d455dc21dab86e445f66ceba718defe64b0ef6f0bd83ba0", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "3f69adc28274cb51be37d09b03e4565232862a4b10288a3894587b0131412124"},
"excoveralls": {:hex, :excoveralls, "0.18.1", "a6f547570c6b24ec13f122a5634833a063aec49218f6fff27de9df693a15588c", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "d65f79db146bb20399f23046015974de0079668b9abb2f5aac074d078da60b8d"},
"expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"},
- "floki": {:hex, :floki, "0.36.1", "712b7f2ba19a4d5a47dfe3e74d81876c95bbcbee44fe551f0af3d2a388abb3da", [:mix], [], "hexpm", "21ba57abb8204bcc70c439b423fc0dd9f0286de67dc82773a14b0200ada0995f"},
"flow": {:hex, :flow, "1.2.4", "1dd58918287eb286656008777cb32714b5123d3855956f29aa141ebae456922d", [:mix], [{:gen_stage, "~> 1.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm", "874adde96368e71870f3510b91e35bc31652291858c86c0e75359cbdd35eb211"},
"gen_stage": {:hex, :gen_stage, "1.2.1", "19d8b5e9a5996d813b8245338a28246307fd8b9c99d1237de199d21efc4c76a1", [:mix], [], "hexpm", "83e8be657fa05b992ffa6ac1e3af6d57aa50aace8f691fcf696ff02f8335b001"},
"gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
- "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
- "jumper": {:hex, :jumper, "1.0.1", "3c00542ef1a83532b72269fab9f0f0c82bf23a35e27d278bfd9ed0865cecabff", [:mix], [], "hexpm", "318c59078ac220e966d27af3646026db9b5a5e6703cb2aa3e26bcfaba65b7433"},
"libgraph": {:hex, :libgraph, "0.16.0", "3936f3eca6ef826e08880230f806bfea13193e49bf153f93edcf0239d4fd1d07", [:mix], [], "hexpm", "41ca92240e8a4138c30a7e06466acc709b0cbb795c643e9e17174a178982d6bf"},
- "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
- "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
- "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
- "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mix_unused": {:hex, :mix_unused, "0.4.1", "9f8d759a300a79d2077d6baf617f3a5af6935d50b0f113c09295b265afc3e411", [:mix], [{:libgraph, ">= 0.0.0", [hex: :libgraph, repo: "hexpm", optional: false]}], "hexpm", "fa21f688a88e0710e3d96ac1c8e5a6181aea8a75c8a4214f0edcfeb069b831a3"},
"myxql": {:hex, :myxql, "0.6.4", "1502ea37ee23c31b79725b95d4cc3553693c2bda7421b1febc50722fd988c918", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:geo, "~> 3.4", [hex: :geo, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a3307f4671f3009d3708283649adf205bfe280f7e036fc8ef7f16dbf821ab8e9"},
- "nanoid": {:hex, :nanoid, "2.1.0", "d192a5bf1d774258bc49762b480fca0e3128178fa6d35a464af2a738526607fd", [:mix], [], "hexpm", "ebc7a342d02d213534a7f93a091d569b9fea7f26fcd3a638dc655060fc1f76ac"},
"nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"},
- "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
- "phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"},
- "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
- "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"},
- "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"},
- "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
- "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.2", "025391424257d6c1ed2fab5c9fb11b1e5b21a8b47a416659b9a36492217dd5cb", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "381c7f8a5702be838a6bf440a59ea010b458018e1a85cc432e8628641c00f07a"},
- "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
- "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
- "phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"},
- "plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
- "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"},
"postgrex": {:hex, :postgrex, "0.17.5", "0483d054938a8dc069b21bdd636bf56c487404c241ce6c319c1f43588246b281", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "50b8b11afbb2c4095a3ba675b4f055c416d0f3d7de6633a595fc131a828a67eb"},
- "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"shorter_maps": {:git, "https://github.com/boyzwj/shorter_maps.git", "787c3447e48c74cf3224f35aba03c84f4c6a3c13", []},
"sizeable": {:hex, :sizeable, "1.0.2", "625fe06a5dad188b52121a140286f1a6ae1adf350a942cf419499ecd8a11ee29", [:mix], [], "hexpm", "4bab548e6dfba777b400ca50830a9e3a4128e73df77ab1582540cf5860601762"},
- "sleeplocks": {:hex, :sleeplocks, "1.1.1", "3d462a0639a6ef36cc75d6038b7393ae537ab394641beb59830a1b8271faeed3", [:rebar3], [], "hexpm", "84ee37aeff4d0d92b290fff986d6a95ac5eedf9b383fadfd1d88e9b84a1c02e1"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"statistex": {:hex, :statistex, "1.0.0", "f3dc93f3c0c6c92e5f291704cf62b99b553253d7969e9a5fa713e5481cd858a5", [:mix], [], "hexpm", "ff9d8bee7035028ab4742ff52fc80a2aa35cece833cf5319009b52f1b5a86c27"},
"stream_split": {:hex, :stream_split, "0.1.7", "2d3fd1fd21697da7f91926768d65f79409086052c9ec7ae593987388f52425f8", [:mix], [], "hexpm", "1dc072ff507a64404a0ad7af90df97096183fee8eeac7b300320cea7c4679147"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
- "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
- "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"typed_struct": {:hex, :typed_struct, "0.3.0", "939789e3c1dca39d7170c87f729127469d1315dcf99fee8e152bb774b17e7ff7", [:mix], [], "hexpm", "c50bd5c3a61fe4e198a8504f939be3d3c85903b382bde4865579bc23111d1b6d"},
"tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
- "unsafe": {:hex, :unsafe, "1.0.1", "a27e1874f72ee49312e0a9ec2e0b27924214a05e3ddac90e91727bc76f8613d8", [:mix], [], "hexpm", "6c7729a2d214806450d29766abc2afaa7a2cbecf415be64f36a6691afebb50e5"},
- "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
- "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"},
}
diff --git a/apps/csv2sql/priv/src/.keep b/priv/src/.keep
similarity index 100%
rename from apps/csv2sql/priv/src/.keep
rename to priv/src/.keep
diff --git a/apps/csv2sql/test/config/loader_test.exs b/test/config/loader_test.exs
similarity index 100%
rename from apps/csv2sql/test/config/loader_test.exs
rename to test/config/loader_test.exs
diff --git a/apps/csv2sql/test/database/connection_test_test.exs b/test/database/connection_test_test.exs
similarity index 100%
rename from apps/csv2sql/test/database/connection_test_test.exs
rename to test/database/connection_test_test.exs
diff --git a/apps/csv2sql/test/database/database_test.exs b/test/database/database_test.exs
similarity index 100%
rename from apps/csv2sql/test/database/database_test.exs
rename to test/database/database_test.exs
diff --git a/apps/csv2sql/test/helpers/helpers_test.exs b/test/helpers/helpers_test.exs
similarity index 100%
rename from apps/csv2sql/test/helpers/helpers_test.exs
rename to test/helpers/helpers_test.exs
diff --git a/apps/csv2sql/test/stages/analyze_test.exs b/test/stages/analyze_test.exs
similarity index 100%
rename from apps/csv2sql/test/stages/analyze_test.exs
rename to test/stages/analyze_test.exs
diff --git a/apps/csv2sql/test/support/csv_src/test.csv b/test/support/csv_src/test.csv
similarity index 100%
rename from apps/csv2sql/test/support/csv_src/test.csv
rename to test/support/csv_src/test.csv
diff --git a/apps/csv2sql/test/support/fixtures/duplicate_cols.csv b/test/support/fixtures/duplicate_cols.csv
similarity index 100%
rename from apps/csv2sql/test/support/fixtures/duplicate_cols.csv
rename to test/support/fixtures/duplicate_cols.csv
diff --git a/apps/csv2sql/test/support/fixtures/invalid.csv b/test/support/fixtures/invalid.csv
similarity index 100%
rename from apps/csv2sql/test/support/fixtures/invalid.csv
rename to test/support/fixtures/invalid.csv
diff --git a/apps/csv2sql/test/support/fixtures/invalid_column_names.csv b/test/support/fixtures/invalid_column_names.csv
similarity index 100%
rename from apps/csv2sql/test/support/fixtures/invalid_column_names.csv
rename to test/support/fixtures/invalid_column_names.csv
diff --git a/apps/csv2sql/test/support/fixtures/test.csv b/test/support/fixtures/test.csv
similarity index 100%
rename from apps/csv2sql/test/support/fixtures/test.csv
rename to test/support/fixtures/test.csv
diff --git a/apps/csv2sql/test/support/test_helper.exs b/test/support/test_helper.exs
similarity index 100%
rename from apps/csv2sql/test/support/test_helper.exs
rename to test/support/test_helper.exs
diff --git a/apps/csv2sql/test/test_helper.exs b/test/test_helper.exs
similarity index 100%
rename from apps/csv2sql/test/test_helper.exs
rename to test/test_helper.exs
diff --git a/apps/csv2sql/test/type_deducer/type_checker_test.exs b/test/type_deducer/type_checker_test.exs
similarity index 100%
rename from apps/csv2sql/test/type_deducer/type_checker_test.exs
rename to test/type_deducer/type_checker_test.exs
diff --git a/apps/csv2sql/test/type_deducer/type_deducer_test.exs b/test/type_deducer/type_deducer_test.exs
similarity index 100%
rename from apps/csv2sql/test/type_deducer/type_deducer_test.exs
rename to test/type_deducer/type_deducer_test.exs