mirror of
https://github.com/ash-project/ash_postgres.git
synced 2024-09-19 21:13:19 +12:00
improvement: add static schema specification in DSL
improvement: support static schema specification in migration generator
This commit is contained in:
parent
4e85466724
commit
6c5ee9aae5
7 changed files with 501 additions and 143 deletions
|
@ -27,6 +27,7 @@ locals_without_parens = [
|
|||
reference: 1,
|
||||
reference: 2,
|
||||
repo: 1,
|
||||
schema: 1,
|
||||
skip_unique_indexes: 1,
|
||||
table: 1,
|
||||
template: 1,
|
||||
|
|
|
@ -19,6 +19,11 @@ defmodule AshPostgres do
|
|||
Extension.get_opt(resource, [:postgres], :table, nil, true)
|
||||
end
|
||||
|
||||
@doc "The configured schema for a resource"
|
||||
def schema(resource) do
|
||||
Extension.get_opt(resource, [:postgres], :schema, nil, true)
|
||||
end
|
||||
|
||||
@doc "The configured references for a resource"
|
||||
def references(resource) do
|
||||
Extension.get_entities(resource, [:postgres, :references])
|
||||
|
|
|
@ -290,8 +290,19 @@ defmodule AshPostgres.DataLayer do
|
|||
],
|
||||
table: [
|
||||
type: :string,
|
||||
doc:
|
||||
"The table to store and read the resource from. Required unless `polymorphic?` is true."
|
||||
doc: """
|
||||
The table to store and read the resource from. Required unless `polymorphic?` is true.
|
||||
|
||||
If this is changed, the migration generator will not remove the old table.
|
||||
"""
|
||||
],
|
||||
schema: [
|
||||
type: :string,
|
||||
doc: """
|
||||
The schema that the table is located in.
|
||||
Multitenancy supersedes this, so this acts as the schema in the cases that `global?: true` is set.
|
||||
If this is changed, the migration generator will not remove the old table in the old schema.
|
||||
"""
|
||||
],
|
||||
polymorphic?: [
|
||||
type: :boolean,
|
||||
|
@ -320,7 +331,7 @@ defmodule AshPostgres.DataLayer do
|
|||
alias Ash.Filter
|
||||
alias Ash.Query.{BooleanExpression, Not}
|
||||
|
||||
import AshPostgres, only: [repo: 1]
|
||||
import AshPostgres, only: [repo: 1, schema: 1]
|
||||
|
||||
@behaviour Ash.DataLayer
|
||||
|
||||
|
@ -438,6 +449,13 @@ defmodule AshPostgres.DataLayer do
|
|||
data_layer_query
|
||||
end
|
||||
|
||||
data_layer_query =
|
||||
if context[:data_layer][:schema] do
|
||||
Ecto.Query.put_query_prefix(data_layer_query, to_string(context[:data_layer][:schema]))
|
||||
else
|
||||
data_layer_query
|
||||
end
|
||||
|
||||
data_layer_query =
|
||||
data_layer_query
|
||||
|> default_bindings(resource, context)
|
||||
|
@ -474,7 +492,11 @@ defmodule AshPostgres.DataLayer do
|
|||
if Ash.Resource.Info.multitenancy_strategy(resource) == :context do
|
||||
[prefix: tenant]
|
||||
else
|
||||
[]
|
||||
if schema = schema(resource) do
|
||||
[prefix: schema]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|> add_timeout(changeset)
|
||||
end
|
||||
|
@ -491,7 +513,11 @@ defmodule AshPostgres.DataLayer do
|
|||
if Ash.Resource.Info.multitenancy_strategy(resource) == :context do
|
||||
[prefix: tenant]
|
||||
else
|
||||
[]
|
||||
if schema = schema(resource) do
|
||||
[prefix: schema]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|> add_timeout(query)
|
||||
end
|
||||
|
@ -798,7 +824,7 @@ defmodule AshPostgres.DataLayer do
|
|||
data_layer_query
|
||||
| prefix:
|
||||
to_string(
|
||||
source_query.tenant || config[:default_prefix] ||
|
||||
source_query.tenant || schema(resource) || config[:default_prefix] ||
|
||||
"public"
|
||||
)
|
||||
}
|
||||
|
@ -807,7 +833,7 @@ defmodule AshPostgres.DataLayer do
|
|||
data_layer_query
|
||||
| prefix:
|
||||
to_string(
|
||||
config[:default_prefix] ||
|
||||
schema(resource) || config[:default_prefix] ||
|
||||
"public"
|
||||
)
|
||||
}
|
||||
|
@ -932,10 +958,19 @@ defmodule AshPostgres.DataLayer do
|
|||
if AshPostgres.polymorphic?(record.__struct__) do
|
||||
table = changeset.context[:data_layer][:table] || AshPostgres.table(record.__struct__)
|
||||
|
||||
if table do
|
||||
Ecto.put_meta(record, source: table)
|
||||
record =
|
||||
if table do
|
||||
Ecto.put_meta(record, source: table)
|
||||
else
|
||||
raise_table_error!(changeset.resource, operation)
|
||||
end
|
||||
|
||||
prefix = changeset.context[:data_layer][:schema] || AshPostgres.schema(record.__struct__)
|
||||
|
||||
if prefix do
|
||||
Ecto.put_meta(record, prefix: table)
|
||||
else
|
||||
raise_table_error!(changeset.resource, operation)
|
||||
record
|
||||
end
|
||||
else
|
||||
record
|
||||
|
|
|
@ -276,7 +276,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
defp deduplicate_snapshots(snapshots, opts, existing_snapshots \\ []) do
|
||||
snapshots
|
||||
|> Enum.group_by(fn snapshot ->
|
||||
snapshot.table
|
||||
{snapshot.table, snapshot.schema}
|
||||
end)
|
||||
|> Enum.map(fn {_table, [snapshot | _] = snapshots} ->
|
||||
existing_snapshot =
|
||||
|
@ -397,7 +397,8 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
on_delete: merge_uniq!(references, table, :on_delete, name),
|
||||
on_update: merge_uniq!(references, table, :on_update, name),
|
||||
name: merge_uniq!(references, table, :name, name),
|
||||
table: merge_uniq!(references, table, :table, name)
|
||||
table: merge_uniq!(references, table, :table, name),
|
||||
schema: merge_uniq!(references, table, :schema, name)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -762,6 +763,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
attribute: %{
|
||||
source: name
|
||||
},
|
||||
schema: schema,
|
||||
table: table
|
||||
} = add
|
||||
| rest
|
||||
|
@ -770,7 +772,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
) do
|
||||
rest
|
||||
|> Enum.take_while(fn op ->
|
||||
op.table == table
|
||||
op.table == table && op.schema == schema
|
||||
end)
|
||||
|> Enum.with_index()
|
||||
|> Enum.find(fn
|
||||
|
@ -808,40 +810,46 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
end
|
||||
|
||||
defp group_into_phases(
|
||||
[%Operation.CreateTable{table: table, multitenancy: multitenancy} | rest],
|
||||
[
|
||||
%Operation.CreateTable{table: table, schema: schema, multitenancy: multitenancy} | rest
|
||||
],
|
||||
nil,
|
||||
acc
|
||||
) do
|
||||
group_into_phases(rest, %Phase.Create{table: table, multitenancy: multitenancy}, acc)
|
||||
group_into_phases(
|
||||
rest,
|
||||
%Phase.Create{table: table, schema: schema, multitenancy: multitenancy},
|
||||
acc
|
||||
)
|
||||
end
|
||||
|
||||
defp group_into_phases(
|
||||
[%Operation.AddAttribute{table: table} = op | rest],
|
||||
%{table: table} = phase,
|
||||
[%Operation.AddAttribute{table: table, schema: schema} = op | rest],
|
||||
%{table: table, schema: schema} = phase,
|
||||
acc
|
||||
) do
|
||||
group_into_phases(rest, %{phase | operations: [op | phase.operations]}, acc)
|
||||
end
|
||||
|
||||
defp group_into_phases(
|
||||
[%Operation.AlterAttribute{table: table} = op | rest],
|
||||
%Phase.Alter{table: table} = phase,
|
||||
[%Operation.AlterAttribute{table: table, schema: schema} = op | rest],
|
||||
%Phase.Alter{table: table, schema: schema} = phase,
|
||||
acc
|
||||
) do
|
||||
group_into_phases(rest, %{phase | operations: [op | phase.operations]}, acc)
|
||||
end
|
||||
|
||||
defp group_into_phases(
|
||||
[%Operation.RenameAttribute{table: table} = op | rest],
|
||||
%Phase.Alter{table: table} = phase,
|
||||
[%Operation.RenameAttribute{table: table, schema: schema} = op | rest],
|
||||
%Phase.Alter{table: table, schema: schema} = phase,
|
||||
acc
|
||||
) do
|
||||
group_into_phases(rest, %{phase | operations: [op | phase.operations]}, acc)
|
||||
end
|
||||
|
||||
defp group_into_phases(
|
||||
[%Operation.RemoveAttribute{table: table} = op | rest],
|
||||
%{table: table} = phase,
|
||||
[%Operation.RemoveAttribute{table: table, schema: schema} = op | rest],
|
||||
%{table: table, schema: schema} = phase,
|
||||
acc
|
||||
) do
|
||||
group_into_phases(rest, %{phase | operations: [op | phase.operations]}, acc)
|
||||
|
@ -855,7 +863,8 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
phase = %Phase.Alter{
|
||||
operations: [operation],
|
||||
multitenancy: operation.multitenancy,
|
||||
table: operation.table
|
||||
table: operation.table,
|
||||
schema: operation.schema
|
||||
}
|
||||
|
||||
group_into_phases(rest, phase, acc)
|
||||
|
@ -889,25 +898,27 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.AddAttribute{attribute: %{order: l}, table: table},
|
||||
%Operation.AddAttribute{attribute: %{order: r}, table: table}
|
||||
%Operation.AddAttribute{attribute: %{order: l}, table: table, schema: schema},
|
||||
%Operation.AddAttribute{attribute: %{order: r}, table: table, schema: schema}
|
||||
),
|
||||
do: l > r
|
||||
|
||||
defp after?(
|
||||
%Operation.RenameUniqueIndex{
|
||||
table: table
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%{table: table}
|
||||
%{table: table, schema: schema}
|
||||
) do
|
||||
true
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.AddUniqueIndex{
|
||||
table: table
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%{table: table}
|
||||
%{table: table, schema: schema}
|
||||
) do
|
||||
true
|
||||
end
|
||||
|
@ -916,9 +927,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.AddCheckConstraint{
|
||||
constraint: %{attribute: attribute_or_attributes},
|
||||
table: table,
|
||||
multitenancy: multitenancy
|
||||
multitenancy: multitenancy,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.AddAttribute{table: table, attribute: %{source: source}}
|
||||
%Operation.AddAttribute{table: table, attribute: %{source: source}, schema: schema}
|
||||
) do
|
||||
source in List.wrap(attribute_or_attributes) ||
|
||||
(multitenancy.attribute && multitenancy.attribute in List.wrap(attribute_or_attributes))
|
||||
|
@ -926,24 +938,30 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|
||||
defp after?(
|
||||
%Operation.AddCustomIndex{
|
||||
table: table
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.AddAttribute{table: table}
|
||||
%Operation.AddAttribute{table: table, schema: schema}
|
||||
) do
|
||||
true
|
||||
end
|
||||
|
||||
defp after?(%Operation.AddCheckConstraint{table: table}, %Operation.RemoveCheckConstraint{
|
||||
table: table
|
||||
}),
|
||||
defp after?(
|
||||
%Operation.AddCheckConstraint{table: table, schema: schema},
|
||||
%Operation.RemoveCheckConstraint{
|
||||
table: table,
|
||||
schema: schema
|
||||
}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(
|
||||
%Operation.AddCheckConstraint{
|
||||
constraint: %{attribute: attribute_or_attributes},
|
||||
table: table
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.AlterAttribute{table: table, new_attribute: %{source: source}}
|
||||
%Operation.AlterAttribute{table: table, new_attribute: %{source: source}, schema: schema}
|
||||
) do
|
||||
source in List.wrap(attribute_or_attributes)
|
||||
end
|
||||
|
@ -951,43 +969,61 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
defp after?(
|
||||
%Operation.AddCheckConstraint{
|
||||
constraint: %{attribute: attribute_or_attributes},
|
||||
table: table
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.RenameAttribute{table: table, new_attribute: %{source: source}}
|
||||
%Operation.RenameAttribute{
|
||||
table: table,
|
||||
new_attribute: %{source: source},
|
||||
schema: schema
|
||||
}
|
||||
) do
|
||||
source in List.wrap(attribute_or_attributes)
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.RemoveUniqueIndex{table: table},
|
||||
%Operation.AddUniqueIndex{table: table}
|
||||
%Operation.RemoveUniqueIndex{table: table, schema: schema},
|
||||
%Operation.AddUniqueIndex{table: table, schema: schema}
|
||||
) do
|
||||
false
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.RemoveUniqueIndex{table: table},
|
||||
%{table: table}
|
||||
%Operation.RemoveUniqueIndex{table: table, schema: schema},
|
||||
%{table: table, schema: schema}
|
||||
) do
|
||||
true
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.RemoveCheckConstraint{constraint: %{attribute: attributes}, table: table},
|
||||
%Operation.RemoveAttribute{table: table, attribute: %{source: source}}
|
||||
%Operation.RemoveCheckConstraint{
|
||||
constraint: %{attribute: attributes},
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.RemoveAttribute{table: table, attribute: %{source: source}, schema: schema}
|
||||
) do
|
||||
source in List.wrap(attributes)
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.RemoveCheckConstraint{constraint: %{attribute: attributes}, table: table},
|
||||
%Operation.RenameAttribute{table: table, old_attribute: %{source: source}}
|
||||
%Operation.RemoveCheckConstraint{
|
||||
constraint: %{attribute: attributes},
|
||||
table: table,
|
||||
schema: schema
|
||||
},
|
||||
%Operation.RenameAttribute{
|
||||
table: table,
|
||||
old_attribute: %{source: source},
|
||||
schema: schema
|
||||
}
|
||||
) do
|
||||
source in List.wrap(attributes)
|
||||
end
|
||||
|
||||
defp after?(%Operation.AlterAttribute{table: table}, %Operation.DropForeignKey{
|
||||
defp after?(%Operation.AlterAttribute{table: table, schema: schema}, %Operation.DropForeignKey{
|
||||
table: table,
|
||||
schema: schema,
|
||||
direction: :up
|
||||
}),
|
||||
do: true
|
||||
|
@ -995,56 +1031,68 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
defp after?(
|
||||
%Operation.DropForeignKey{
|
||||
table: table,
|
||||
schema: schema,
|
||||
direction: :down
|
||||
},
|
||||
%Operation.AlterAttribute{table: table}
|
||||
%Operation.AlterAttribute{table: table, schema: schema}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(%Operation.AddAttribute{table: table}, %Operation.CreateTable{table: table}) do
|
||||
defp after?(%Operation.AddAttribute{table: table, schema: schema}, %Operation.CreateTable{
|
||||
table: table,
|
||||
schema: schema
|
||||
}) do
|
||||
true
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.AddAttribute{
|
||||
attribute: %{
|
||||
references: %{table: table, destination_field: name}
|
||||
references: %{table: table, destination_field: name, schema: schema}
|
||||
}
|
||||
},
|
||||
%Operation.AddAttribute{table: table, attribute: %{source: name}}
|
||||
%Operation.AddAttribute{table: table, schema: schema, attribute: %{source: name}}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(
|
||||
%Operation.AddAttribute{
|
||||
table: table,
|
||||
schema: schema,
|
||||
attribute: %{
|
||||
primary_key?: false
|
||||
}
|
||||
},
|
||||
%Operation.AddAttribute{table: table, attribute: %{primary_key?: true}}
|
||||
%Operation.AddAttribute{schema: schema, table: table, attribute: %{primary_key?: true}}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(
|
||||
%Operation.AddAttribute{
|
||||
table: table,
|
||||
schema: schema,
|
||||
attribute: %{
|
||||
primary_key?: true
|
||||
}
|
||||
},
|
||||
%Operation.RemoveAttribute{table: table, attribute: %{primary_key?: true}}
|
||||
%Operation.RemoveAttribute{
|
||||
schema: schema,
|
||||
table: table,
|
||||
attribute: %{primary_key?: true}
|
||||
}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(
|
||||
%Operation.AlterAttribute{
|
||||
table: table,
|
||||
schema: schema,
|
||||
new_attribute: %{primary_key?: false},
|
||||
old_attribute: %{primary_key?: true}
|
||||
},
|
||||
%Operation.AddAttribute{
|
||||
table: table,
|
||||
schema: schema,
|
||||
attribute: %{
|
||||
primary_key?: true
|
||||
}
|
||||
|
@ -1053,9 +1101,11 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
do: true
|
||||
|
||||
defp after?(
|
||||
%Operation.RemoveAttribute{attribute: %{source: source}, table: table},
|
||||
%Operation.RemoveAttribute{attribute: %{source: source}, table: table, schema: schema},
|
||||
%Operation.AlterAttribute{
|
||||
old_attribute: %{references: %{table: table, destination_field: source}}
|
||||
old_attribute: %{
|
||||
references: %{table: table, schema: schema, destination_field: source}
|
||||
}
|
||||
}
|
||||
),
|
||||
do: true
|
||||
|
@ -1063,14 +1113,17 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
defp after?(
|
||||
%Operation.AlterAttribute{
|
||||
new_attribute: %{
|
||||
references: %{table: table, destination_field: name}
|
||||
references: %{table: table, schema: schema, destination_field: name}
|
||||
}
|
||||
},
|
||||
%Operation.AddAttribute{table: table, attribute: %{source: name}}
|
||||
%Operation.AddAttribute{schema: schema, table: table, attribute: %{source: name}}
|
||||
),
|
||||
do: true
|
||||
|
||||
defp after?(%Operation.AddCheckConstraint{table: table}, %Operation.CreateTable{table: table}) do
|
||||
defp after?(%Operation.AddCheckConstraint{table: table, schema: schema}, %Operation.CreateTable{
|
||||
table: table,
|
||||
schema: schema
|
||||
}) do
|
||||
true
|
||||
end
|
||||
|
||||
|
@ -1098,10 +1151,21 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|
||||
defp do_fetch_operations(snapshot, existing_snapshot, opts, acc \\ [])
|
||||
|
||||
defp do_fetch_operations(
|
||||
%{schema: new_schema} = snapshot,
|
||||
%{schema: old_schema},
|
||||
opts,
|
||||
[]
|
||||
)
|
||||
when new_schema != old_schema do
|
||||
do_fetch_operations(snapshot, nil, opts, [])
|
||||
end
|
||||
|
||||
defp do_fetch_operations(snapshot, nil, opts, acc) do
|
||||
empty_snapshot = %{
|
||||
attributes: [],
|
||||
identities: [],
|
||||
schema: nil,
|
||||
custom_indexes: [],
|
||||
check_constraints: [],
|
||||
table: snapshot.table,
|
||||
|
@ -1117,6 +1181,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
do_fetch_operations(snapshot, empty_snapshot, opts, [
|
||||
%Operation.CreateTable{
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
multitenancy: snapshot.multitenancy,
|
||||
old_multitenancy: empty_snapshot.multitenancy
|
||||
}
|
||||
|
@ -1138,9 +1203,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn custom_index ->
|
||||
%Operation.AddCustomIndex{
|
||||
index: custom_index,
|
||||
table: old_snapshot.table,
|
||||
multitenancy: old_snapshot.multitenancy,
|
||||
base_filter: old_snapshot.base_filter
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
multitenancy: snapshot.multitenancy,
|
||||
base_filter: snapshot.base_filter
|
||||
}
|
||||
end)
|
||||
|
||||
|
@ -1154,9 +1220,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn custom_index ->
|
||||
%Operation.RemoveCustomIndex{
|
||||
index: custom_index,
|
||||
table: snapshot.table,
|
||||
multitenancy: snapshot.multitenancy,
|
||||
base_filter: snapshot.base_filter
|
||||
table: old_snapshot.table,
|
||||
schema: old_snapshot.schema,
|
||||
multitenancy: old_snapshot.multitenancy,
|
||||
base_filter: old_snapshot.base_filter
|
||||
}
|
||||
end)
|
||||
|
||||
|
@ -1173,7 +1240,11 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
end)
|
||||
end
|
||||
|> Enum.map(fn identity ->
|
||||
%Operation.RemoveUniqueIndex{identity: identity, table: snapshot.table}
|
||||
%Operation.RemoveUniqueIndex{
|
||||
identity: identity,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema
|
||||
}
|
||||
end)
|
||||
|
||||
unique_indexes_to_rename =
|
||||
|
@ -1195,6 +1266,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.RenameUniqueIndex{
|
||||
old_identity: old_identity,
|
||||
new_identity: new_identity,
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
}
|
||||
end)
|
||||
|
@ -1214,6 +1286,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn identity ->
|
||||
%Operation.AddUniqueIndex{
|
||||
identity: identity,
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
}
|
||||
end)
|
||||
|
@ -1228,7 +1301,8 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn constraint ->
|
||||
%Operation.AddCheckConstraint{
|
||||
constraint: constraint,
|
||||
table: snapshot.table
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema
|
||||
}
|
||||
end)
|
||||
|
||||
|
@ -1242,7 +1316,8 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.map(fn old_constraint ->
|
||||
%Operation.RemoveCheckConstraint{
|
||||
constraint: old_constraint,
|
||||
table: old_snapshot.table
|
||||
table: old_snapshot.table,
|
||||
schema: old_snapshot.schema
|
||||
}
|
||||
end)
|
||||
|
||||
|
@ -1289,7 +1364,12 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|
||||
rename_attribute_events =
|
||||
Enum.map(attributes_to_rename, fn {new, old} ->
|
||||
%Operation.RenameAttribute{new_attribute: new, old_attribute: old, table: snapshot.table}
|
||||
%Operation.RenameAttribute{
|
||||
new_attribute: new,
|
||||
old_attribute: old,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema
|
||||
}
|
||||
end)
|
||||
|
||||
add_attribute_events =
|
||||
|
@ -1298,16 +1378,19 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
[
|
||||
%Operation.AddAttribute{
|
||||
attribute: Map.delete(attribute, :references),
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
},
|
||||
%Operation.AlterAttribute{
|
||||
old_attribute: Map.delete(attribute, :references),
|
||||
new_attribute: attribute,
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
},
|
||||
%Operation.DropForeignKey{
|
||||
attribute: attribute,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
multitenancy: Map.get(attribute, :multitenancy),
|
||||
direction: :down
|
||||
}
|
||||
|
@ -1316,7 +1399,8 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
[
|
||||
%Operation.AddAttribute{
|
||||
attribute: attribute,
|
||||
table: snapshot.table
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema
|
||||
}
|
||||
]
|
||||
end
|
||||
|
@ -1330,12 +1414,14 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.DropForeignKey{
|
||||
attribute: old_attribute,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
multitenancy: old_snapshot.multitenancy,
|
||||
direction: :up
|
||||
},
|
||||
%Operation.AlterAttribute{
|
||||
new_attribute: new_attribute,
|
||||
old_attribute: old_attribute,
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
}
|
||||
]
|
||||
|
@ -1346,6 +1432,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.DropForeignKey{
|
||||
attribute: new_attribute,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
multitenancy: snapshot.multitenancy,
|
||||
direction: :down
|
||||
}
|
||||
|
@ -1358,6 +1445,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.AlterAttribute{
|
||||
new_attribute: Map.delete(new_attribute, :references),
|
||||
old_attribute: Map.delete(old_attribute, :references),
|
||||
schema: snapshot.schema,
|
||||
table: snapshot.table
|
||||
}
|
||||
]
|
||||
|
@ -1369,6 +1457,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
%Operation.RemoveAttribute{
|
||||
attribute: attribute,
|
||||
table: snapshot.table,
|
||||
schema: snapshot.schema,
|
||||
commented?: !opts.drop_columns
|
||||
}
|
||||
end)
|
||||
|
@ -1572,7 +1661,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Enum.uniq()
|
||||
|> Enum.map(fn relationship ->
|
||||
resource
|
||||
|> do_snapshot(relationship.context[:data_layer][:table])
|
||||
|> do_snapshot(
|
||||
relationship.context[:data_layer][:table],
|
||||
relationship.context[:data_layer][:schema]
|
||||
)
|
||||
|> Map.update!(:identities, fn identities ->
|
||||
identity_index_names = AshPostgres.identity_index_names(resource)
|
||||
|
||||
|
@ -1603,6 +1695,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
destination_field_generated: source_attribute.generated?,
|
||||
multitenancy: multitenancy(relationship.source),
|
||||
table: AshPostgres.table(relationship.source),
|
||||
schema: AshPostgres.table(relationship.source),
|
||||
on_delete: AshPostgres.polymorphic_on_delete(relationship.source),
|
||||
on_update: AshPostgres.polymorphic_on_update(relationship.source),
|
||||
name:
|
||||
|
@ -1620,11 +1713,12 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
end
|
||||
end
|
||||
|
||||
defp do_snapshot(resource, table) do
|
||||
defp do_snapshot(resource, table, schema \\ nil) do
|
||||
snapshot = %{
|
||||
attributes: attributes(resource, table),
|
||||
identities: identities(resource),
|
||||
table: table || AshPostgres.table(resource),
|
||||
schema: schema || AshPostgres.schema(resource),
|
||||
check_constraints: check_constraints(resource),
|
||||
custom_indexes: custom_indexes(resource),
|
||||
repo: AshPostgres.repo(resource),
|
||||
|
@ -1776,6 +1870,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
on_delete: configured_reference.on_delete,
|
||||
on_update: configured_reference.on_update,
|
||||
name: configured_reference.name,
|
||||
schema:
|
||||
relationship.context[:data_layer][:schema] ||
|
||||
AshPostgres.schema(relationship.destination) ||
|
||||
AshPostgres.repo(relationship.destination).config()[:default_prefix],
|
||||
table:
|
||||
relationship.context[:data_layer][:table] ||
|
||||
AshPostgres.table(relationship.destination)
|
||||
|
@ -1792,6 +1890,10 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
|> Kernel.||(%{
|
||||
on_delete: nil,
|
||||
on_update: nil,
|
||||
schema:
|
||||
relationship.context[:data_layer][:schema] ||
|
||||
AshPostgres.schema(relationship.destination) ||
|
||||
AshPostgres.repo(relationship.destination).config()[:default_prefix],
|
||||
name: nil
|
||||
})
|
||||
|
||||
|
@ -1929,6 +2031,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
defp sanitize_snapshot(snapshot) do
|
||||
snapshot
|
||||
|> Map.put_new(:has_create_action, true)
|
||||
|> Map.put_new(:schema, nil)
|
||||
|> Map.update!(:identities, fn identities ->
|
||||
Enum.map(identities, &load_identity(&1, snapshot.table))
|
||||
end)
|
||||
|
@ -2007,6 +2110,7 @@ defmodule AshPostgres.MigrationGenerator do
|
|||
references ->
|
||||
references
|
||||
|> Map.update!(:destination_field, &String.to_atom/1)
|
||||
|> Map.put_new(:schema, nil)
|
||||
|> Map.put_new(:destination_field_default, "nil")
|
||||
|> Map.put_new(:destination_field_generated, false)
|
||||
|> Map.put_new(:on_delete, nil)
|
||||
|
|
|
@ -20,6 +20,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
def maybe_add_null(false), do: "null: false"
|
||||
def maybe_add_null(_), do: nil
|
||||
|
||||
def maybe_add_prefix(nil), do: nil
|
||||
def maybe_add_prefix(prefix), do: "prefix: #{prefix}"
|
||||
|
||||
def in_quotes(nil), do: nil
|
||||
def in_quotes(value), do: "\"#{value}\""
|
||||
|
||||
def option(key, value) do
|
||||
if value do
|
||||
"#{key}: #{inspect(value)}"
|
||||
|
@ -60,12 +66,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
defmodule CreateTable do
|
||||
@moduledoc false
|
||||
defstruct [:table, :multitenancy, :old_multitenancy]
|
||||
defstruct [:table, :schema, :multitenancy, :old_multitenancy]
|
||||
end
|
||||
|
||||
defmodule AddAttribute do
|
||||
@moduledoc false
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy]
|
||||
defstruct [:attribute, :table, :schema, :multitenancy, :old_multitenancy]
|
||||
|
||||
import Helper
|
||||
|
||||
|
@ -77,6 +83,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
%{
|
||||
table: table,
|
||||
destination_field: destination_field,
|
||||
schema: destination_schema,
|
||||
multitenancy: %{strategy: :attribute, attribute: destination_attribute}
|
||||
} = reference
|
||||
} = attribute
|
||||
|
@ -99,6 +106,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
with_match,
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
option("prefix", destination_schema),
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
size
|
||||
|
@ -119,6 +127,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
%{
|
||||
table: table,
|
||||
destination_field: destination_field,
|
||||
schema: destination_schema,
|
||||
multitenancy: %{strategy: :attribute}
|
||||
} = reference
|
||||
} = attribute
|
||||
|
@ -133,7 +142,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"references(:#{table}",
|
||||
[
|
||||
"column: #{inspect(destination_field)}",
|
||||
"prefix: \"public\"",
|
||||
option("prefix", destination_schema),
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
|
@ -212,11 +221,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
def up(%{
|
||||
multitenancy: %{strategy: :context},
|
||||
schema: schema,
|
||||
attribute:
|
||||
%{
|
||||
references:
|
||||
%{
|
||||
table: table,
|
||||
schema: destination_schema,
|
||||
destination_field: destination_field
|
||||
} = reference
|
||||
} = attribute
|
||||
|
@ -226,6 +237,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
destination_schema =
|
||||
if schema != destination_schema do
|
||||
destination_schema
|
||||
end
|
||||
|
||||
[
|
||||
"add #{inspect(attribute.source)}",
|
||||
"references(:#{table}",
|
||||
|
@ -233,7 +249,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"column: #{inspect(destination_field)}",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
"prefix: \"public\"",
|
||||
option("prefix", destination_schema),
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
|
@ -248,8 +264,11 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
def up(%{
|
||||
attribute:
|
||||
%{references: %{table: table, destination_field: destination_field} = reference} =
|
||||
attribute
|
||||
%{
|
||||
references:
|
||||
%{table: table, schema: destination_schema, destination_field: destination_field} =
|
||||
reference
|
||||
} = attribute
|
||||
}) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
|
@ -263,6 +282,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"column: #{inspect(destination_field)}",
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
option("prefix", destination_schema),
|
||||
size,
|
||||
on_delete(reference),
|
||||
on_update(reference)
|
||||
|
@ -330,7 +350,14 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
defmodule AlterAttribute do
|
||||
@moduledoc false
|
||||
defstruct [:old_attribute, :new_attribute, :table, :multitenancy, :old_multitenancy]
|
||||
defstruct [
|
||||
:old_attribute,
|
||||
:new_attribute,
|
||||
:table,
|
||||
:schema,
|
||||
:multitenancy,
|
||||
:old_multitenancy
|
||||
]
|
||||
|
||||
import Helper
|
||||
|
||||
|
@ -360,12 +387,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
def up(%{
|
||||
multitenancy: multitenancy,
|
||||
old_attribute: old_attribute,
|
||||
new_attribute: attribute
|
||||
new_attribute: attribute,
|
||||
schema: schema
|
||||
}) do
|
||||
type_or_reference =
|
||||
if AshPostgres.MigrationGenerator.has_reference?(multitenancy, attribute) and
|
||||
Map.get(old_attribute, :references) != Map.get(attribute, :references) do
|
||||
reference(multitenancy, attribute)
|
||||
reference(multitenancy, attribute, schema)
|
||||
else
|
||||
inspect(attribute.type)
|
||||
end
|
||||
|
@ -382,7 +410,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
table: table,
|
||||
destination_field: destination_field
|
||||
} = reference
|
||||
} = attribute
|
||||
} = attribute,
|
||||
_schema
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
|
@ -408,10 +437,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
%{
|
||||
multitenancy: %{strategy: :attribute, attribute: destination_attribute},
|
||||
table: table,
|
||||
schema: destination_schema,
|
||||
destination_field: destination_field
|
||||
} = reference
|
||||
} = attribute
|
||||
} = attribute,
|
||||
schema
|
||||
) do
|
||||
destination_schema =
|
||||
if schema != destination_schema do
|
||||
destination_schema
|
||||
end
|
||||
|
||||
with_match =
|
||||
if destination_attribute != destination_field do
|
||||
"with: [#{source_attribute}: :#{destination_attribute}], match: :full"
|
||||
|
@ -428,6 +464,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
option("prefix", destination_schema),
|
||||
on_delete(reference),
|
||||
on_update(reference),
|
||||
")"
|
||||
|
@ -440,17 +477,25 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
references:
|
||||
%{
|
||||
table: table,
|
||||
destination_field: destination_field
|
||||
destination_field: destination_field,
|
||||
schema: destination_schema
|
||||
} = reference
|
||||
} = attribute
|
||||
} = attribute,
|
||||
schema
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
end
|
||||
|
||||
destination_schema =
|
||||
if schema != destination_schema do
|
||||
destination_schema
|
||||
end
|
||||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}, prefix: \"public\"",
|
||||
"references(:#{table}, column: #{inspect(destination_field)}",
|
||||
option("prefix", destination_schema),
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
|
@ -466,10 +511,17 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
references:
|
||||
%{
|
||||
table: table,
|
||||
destination_field: destination_field
|
||||
destination_field: destination_field,
|
||||
schema: destination_schema
|
||||
} = reference
|
||||
} = attribute
|
||||
} = attribute,
|
||||
schema
|
||||
) do
|
||||
destination_schema =
|
||||
if schema != destination_schema do
|
||||
destination_schema
|
||||
end
|
||||
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
|
@ -477,6 +529,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
join([
|
||||
"references(:#{table}, column: #{inspect(destination_field)}",
|
||||
option("prefix", destination_schema),
|
||||
"name: #{inspect(reference.name)}",
|
||||
"type: #{inspect(reference_type(attribute, reference))}",
|
||||
size,
|
||||
|
@ -502,18 +555,25 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
# We only run this migration in one direction, based on the input
|
||||
# This is because the creation of a foreign key is handled by `references/3`
|
||||
# We only need to drop it before altering an attribute with `references/3`
|
||||
defstruct [:attribute, :table, :multitenancy, :direction, no_phase: true]
|
||||
defstruct [:attribute, :schema, :table, :multitenancy, :direction, no_phase: true]
|
||||
|
||||
def up(%{table: table, attribute: %{references: reference}, direction: :up}) do
|
||||
"drop constraint(:#{table}, #{inspect(reference.name)})"
|
||||
import Helper
|
||||
|
||||
def up(%{table: table, schema: schema, attribute: %{references: reference}, direction: :up}) do
|
||||
"drop constraint(:#{table}, #{join([inspect(reference.name), option("prefix", schema)])})"
|
||||
end
|
||||
|
||||
def up(_) do
|
||||
""
|
||||
end
|
||||
|
||||
def down(%{table: table, attribute: %{references: reference}, direction: :down}) do
|
||||
"drop constraint(:#{table}, #{inspect(reference.name)})"
|
||||
def down(%{
|
||||
table: table,
|
||||
schema: schema,
|
||||
attribute: %{references: reference},
|
||||
direction: :down
|
||||
}) do
|
||||
"drop constraint(:#{table}, #{join([inspect(reference.name), option("prefix", schema)])})"
|
||||
end
|
||||
|
||||
def down(_) do
|
||||
|
@ -527,23 +587,36 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
:old_attribute,
|
||||
:new_attribute,
|
||||
:table,
|
||||
:schema,
|
||||
:multitenancy,
|
||||
:old_multitenancy,
|
||||
no_phase: true
|
||||
]
|
||||
|
||||
def up(%{old_attribute: old_attribute, new_attribute: new_attribute, table: table}) do
|
||||
"rename table(:#{table}), #{inspect(old_attribute.source)}, to: #{inspect(new_attribute.source)}"
|
||||
import Helper
|
||||
|
||||
def up(%{
|
||||
old_attribute: old_attribute,
|
||||
new_attribute: new_attribute,
|
||||
schema: schema,
|
||||
table: table
|
||||
}) do
|
||||
"rename table(:#{table}), #{inspect(old_attribute.source)}, to: #{join([inspect(new_attribute.source), option("prefix", schema)])}"
|
||||
end
|
||||
|
||||
def down(%{new_attribute: old_attribute, old_attribute: new_attribute, table: table}) do
|
||||
"rename table(:#{table}), #{inspect(old_attribute.source)}, to: #{inspect(new_attribute.source)}"
|
||||
def down(
|
||||
%{
|
||||
new_attribute: old_attribute,
|
||||
old_attribute: new_attribute
|
||||
} = data
|
||||
) do
|
||||
up(%{data | new_attribute: old_attribute, old_attribute: new_attribute})
|
||||
end
|
||||
end
|
||||
|
||||
defmodule RemoveAttribute do
|
||||
@moduledoc false
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy, commented?: true]
|
||||
defstruct [:attribute, :schema, :table, :multitenancy, :old_multitenancy, commented?: true]
|
||||
|
||||
def up(%{attribute: attribute, commented?: true}) do
|
||||
"""
|
||||
|
@ -577,10 +650,12 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
prefix <> "\n" <> contents
|
||||
end
|
||||
|
||||
def down(%{attribute: attribute, multitenancy: multitenancy}) do
|
||||
def down(%{attribute: attribute, multitenancy: multitenancy, table: table, schema: schema}) do
|
||||
AshPostgres.MigrationGenerator.Operation.AddAttribute.up(
|
||||
%AshPostgres.MigrationGenerator.Operation.AddAttribute{
|
||||
attribute: attribute,
|
||||
table: table,
|
||||
schema: schema,
|
||||
multitenancy: multitenancy
|
||||
}
|
||||
)
|
||||
|
@ -589,11 +664,14 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
defmodule AddUniqueIndex do
|
||||
@moduledoc false
|
||||
defstruct [:identity, :table, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
defstruct [:identity, :table, :schema, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
|
||||
import Helper
|
||||
|
||||
def up(%{
|
||||
identity: %{name: name, keys: keys, base_filter: base_filter, index_name: index_name},
|
||||
table: table,
|
||||
schema: schema,
|
||||
multitenancy: multitenancy
|
||||
}) do
|
||||
keys =
|
||||
|
@ -608,15 +686,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
index_name = index_name || "#{table}_#{name}_index"
|
||||
|
||||
if base_filter do
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\", where: \"#{base_filter}\")"
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], where: \"#{base_filter}\", #{join(["name: \"#{index_name}\"", option("prefix", schema)])})"
|
||||
else
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option("prefix", schema)])})"
|
||||
end
|
||||
end
|
||||
|
||||
def down(%{
|
||||
identity: %{name: name, keys: keys, index_name: index_name},
|
||||
table: table,
|
||||
schema: schema,
|
||||
multitenancy: multitenancy
|
||||
}) do
|
||||
keys =
|
||||
|
@ -630,18 +709,19 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
index_name = index_name || "#{table}_#{name}_index"
|
||||
|
||||
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option("prefix", schema)])})"
|
||||
end
|
||||
end
|
||||
|
||||
defmodule AddCustomIndex do
|
||||
@moduledoc false
|
||||
defstruct [:table, :index, :base_filter, :multitenancy, no_phase: true]
|
||||
defstruct [:table, :schema, :index, :base_filter, :multitenancy, no_phase: true]
|
||||
import Helper
|
||||
|
||||
def up(%{
|
||||
index: index,
|
||||
table: table,
|
||||
schema: schema,
|
||||
base_filter: base_filter,
|
||||
multitenancy: multitenancy
|
||||
}) do
|
||||
|
@ -669,7 +749,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
option(:using, index.using),
|
||||
option(:prefix, index.prefix),
|
||||
option(:where, index.where),
|
||||
option(:include, index.include)
|
||||
option(:include, index.include),
|
||||
option(:prefix, schema)
|
||||
])
|
||||
|
||||
if opts == "",
|
||||
|
@ -677,7 +758,7 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
else: "create index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{opts})"
|
||||
end
|
||||
|
||||
def down(%{index: index, table: table, multitenancy: multitenancy}) do
|
||||
def down(%{schema: schema, index: index, table: table, multitenancy: multitenancy}) do
|
||||
index_name = AshPostgres.CustomIndex.name(table, index)
|
||||
|
||||
keys =
|
||||
|
@ -689,16 +770,16 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
index.fields
|
||||
end
|
||||
|
||||
"drop_if_exists index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"drop_if_exists index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})"
|
||||
end
|
||||
end
|
||||
|
||||
defmodule RemoveCustomIndex do
|
||||
@moduledoc false
|
||||
defstruct [:table, :index, :base_filter, :multitenancy, no_phase: true]
|
||||
defstruct [:schema, :table, :index, :base_filter, :multitenancy, no_phase: true]
|
||||
import Helper
|
||||
|
||||
def up(%{index: index, table: table, multitenancy: multitenancy}) do
|
||||
def up(%{index: index, table: table, multitenancy: multitenancy, schema: schema}) do
|
||||
index_name = AshPostgres.CustomIndex.name(table, index)
|
||||
|
||||
keys =
|
||||
|
@ -710,12 +791,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
index.fields
|
||||
end
|
||||
|
||||
"drop_if_exists index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"drop_if_exists index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})"
|
||||
end
|
||||
|
||||
def down(%{
|
||||
index: index,
|
||||
table: table,
|
||||
schema: schema,
|
||||
base_filter: base_filter,
|
||||
multitenancy: multitenancy
|
||||
}) do
|
||||
|
@ -743,7 +825,8 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
option(:using, index.using),
|
||||
option(:prefix, index.prefix),
|
||||
option(:where, index.where),
|
||||
option(:include, index.include)
|
||||
option(:include, index.include),
|
||||
option(:prefix, schema)
|
||||
])
|
||||
|
||||
"create index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{opts})"
|
||||
|
@ -756,41 +839,55 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
:new_identity,
|
||||
:old_identity,
|
||||
:table,
|
||||
:schema,
|
||||
:multitenancy,
|
||||
:old_multitenancy,
|
||||
no_phase: true
|
||||
]
|
||||
|
||||
defp prefix_name(name, prefix) do
|
||||
if prefix do
|
||||
"#{prefix}.#{name}"
|
||||
else
|
||||
name
|
||||
end
|
||||
end
|
||||
|
||||
def up(%{
|
||||
old_identity: %{index_name: old_index_name, name: old_name},
|
||||
new_identity: %{index_name: new_index_name},
|
||||
schema: schema,
|
||||
table: table
|
||||
}) do
|
||||
old_index_name = old_index_name || "#{table}_#{old_name}_index"
|
||||
|
||||
"execute(\"ALTER INDEX #{old_index_name} " <>
|
||||
"RENAME TO #{new_index_name}\")\n"
|
||||
"execute(\"ALTER INDEX #{prefix_name(old_index_name, schema)} " <>
|
||||
"RENAME TO #{prefix_name(new_index_name, schema)}\")\n"
|
||||
end
|
||||
|
||||
def down(%{
|
||||
old_identity: %{index_name: old_index_name, name: old_name},
|
||||
new_identity: %{index_name: new_index_name},
|
||||
schema: schema,
|
||||
table: table
|
||||
}) do
|
||||
old_index_name = old_index_name || "#{table}_#{old_name}_index"
|
||||
|
||||
"execute(\"ALTER INDEX #{new_index_name} " <>
|
||||
"RENAME TO #{old_index_name}\")\n"
|
||||
"execute(\"ALTER INDEX #{prefix_name(new_index_name, schema)} " <>
|
||||
"RENAME TO #{prefix_name(old_index_name, schema)}\")\n"
|
||||
end
|
||||
end
|
||||
|
||||
defmodule RemoveUniqueIndex do
|
||||
@moduledoc false
|
||||
defstruct [:identity, :table, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
defstruct [:identity, :schema, :table, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
|
||||
import Helper
|
||||
|
||||
def up(%{
|
||||
identity: %{name: name, keys: keys, index_name: index_name},
|
||||
table: table,
|
||||
schema: schema,
|
||||
old_multitenancy: multitenancy
|
||||
}) do
|
||||
keys =
|
||||
|
@ -804,12 +901,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
|
||||
index_name = index_name || "#{table}_#{name}_index"
|
||||
|
||||
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"drop_if_exists unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})"
|
||||
end
|
||||
|
||||
def down(%{
|
||||
identity: %{name: name, keys: keys, base_filter: base_filter, index_name: index_name},
|
||||
table: table,
|
||||
schema: schema,
|
||||
multitenancy: multitenancy
|
||||
}) do
|
||||
keys =
|
||||
|
@ -824,18 +922,21 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
index_name = index_name || "#{table}_#{name}_index"
|
||||
|
||||
if base_filter do
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\", where: \"#{base_filter}\")"
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], where: \"#{base_filter}\", #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})"
|
||||
else
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], name: \"#{index_name}\")"
|
||||
"create unique_index(:#{table}, [#{Enum.map_join(keys, ",", &inspect/1)}], #{join(["name: \"#{index_name}\"", option(:prefix, schema)])})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule AddCheckConstraint do
|
||||
@moduledoc false
|
||||
defstruct [:table, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
defstruct [:table, :schema, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
|
||||
import Helper
|
||||
|
||||
def up(%{
|
||||
schema: schema,
|
||||
constraint: %{
|
||||
name: name,
|
||||
check: check,
|
||||
|
@ -844,26 +945,29 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
table: table
|
||||
}) do
|
||||
if base_filter do
|
||||
"create constraint(:#{table}, :#{name}, check: \"#{base_filter} AND #{check}\")"
|
||||
"create constraint(:#{table}, :#{name}, #{join(["check: \"#{base_filter} AND #{check}\")", option(:prefix, schema)])}"
|
||||
else
|
||||
"create constraint(:#{table}, :#{name}, check: \"#{check}\")"
|
||||
"create constraint(:#{table}, :#{name}, #{join(["check: \"#{check}\")", option(:prefix, schema)])}"
|
||||
end
|
||||
end
|
||||
|
||||
def down(%{
|
||||
constraint: %{name: name},
|
||||
schema: schema,
|
||||
table: table
|
||||
}) do
|
||||
"drop_if_exists constraint(:#{table}, :#{name})"
|
||||
"drop_if_exists constraint(:#{table}, #{join([":#{name}", option(:prefix, schema)])})"
|
||||
end
|
||||
end
|
||||
|
||||
defmodule RemoveCheckConstraint do
|
||||
@moduledoc false
|
||||
defstruct [:table, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
defstruct [:table, :schema, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
||||
|
||||
def up(%{constraint: %{name: name}, table: table}) do
|
||||
"drop_if_exists constraint(:#{table}, :#{name})"
|
||||
import Helper
|
||||
|
||||
def up(%{constraint: %{name: name}, schema: schema, table: table}) do
|
||||
"drop_if_exists constraint(:#{table}, #{join([":#{name}", option(:prefix, schema)])})"
|
||||
end
|
||||
|
||||
def down(%{
|
||||
|
@ -872,12 +976,13 @@ defmodule AshPostgres.MigrationGenerator.Operation do
|
|||
check: check,
|
||||
base_filter: base_filter
|
||||
},
|
||||
schema: schema,
|
||||
table: table
|
||||
}) do
|
||||
if base_filter do
|
||||
"create constraint(:#{table}, :#{name}, check: \"#{base_filter} AND #{check}\")"
|
||||
"create constraint(:#{table}, :#{name}, #{join(["check: \"#{base_filter} AND #{check}\")", option(:prefix, schema)])}"
|
||||
else
|
||||
"create constraint(:#{table}, :#{name}, check: \"#{check}\")"
|
||||
"create constraint(:#{table}, :#{name}, #{join(["check: \"#{check}\")", option(:prefix, schema)])}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,34 +3,48 @@ defmodule AshPostgres.MigrationGenerator.Phase do
|
|||
|
||||
defmodule Create do
|
||||
@moduledoc false
|
||||
defstruct [:table, :multitenancy, operations: [], commented?: false]
|
||||
defstruct [:table, :schema, :multitenancy, operations: [], commented?: false]
|
||||
|
||||
def up(%{table: table, operations: operations, multitenancy: multitenancy}) do
|
||||
def up(%{schema: schema, table: table, operations: operations, multitenancy: multitenancy}) do
|
||||
if multitenancy.strategy == :context do
|
||||
"create table(:#{table}, primary_key: false, prefix: prefix()) do\n" <>
|
||||
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <>
|
||||
"\nend"
|
||||
else
|
||||
"create table(:#{table}, primary_key: false) do\n" <>
|
||||
opts =
|
||||
if schema do
|
||||
", prefix: \"#{schema}\""
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
"create table(:#{table}, primary_key: false#{opts}) do\n" <>
|
||||
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <>
|
||||
"\nend"
|
||||
end
|
||||
end
|
||||
|
||||
def down(%{table: table, multitenancy: multitenancy}) do
|
||||
def down(%{schema: schema, table: table, multitenancy: multitenancy}) do
|
||||
if multitenancy.strategy == :context do
|
||||
"drop table(:#{inspect(table)}, prefix: prefix())"
|
||||
else
|
||||
"drop table(:#{inspect(table)})"
|
||||
opts =
|
||||
if schema do
|
||||
", prefix: \"#{schema}\""
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
"drop table(:#{inspect(table)}#{opts})"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Alter do
|
||||
@moduledoc false
|
||||
defstruct [:table, :multitenancy, operations: [], commented?: false]
|
||||
defstruct [:schema, :table, :multitenancy, operations: [], commented?: false]
|
||||
|
||||
def up(%{table: table, operations: operations, multitenancy: multitenancy}) do
|
||||
def up(%{table: table, schema: schema, operations: operations, multitenancy: multitenancy}) do
|
||||
body =
|
||||
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end)
|
||||
|
||||
|
@ -39,13 +53,20 @@ defmodule AshPostgres.MigrationGenerator.Phase do
|
|||
body <>
|
||||
"\nend"
|
||||
else
|
||||
"alter table(:#{table}) do\n" <>
|
||||
opts =
|
||||
if schema do
|
||||
", prefix: \"#{schema}\""
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
"alter table(:#{table}#{opts}) do\n" <>
|
||||
body <>
|
||||
"\nend"
|
||||
end
|
||||
end
|
||||
|
||||
def down(%{table: table, operations: operations, multitenancy: multitenancy}) do
|
||||
def down(%{table: table, schema: schema, operations: operations, multitenancy: multitenancy}) do
|
||||
body =
|
||||
operations
|
||||
|> Enum.reverse()
|
||||
|
@ -56,7 +77,14 @@ defmodule AshPostgres.MigrationGenerator.Phase do
|
|||
body <>
|
||||
"\nend"
|
||||
else
|
||||
"alter table(:#{table}) do\n" <>
|
||||
opts =
|
||||
if schema do
|
||||
", prefix: \"#{schema}\""
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
"alter table(:#{table}#{opts}) do\n" <>
|
||||
body <>
|
||||
"\nend"
|
||||
end
|
||||
|
|
|
@ -128,6 +128,86 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "creating initial snapshots for resources with a schema" do
|
||||
setup do
|
||||
on_exit(fn ->
|
||||
File.rm_rf!("test_snapshots_path")
|
||||
File.rm_rf!("test_migration_path")
|
||||
end)
|
||||
|
||||
defposts do
|
||||
postgres do
|
||||
migration_types second_title: {:varchar, 16}
|
||||
schema("example")
|
||||
end
|
||||
|
||||
identities do
|
||||
identity(:title, [:title])
|
||||
end
|
||||
|
||||
attributes do
|
||||
uuid_primary_key(:id)
|
||||
attribute(:title, :string)
|
||||
attribute(:second_title, :string)
|
||||
end
|
||||
end
|
||||
|
||||
defapi([Post])
|
||||
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
||||
{:ok, _} =
|
||||
Ecto.Adapters.SQL.query(
|
||||
AshPostgres.TestRepo,
|
||||
"""
|
||||
CREATE SCHEMA IF NOT EXISTS example;
|
||||
"""
|
||||
)
|
||||
|
||||
AshPostgres.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
format: false
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
test "the migration sets up resources correctly" do
|
||||
# the snapshot exists and contains valid json
|
||||
assert File.read!(Path.wildcard("test_snapshots_path/test_repo/posts/*.json"))
|
||||
|> Jason.decode!(keys: :atoms!)
|
||||
|
||||
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
||||
|
||||
file_contents = File.read!(file)
|
||||
|
||||
# the migration creates the table
|
||||
assert file_contents =~ "create table(:posts, primary_key: false, prefix: \"example\") do"
|
||||
|
||||
# the migration sets up the custom_indexes
|
||||
assert file_contents =~
|
||||
~S{create index(:posts, ["id"], name: "test_unique_index", unique: true, prefix: "example")}
|
||||
|
||||
assert file_contents =~ ~S{create index(:posts, ["id"]}
|
||||
|
||||
# the migration adds the id, with its default
|
||||
assert file_contents =~
|
||||
~S[add :id, :uuid, null: false, default: fragment("uuid_generate_v4()"), primary_key: true]
|
||||
|
||||
# the migration adds other attributes
|
||||
assert file_contents =~ ~S[add :title, :text]
|
||||
|
||||
# the migration adds custom attributes
|
||||
assert file_contents =~ ~S[add :second_title, :varchar, size: 16]
|
||||
|
||||
# the migration creates unique_indexes based on the identities of the resource
|
||||
assert file_contents =~
|
||||
~S{create unique_index(:posts, [:title], name: "posts_title_index", prefix: "example")}
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating follow up migrations" do
|
||||
setup do
|
||||
on_exit(fn ->
|
||||
|
@ -527,7 +607,7 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
||||
|
||||
assert File.read!(file) =~
|
||||
~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :uuid)]
|
||||
~S[references(:posts, column: :id, name: "posts_post_id_fkey", type: :uuid, prefix: "public")]
|
||||
end
|
||||
|
||||
test "when modified, the foreign key is dropped before modification" do
|
||||
|
@ -590,7 +670,7 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
|> Enum.at(1)
|
||||
|
||||
assert File.read!(file) =~
|
||||
~S[references(:posts, column: :id, name: "special_post_fkey", type: :uuid, on_delete: :delete_all, on_update: :update_all)]
|
||||
~S[references(:posts, column: :id, prefix: "public", name: "special_post_fkey", type: :uuid, on_delete: :delete_all, on_update: :update_all)]
|
||||
|
||||
assert File.read!(file) =~ ~S[drop constraint(:posts, "posts_post_id_fkey")]
|
||||
end
|
||||
|
@ -757,7 +837,7 @@ defmodule AshPostgres.MigrationGeneratorTest do
|
|||
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
|
||||
|
||||
assert File.read!(file) =~
|
||||
~S[references(:post_comments, column: :id, name: "posts_best_comment_id_fkey", type: :uuid)]
|
||||
~S[references(:post_comments, column: :id, name: "posts_best_comment_id_fkey", type: :uuid, prefix: "public")]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue