Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/common/configs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ defmodule Plsm.Common.Configs do
database_name: Application.get_env(:plsm, :database_name, ""),
username: Application.get_env(:plsm, :username, ""),
password: Application.get_env(:plsm, :password, ""),
type: Application.get_env(:plsm, :type, :mysql)
type: Application.get_env(:plsm, :type, :mysql),
schema: Application.get_env(:plsm, :schema, "public")
}

project_config = %Plsm.Configs.Project{
Expand Down
8 changes: 7 additions & 1 deletion lib/common/structs.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ defmodule Plsm.Configs do
end

defmodule Plsm.Configs.Database do
defstruct server: "", port: "", database_name: "", username: "", password: "", type: :mysql
defstruct server: "",
port: "",
database_name: "",
username: "",
password: "",
type: :mysql,
schema: ""
end

defmodule Plsm.Configs.Project do
Expand Down
12 changes: 8 additions & 4 deletions lib/config/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Plsm.Config.Config do

def write(file_name) do
config_exists? = File.exists?(file_name)

case File.open(file_name, [:append]) do
{:ok, file} -> IO.binwrite(file, output_config(config_exists?))
_ -> {:error, "Could not open file #{file_name}. Please ensure that it exists."}
Expand All @@ -30,15 +31,17 @@ defmodule Plsm.Config.Config do
current
|> append_config_item_string("server", "localhost")
|> append_next_item()
|> append_config_item_string("port", "3306")
|> append_config_item_string("port", "5432")
|> append_next_item()
|> append_config_item_string("database_name", "name of database")
|> append_next_item()
|> append_config_item_string("username", "username")
|> append_config_item_string("username", "postgres")
|> append_next_item()
|> append_config_item_string("password", "postgres")
|> append_next_item()
|> append_config_item_string("password", "password")
|> append_config_item_atom("type", "postgres")
|> append_next_item()
|> append_config_item_atom("type", "mysql")
|> append_config_item_string("schema", "public")
end

defp project_config(current) do
Expand Down Expand Up @@ -71,6 +74,7 @@ defmodule Plsm.Config.Config do
# * username -> The username that is used to connect. Make sure that there is sufficient privileges to be able to connect, query tables as well as query information schemas on the database. The schema information is used to find the index/keys on each table
# * password -> This is necessary as there is no default nor is there any handling of a blank password currently.
# * type -> This dictates which database vendor you are using. We currently support PostgreSQL and MySQL. If no value is entered then it will default to MySQL. Do note that this is an atom and not a string
# * schema -> The database schema namespace for the target tables.
"""
end

Expand Down
87 changes: 66 additions & 21 deletions lib/database/postgresql.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule Plsm.Database.PostgreSQL do
username: "postgres",
password: "postgres",
database_name: "db",
schema: "public",
connection: nil
end

Expand All @@ -15,7 +16,8 @@ defimpl Plsm.Database, for: Plsm.Database.PostgreSQL do
port: configs.database.port,
username: configs.database.username,
password: configs.database.password,
database_name: configs.database.database_name
database_name: configs.database.database_name,
schema: configs.database.schema
}
end

Expand All @@ -30,13 +32,16 @@ defimpl Plsm.Database, for: Plsm.Database.PostgreSQL do
database: db.database_name
)

Postgrex.query!(conn, "SET search_path TO '#{db.schema}';", [])

%Plsm.Database.PostgreSQL{
connection: conn,
server: db.server,
port: db.port,
username: db.username,
password: db.password,
database_name: db.database_name
database_name: db.database_name,
schema: db.schema
}
end

Expand All @@ -46,7 +51,7 @@ defimpl Plsm.Database, for: Plsm.Database.PostgreSQL do
{_, result} =
Postgrex.query(
db.connection,
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';",
"SELECT table_name FROM information_schema.tables WHERE table_schema = '#{db.schema}';",
[]
)

Expand Down Expand Up @@ -124,25 +129,65 @@ defimpl Plsm.Database, for: Plsm.Database.PostgreSQL do
{_, type} = start_type
upcase = String.upcase(type)

custom_types = Application.get_env(:plsm, :custom_types, %{})

cond do
String.starts_with?(upcase, "INTEGER") == true -> :integer
String.starts_with?(upcase, "INT") == true -> :integer
String.starts_with?(upcase, "SMALLINT") == true -> :integer
String.starts_with?(upcase, "BIGINT") == true -> :integer
String.starts_with?(upcase, "CHAR") == true -> :string
String.starts_with?(upcase, "TEXT") == true -> :string
String.starts_with?(upcase, "FLOAT") == true -> :float
String.starts_with?(upcase, "DOUBLE") == true -> :float
String.starts_with?(upcase, "DECIMAL") == true -> :decimal
String.starts_with?(upcase, "NUMERIC") == true -> :decimal
String.starts_with?(upcase, "JSON") == true -> :map
String.starts_with?(upcase, "JSONB") == true -> :map
String.starts_with?(upcase, "DATE") == true -> :date
String.starts_with?(upcase, "DATETIME") == true -> :timestamp
String.starts_with?(upcase, "TIMESTAMP") == true -> :timestamp
String.starts_with?(upcase, "TIME") == true -> :time
String.starts_with?(upcase, "BOOLEAN") == true -> :boolean
true -> :none
String.starts_with?(upcase, "INTEGER") ->
:integer

String.starts_with?(upcase, "INT") ->
:integer

String.starts_with?(upcase, "SMALLINT") ->
:integer

String.starts_with?(upcase, "BIGINT") ->
:integer

String.starts_with?(upcase, "CHAR") ->
:string

String.starts_with?(upcase, "TEXT") ->
:string

String.starts_with?(upcase, "FLOAT") ->
:float

String.starts_with?(upcase, "DOUBLE") ->
:float

String.starts_with?(upcase, "DECIMAL") ->
:decimal

String.starts_with?(upcase, "NUMERIC") ->
:decimal

String.starts_with?(upcase, "JSON") ->
:map

String.starts_with?(upcase, "JSONB") ->
:map

String.starts_with?(upcase, "DATE") ->
:date

String.starts_with?(upcase, "DATETIME") ->
:timestamp

String.starts_with?(upcase, "TIMESTAMP") ->
:timestamp

String.starts_with?(upcase, "TIME") ->
:time

String.starts_with?(upcase, "BOOLEAN") ->
:boolean

String.starts_with?(upcase, "UUID") ->
:uuid

true ->
Map.get(custom_types, upcase, {:none, upcase})
end
end
end
36 changes: 31 additions & 5 deletions lib/io/export.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,35 @@ defmodule Plsm.IO.Export do
defp map_type(:time), do: ":time"
defp map_type(:timestamp), do: ":naive_datetime"
defp map_type(:integer), do: ":integer"
defp map_type(:uuid), do: "Ecto.UUID"

defp map_type({:none, datatype}) do
raise "Unknown column type: #{datatype}"
end

defp map_type(type) when is_atom(type), do: to_string(type)

@doc """
When escaped name and name are the same, source option is not needed
"""
defp type_output_with_source(escaped_name, escaped_name, mapped_type, is_primary_key?),
do: "field :#{escaped_name}, #{mapped_type}, primary_key: #{is_primary_key?}\n"
defp type_output_with_source(escaped_name, escaped_name, mapped_type, is_primary_key?) do
if is_primary_key? do
"field :#{escaped_name}, #{mapped_type}, primary_key: true\n"
else
"field :#{escaped_name}, #{mapped_type}\n"
end
end

@doc """
When escaped name and name are different, add a source option poitning to the original field name as an atom
"""
defp type_output_with_source(escaped_name, name, mapped_type, is_primary_key?),
do:
"field :#{escaped_name}, #{mapped_type}, primary_key: #{is_primary_key?}, source: :\"#{name}\"\n"
defp type_output_with_source(escaped_name, name, mapped_type, is_primary_key?) do
if is_primary_key? do
"field :#{escaped_name}, #{mapped_type}, primary_key: true, source: :\"#{name}\"\n"
else
"field :#{escaped_name}, #{mapped_type}, source: :\"#{name}\"\n"
end
end

@doc """
Write the given schema to file.
Expand All @@ -58,6 +74,7 @@ defmodule Plsm.IO.Export do
module_declaration(project_name, table.header.name) <>
model_inclusion() <>
primary_key_disable() <>
schema_prefix_declaration() <>
schema_declaration(table.header.name)

trimmed_columns = remove_foreign_keys(table.columns)
Expand Down Expand Up @@ -99,6 +116,15 @@ defmodule Plsm.IO.Export do
two_space("@primary_key false\n")
end

defp schema_prefix_declaration do
configs = Plsm.Common.Configs.load_configs()

case configs.database.schema do
"public" -> ""
prefix -> two_space("@schema_prefix \"#{prefix}\"\n")
end
end

defp schema_declaration(table_name) do
two_space("schema \"#{table_name}\" do\n")
end
Expand Down