mirror of
https://github.com/ash-project/ash_sqlite.git
synced 2024-09-19 12:52:50 +12:00
improvement: get at least one test passing
This commit is contained in:
parent
c8c811c7eb
commit
6176f80e9b
41 changed files with 1464 additions and 1080 deletions
|
@ -1,8 +1,6 @@
|
||||||
spark_locals_without_parens = [
|
spark_locals_without_parens = [
|
||||||
base_filter_sql: 1,
|
base_filter_sql: 1,
|
||||||
check: 1,
|
check: 1,
|
||||||
check_constraint: 2,
|
|
||||||
check_constraint: 3,
|
|
||||||
code?: 1,
|
code?: 1,
|
||||||
concurrently: 1,
|
concurrently: 1,
|
||||||
create?: 1,
|
create?: 1,
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -25,3 +25,6 @@ ash_sqlite-*.tar
|
||||||
test_migration_path
|
test_migration_path
|
||||||
test_snapshots_path
|
test_snapshots_path
|
||||||
|
|
||||||
|
test/test.db
|
||||||
|
test/test.db-shm
|
||||||
|
test/test.db-wal
|
||||||
|
|
|
@ -21,29 +21,14 @@ if Mix.env() == :test do
|
||||||
config :ash, :validate_api_config_inclusion?, false
|
config :ash, :validate_api_config_inclusion?, false
|
||||||
|
|
||||||
config :ash_sqlite, AshSqlite.TestRepo,
|
config :ash_sqlite, AshSqlite.TestRepo,
|
||||||
username: "sqlite",
|
database: Path.join(__DIR__, "../test/test.db"),
|
||||||
database: "ash_sqlite",
|
pool_size: 1,
|
||||||
hostname: "localhost",
|
migration_lock: false,
|
||||||
pool: Ecto.Adapters.SQL.Sandbox
|
pool: Ecto.Adapters.SQL.Sandbox,
|
||||||
|
|
||||||
# sobelow_skip ["Config.Secrets"]
|
|
||||||
config :ash_sqlite, AshSqlite.TestRepo, password: "sqlite"
|
|
||||||
|
|
||||||
config :ash_sqlite, AshSqlite.TestRepo, migration_primary_key: [name: :id, type: :binary_id]
|
|
||||||
|
|
||||||
config :ash_sqlite, AshSqlite.TestNoSandboxRepo,
|
|
||||||
username: "sqlite",
|
|
||||||
database: "ash_sqlite_test",
|
|
||||||
hostname: "localhost"
|
|
||||||
|
|
||||||
# sobelow_skip ["Config.Secrets"]
|
|
||||||
config :ash_sqlite, AshSqlite.TestNoSandboxRepo, password: "sqlite"
|
|
||||||
|
|
||||||
config :ash_sqlite, AshSqlite.TestNoSandboxRepo,
|
|
||||||
migration_primary_key: [name: :id, type: :binary_id]
|
migration_primary_key: [name: :id, type: :binary_id]
|
||||||
|
|
||||||
config :ash_sqlite,
|
config :ash_sqlite,
|
||||||
ecto_repos: [AshSqlite.TestRepo, AshSqlite.TestNoSandboxRepo],
|
ecto_repos: [AshSqlite.TestRepo],
|
||||||
ash_apis: [
|
ash_apis: [
|
||||||
AshSqlite.Test.Api
|
AshSqlite.Test.Api
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
defmodule AshSqlite.CheckConstraint do
|
|
||||||
@moduledoc "Represents a configured check constraint on the table backing a resource"
|
|
||||||
|
|
||||||
defstruct [:attribute, :name, :message, :check]
|
|
||||||
|
|
||||||
def schema do
|
|
||||||
[
|
|
||||||
attribute: [
|
|
||||||
type: :any,
|
|
||||||
doc:
|
|
||||||
"The attribute or list of attributes to which an error will be added if the check constraint fails",
|
|
||||||
required: true
|
|
||||||
],
|
|
||||||
name: [
|
|
||||||
type: :string,
|
|
||||||
required: true,
|
|
||||||
doc: "The name of the constraint"
|
|
||||||
],
|
|
||||||
message: [
|
|
||||||
type: :string,
|
|
||||||
doc: "The message to be added if the check constraint fails"
|
|
||||||
],
|
|
||||||
check: [
|
|
||||||
type: :string,
|
|
||||||
doc:
|
|
||||||
"The contents of the check. If this is set, the migration generator will include it when generating migrations"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -5,7 +5,6 @@ defmodule AshSqlite.CustomIndex do
|
||||||
:fields,
|
:fields,
|
||||||
:name,
|
:name,
|
||||||
:unique,
|
:unique,
|
||||||
:concurrently,
|
|
||||||
:using,
|
:using,
|
||||||
:where,
|
:where,
|
||||||
:include,
|
:include,
|
||||||
|
@ -30,11 +29,6 @@ defmodule AshSqlite.CustomIndex do
|
||||||
doc: "indicates whether the index should be unique.",
|
doc: "indicates whether the index should be unique.",
|
||||||
default: false
|
default: false
|
||||||
],
|
],
|
||||||
concurrently: [
|
|
||||||
type: :boolean,
|
|
||||||
doc: "indicates whether the index should be created/dropped concurrently.",
|
|
||||||
default: false
|
|
||||||
],
|
|
||||||
using: [
|
using: [
|
||||||
type: :string,
|
type: :string,
|
||||||
doc: "configures the index type."
|
doc: "configures the index type."
|
||||||
|
|
|
@ -136,44 +136,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@check_constraint %Spark.Dsl.Entity{
|
|
||||||
name: :check_constraint,
|
|
||||||
describe: """
|
|
||||||
Add a check constraint to be validated.
|
|
||||||
|
|
||||||
If a check constraint exists on the table but not in this section, and it produces an error, a runtime error will be raised.
|
|
||||||
|
|
||||||
Provide a list of attributes instead of a single attribute to add the message to multiple attributes.
|
|
||||||
|
|
||||||
By adding the `check` option, the migration generator will include it when generating migrations.
|
|
||||||
""",
|
|
||||||
examples: [
|
|
||||||
"""
|
|
||||||
check_constraint :price, "price_must_be_positive", check: "price > 0", message: "price must be positive"
|
|
||||||
"""
|
|
||||||
],
|
|
||||||
args: [:attribute, :name],
|
|
||||||
target: AshSqlite.CheckConstraint,
|
|
||||||
schema: AshSqlite.CheckConstraint.schema()
|
|
||||||
}
|
|
||||||
|
|
||||||
@check_constraints %Spark.Dsl.Section{
|
|
||||||
name: :check_constraints,
|
|
||||||
describe: """
|
|
||||||
A section for configuring the check constraints for a given table.
|
|
||||||
|
|
||||||
This can be used to automatically create those check constraints, or just to provide message when they are raised
|
|
||||||
""",
|
|
||||||
examples: [
|
|
||||||
"""
|
|
||||||
check_constraints do
|
|
||||||
check_constraint :price, "price_must_be_positive", check: "price > 0", message: "price must be positive"
|
|
||||||
end
|
|
||||||
"""
|
|
||||||
],
|
|
||||||
entities: [@check_constraint]
|
|
||||||
}
|
|
||||||
|
|
||||||
@references %Spark.Dsl.Section{
|
@references %Spark.Dsl.Section{
|
||||||
name: :references,
|
name: :references,
|
||||||
describe: """
|
describe: """
|
||||||
|
@ -217,8 +179,7 @@ defmodule AshSqlite.DataLayer do
|
||||||
sections: [
|
sections: [
|
||||||
@custom_indexes,
|
@custom_indexes,
|
||||||
@custom_statements,
|
@custom_statements,
|
||||||
@references,
|
@references
|
||||||
@check_constraints
|
|
||||||
],
|
],
|
||||||
modules: [
|
modules: [
|
||||||
:repo
|
:repo
|
||||||
|
@ -364,20 +325,9 @@ defmodule AshSqlite.DataLayer do
|
||||||
import Ecto.Query, only: [from: 2, subquery: 1]
|
import Ecto.Query, only: [from: 2, subquery: 1]
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def can?(_, :async_engine), do: true
|
def can?(_, :async_engine), do: false
|
||||||
def can?(_, :bulk_create), do: true
|
def can?(_, :bulk_create), do: true
|
||||||
def can?(_, {:lock, :for_update}), do: true
|
def can?(_, {:lock, _}), do: false
|
||||||
|
|
||||||
def can?(_, {:lock, string}) do
|
|
||||||
string = String.trim_trailing(string, " NOWAIT")
|
|
||||||
|
|
||||||
String.upcase(string) in [
|
|
||||||
"FOR UPDATE",
|
|
||||||
"FOR NO KEY UPDATE",
|
|
||||||
"FOR SHARE",
|
|
||||||
"FOR KEY SHARE"
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
def can?(_, :transact), do: true
|
def can?(_, :transact), do: true
|
||||||
def can?(_, :composite_primary_key), do: true
|
def can?(_, :composite_primary_key), do: true
|
||||||
|
@ -470,7 +420,7 @@ defmodule AshSqlite.DataLayer do
|
||||||
data_layer_query
|
data_layer_query
|
||||||
end
|
end
|
||||||
|
|
||||||
default_bindings(data_layer_query, resource, context)
|
{:ok, default_bindings(data_layer_query, resource, context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
|
@ -563,7 +513,7 @@ defmodule AshSqlite.DataLayer do
|
||||||
def functions(_resource) do
|
def functions(_resource) do
|
||||||
[
|
[
|
||||||
AshSqlite.Functions.Fragment,
|
AshSqlite.Functions.Fragment,
|
||||||
AshSqlite.Functions.Like,
|
AshSqlite.Functions.Like
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -623,7 +573,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
else
|
else
|
||||||
{:ok,
|
{:ok,
|
||||||
Stream.zip_with(results, changesets, fn result, changeset ->
|
Stream.zip_with(results, changesets, fn result, changeset ->
|
||||||
|
|
||||||
Ash.Resource.put_metadata(
|
Ash.Resource.put_metadata(
|
||||||
result,
|
result,
|
||||||
:bulk_create_index,
|
:bulk_create_index,
|
||||||
|
@ -717,7 +666,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
|> Map.update!(:filters, &Map.merge(&1, filters))
|
|> Map.update!(:filters, &Map.merge(&1, filters))
|
||||||
|> add_configured_foreign_key_constraints(record.__struct__)
|
|> add_configured_foreign_key_constraints(record.__struct__)
|
||||||
|> add_unique_indexes(record.__struct__, changeset)
|
|> add_unique_indexes(record.__struct__, changeset)
|
||||||
|> add_check_constraints(record.__struct__)
|
|
||||||
|> add_exclusion_constraints(record.__struct__)
|
|> add_exclusion_constraints(record.__struct__)
|
||||||
|
|
||||||
case type do
|
case type do
|
||||||
|
@ -778,7 +726,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
record
|
record
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
record
|
record
|
||||||
end
|
end
|
||||||
|
@ -847,21 +794,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
|
|
||||||
def to_ecto(other), do: other
|
def to_ecto(other), do: other
|
||||||
|
|
||||||
defp add_check_constraints(changeset, resource) do
|
|
||||||
resource
|
|
||||||
|> AshSqlite.DataLayer.Info.check_constraints()
|
|
||||||
|> Enum.reduce(changeset, fn constraint, changeset ->
|
|
||||||
constraint.attribute
|
|
||||||
|> List.wrap()
|
|
||||||
|> Enum.reduce(changeset, fn attribute, changeset ->
|
|
||||||
Ecto.Changeset.check_constraint(changeset, attribute,
|
|
||||||
name: constraint.name,
|
|
||||||
message: constraint.message || "is invalid"
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp add_exclusion_constraints(changeset, resource) do
|
defp add_exclusion_constraints(changeset, resource) do
|
||||||
resource
|
resource
|
||||||
|> AshSqlite.DataLayer.Info.exclusion_constraint_names()
|
|> AshSqlite.DataLayer.Info.exclusion_constraint_names()
|
||||||
|
@ -1264,41 +1196,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
|
||||||
def lock(query, :for_update, _) do
|
|
||||||
if query.distinct do
|
|
||||||
new_query =
|
|
||||||
Ecto.Query.lock(%{query | distinct: nil}, [{^0, a}], fragment("FOR UPDATE OF ?", a))
|
|
||||||
|
|
||||||
q = from(row in subquery(new_query), [])
|
|
||||||
{:ok, %{q | distinct: query.distinct}}
|
|
||||||
else
|
|
||||||
{:ok, Ecto.Query.lock(query, [{^0, a}], fragment("FOR UPDATE OF ?", a))}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@locks [
|
|
||||||
"FOR UPDATE",
|
|
||||||
"FOR NO KEY UPDATE",
|
|
||||||
"FOR SHARE",
|
|
||||||
"FOR KEY SHARE"
|
|
||||||
]
|
|
||||||
|
|
||||||
for lock <- @locks do
|
|
||||||
frag = "#{lock} OF ?"
|
|
||||||
|
|
||||||
def lock(query, unquote(lock), _) do
|
|
||||||
{:ok, Ecto.Query.lock(query, [{^0, a}], fragment(unquote(frag), a))}
|
|
||||||
end
|
|
||||||
|
|
||||||
frag = "#{lock} OF ? NOWAIT"
|
|
||||||
lock = "#{lock} NOWAIT"
|
|
||||||
|
|
||||||
def lock(query, unquote(lock), _) do
|
|
||||||
{:ok, Ecto.Query.lock(query, [{^0, a}], fragment(unquote(frag), a))}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def sort(query, sort, _resource) do
|
def sort(query, sort, _resource) do
|
||||||
{:ok, Map.update!(query, :__ash_bindings__, &Map.put(&1, :sort, sort))}
|
{:ok, Map.update!(query, :__ash_bindings__, &Map.put(&1, :sort, sort))}
|
||||||
|
@ -1374,7 +1271,6 @@ defmodule AshSqlite.DataLayer do
|
||||||
:with_ctes,
|
:with_ctes,
|
||||||
:limit,
|
:limit,
|
||||||
:offset,
|
:offset,
|
||||||
:lock,
|
|
||||||
:preload,
|
:preload,
|
||||||
:update,
|
:update,
|
||||||
:where
|
:where
|
||||||
|
|
|
@ -13,7 +13,6 @@ defmodule AshSqlite.DataLayer.Info do
|
||||||
Extension.get_opt(resource, [:sqlite], :table, nil, true)
|
Extension.get_opt(resource, [:sqlite], :table, nil, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@doc "The configured references for a resource"
|
@doc "The configured references for a resource"
|
||||||
def references(resource) do
|
def references(resource) do
|
||||||
Extension.get_entities(resource, [:sqlite, :references])
|
Extension.get_entities(resource, [:sqlite, :references])
|
||||||
|
@ -41,10 +40,6 @@ defmodule AshSqlite.DataLayer.Info do
|
||||||
Extension.get_opt(resource, [:sqlite], :migration_ignore_attributes, [])
|
Extension.get_opt(resource, [:sqlite], :migration_ignore_attributes, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "The configured check_constraints for a resource"
|
|
||||||
def check_constraints(resource) do
|
|
||||||
Extension.get_entities(resource, [:sqlite, :check_constraints])
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc "The configured custom_indexes for a resource"
|
@doc "The configured custom_indexes for a resource"
|
||||||
def custom_indexes(resource) do
|
def custom_indexes(resource) do
|
||||||
|
@ -120,5 +115,4 @@ defmodule AshSqlite.DataLayer.Info do
|
||||||
def skip_unique_indexes(resource) do
|
def skip_unique_indexes(resource) do
|
||||||
Extension.get_opt(resource, [:sqlite], :skip_unique_indexes, [])
|
Extension.get_opt(resource, [:sqlite], :skip_unique_indexes, [])
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
70
lib/expr.ex
70
lib/expr.ex
|
@ -385,24 +385,7 @@ defmodule AshSqlite.Expr do
|
||||||
type
|
type
|
||||||
) do
|
) do
|
||||||
if options[:trim?] do
|
if options[:trim?] do
|
||||||
require_ash_functions!(query, "string_split(..., trim?: true)")
|
raise "trim?: true not supported by AshSqlite"
|
||||||
|
|
||||||
do_dynamic_expr(
|
|
||||||
query,
|
|
||||||
%Fragment{
|
|
||||||
embedded?: pred_embedded?,
|
|
||||||
arguments: [
|
|
||||||
raw: "ash_trim_whitespace(string_to_array(",
|
|
||||||
expr: string,
|
|
||||||
raw: ", NULLIF(",
|
|
||||||
expr: delimiter,
|
|
||||||
raw: ", '')))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
bindings,
|
|
||||||
embedded?,
|
|
||||||
type
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
do_dynamic_expr(
|
do_dynamic_expr(
|
||||||
query,
|
query,
|
||||||
|
@ -641,44 +624,10 @@ defmodule AshSqlite.Expr do
|
||||||
)
|
)
|
||||||
|
|
||||||
:|| ->
|
:|| ->
|
||||||
require_ash_functions!(query, "||")
|
raise "|| operator not supported by AshSqlite"
|
||||||
|
|
||||||
do_dynamic_expr(
|
|
||||||
query,
|
|
||||||
%Fragment{
|
|
||||||
embedded?: pred_embedded?,
|
|
||||||
arguments: [
|
|
||||||
raw: "ash_elixir_or(",
|
|
||||||
casted_expr: left_expr,
|
|
||||||
raw: ", ",
|
|
||||||
casted_expr: right_expr,
|
|
||||||
raw: ")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
bindings,
|
|
||||||
embedded?,
|
|
||||||
type
|
|
||||||
)
|
|
||||||
|
|
||||||
:&& ->
|
:&& ->
|
||||||
require_ash_functions!(query, "&&")
|
raise "&& operator not supported by AshSqlite"
|
||||||
|
|
||||||
do_dynamic_expr(
|
|
||||||
query,
|
|
||||||
%Fragment{
|
|
||||||
embedded?: pred_embedded?,
|
|
||||||
arguments: [
|
|
||||||
raw: "ash_elixir_and(",
|
|
||||||
casted_expr: left_expr,
|
|
||||||
raw: ", ",
|
|
||||||
casted_expr: right_expr,
|
|
||||||
raw: ")"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
bindings,
|
|
||||||
embedded?,
|
|
||||||
type
|
|
||||||
)
|
|
||||||
|
|
||||||
other ->
|
other ->
|
||||||
raise "Operator not implemented #{other}"
|
raise "Operator not implemented #{other}"
|
||||||
|
@ -1289,19 +1238,6 @@ defmodule AshSqlite.Expr do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp require_ash_functions!(query, operator) do
|
|
||||||
installed_extensions =
|
|
||||||
AshSqlite.DataLayer.Info.repo(query.__ash_bindings__.resource).installed_extensions()
|
|
||||||
|
|
||||||
unless "ash-functions" in installed_extensions do
|
|
||||||
raise """
|
|
||||||
Cannot use `#{operator}` without adding the extension `ash-functions` to your repo.
|
|
||||||
|
|
||||||
Add it to the list in `installed_extensions/0` and generate migrations.
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp require_extension!(query, extension, context) do
|
defp require_extension!(query, extension, context) do
|
||||||
repo = AshSqlite.DataLayer.Info.repo(query.__ash_bindings__.resource)
|
repo = AshSqlite.DataLayer.Info.repo(query.__ash_bindings__.resource)
|
||||||
|
|
||||||
|
|
|
@ -579,6 +579,7 @@ defmodule AshSqlite.Join do
|
||||||
relationship_destination =
|
relationship_destination =
|
||||||
relationship_destination
|
relationship_destination
|
||||||
|> Ecto.Queryable.to_query()
|
|> Ecto.Queryable.to_query()
|
||||||
|
|
||||||
binding_kinds =
|
binding_kinds =
|
||||||
case kind do
|
case kind do
|
||||||
:left ->
|
:left ->
|
||||||
|
|
|
@ -142,8 +142,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv", "resource_snapshots"])
|
Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv", "resource_snapshots"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@latest_ash_functions_version 1
|
|
||||||
|
|
||||||
defp create_extension_migrations(repos, opts) do
|
defp create_extension_migrations(repos, opts) do
|
||||||
for repo <- repos do
|
for repo <- repos do
|
||||||
snapshot_path = snapshot_path(opts, repo)
|
snapshot_path = snapshot_path(opts, repo)
|
||||||
|
@ -158,7 +156,7 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
{extensions_snapshot, installed_extensions} =
|
{_extensions_snapshot, installed_extensions} =
|
||||||
case installed_extensions do
|
case installed_extensions do
|
||||||
installed when is_list(installed) ->
|
installed when is_list(installed) ->
|
||||||
{%{
|
{%{
|
||||||
|
@ -186,15 +184,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Enum.filter(fn {name, _extension} -> !Enum.member?(installed_extensions, name) end)
|
|> Enum.filter(fn {name, _extension} -> !Enum.member?(installed_extensions, name) end)
|
||||||
|> Enum.map(fn {_name, extension} -> extension end)
|
|> Enum.map(fn {_name, extension} -> extension end)
|
||||||
|
|
||||||
to_install =
|
|
||||||
if "ash-functions" in requesteds &&
|
|
||||||
extensions_snapshot[:ash_functions_version] !=
|
|
||||||
@latest_ash_functions_version do
|
|
||||||
Enum.uniq(["ash-functions" | to_install])
|
|
||||||
else
|
|
||||||
to_install
|
|
||||||
end
|
|
||||||
|
|
||||||
if Enum.empty?(to_install) do
|
if Enum.empty?(to_install) do
|
||||||
Mix.shell().info("No extensions to install")
|
Mix.shell().info("No extensions to install")
|
||||||
:ok
|
:ok
|
||||||
|
@ -227,26 +216,20 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|
|
||||||
install =
|
install =
|
||||||
Enum.map_join(to_install, "\n", fn
|
Enum.map_join(to_install, "\n", fn
|
||||||
"ash-functions" ->
|
|
||||||
install_ash_functions(extensions_snapshot[:ash_functions_version])
|
|
||||||
|
|
||||||
{_ext_name, version, up_fn, _down_fn} when is_function(up_fn, 1) ->
|
{_ext_name, version, up_fn, _down_fn} when is_function(up_fn, 1) ->
|
||||||
up_fn.(version)
|
up_fn.(version)
|
||||||
|
|
||||||
extension ->
|
extension ->
|
||||||
"execute(\"CREATE EXTENSION IF NOT EXISTS \\\"#{extension}\\\"\")"
|
raise "only custom extensions supported currently. Got #{inspect(extension)}"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
uninstall =
|
uninstall =
|
||||||
Enum.map_join(to_install, "\n", fn
|
Enum.map_join(to_install, "\n", fn
|
||||||
"ash-functions" ->
|
|
||||||
"execute(\"DROP FUNCTION IF EXISTS ash_elixir_and(BOOLEAN, ANYCOMPATIBLE), ash_elixir_and(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(ANYCOMPATIBLE, ANYCOMPATIBLE), ash_elixir_or(BOOLEAN, ANYCOMPATIBLE)\")"
|
|
||||||
|
|
||||||
{_ext_name, version, _up_fn, down_fn} when is_function(down_fn, 1) ->
|
{_ext_name, version, _up_fn, down_fn} when is_function(down_fn, 1) ->
|
||||||
down_fn.(version)
|
down_fn.(version)
|
||||||
|
|
||||||
extension ->
|
extension ->
|
||||||
"# execute(\"DROP EXTENSION IF EXISTS \\\"#{extension}\\\"\")"
|
raise "only custom extensions supported currently. Got #{inspect(extension)}"
|
||||||
end)
|
end)
|
||||||
|
|
||||||
contents = """
|
contents = """
|
||||||
|
@ -277,8 +260,7 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
Jason.encode!(
|
Jason.encode!(
|
||||||
%{
|
%{
|
||||||
installed: installed
|
installed: installed
|
||||||
}
|
},
|
||||||
|> set_ash_functions(installed),
|
|
||||||
pretty: true
|
pretty: true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -289,122 +271,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp install_ash_functions(nil) do
|
|
||||||
"""
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE)
|
|
||||||
AS $$ SELECT COALESCE(NULLIF($1, FALSE), $2) $$
|
|
||||||
LANGUAGE SQL
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE)
|
|
||||||
AS $$ SELECT COALESCE($1, $2) $$
|
|
||||||
LANGUAGE SQL
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_elixir_and(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$
|
|
||||||
SELECT CASE
|
|
||||||
WHEN $1 IS TRUE THEN $2
|
|
||||||
ELSE $1
|
|
||||||
END $$
|
|
||||||
LANGUAGE SQL
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_elixir_and(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) AS $$
|
|
||||||
SELECT CASE
|
|
||||||
WHEN $1 IS NOT NULL THEN $2
|
|
||||||
ELSE $1
|
|
||||||
END $$
|
|
||||||
LANGUAGE SQL
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[])
|
|
||||||
RETURNS text[] AS $$
|
|
||||||
DECLARE
|
|
||||||
start_index INT = 1;
|
|
||||||
end_index INT = array_length(arr, 1);
|
|
||||||
BEGIN
|
|
||||||
WHILE start_index <= end_index AND arr[start_index] = '' LOOP
|
|
||||||
start_index := start_index + 1;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
WHILE end_index >= start_index AND arr[end_index] = '' LOOP
|
|
||||||
end_index := end_index - 1;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
IF start_index > end_index THEN
|
|
||||||
RETURN ARRAY[]::text[];
|
|
||||||
ELSE
|
|
||||||
RETURN arr[start_index : end_index];
|
|
||||||
END IF;
|
|
||||||
END; $$
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp install_ash_functions(0) do
|
|
||||||
"""
|
|
||||||
execute(\"\"\"
|
|
||||||
ALTER FUNCTION ash_elixir_or(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) IMMUTABLE
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
ALTER FUNCTION ash_elixir_or(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) IMMUTABLE
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
ALTER FUNCTION ash_elixir_and(left BOOLEAN, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) IMMUTABLE
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
ALTER FUNCTION ash_elixir_and(left ANYCOMPATIBLE, in right ANYCOMPATIBLE, out f1 ANYCOMPATIBLE) IMMUTABLE
|
|
||||||
\"\"\")
|
|
||||||
|
|
||||||
execute(\"\"\"
|
|
||||||
CREATE OR REPLACE FUNCTION ash_trim_whitespace(arr text[])
|
|
||||||
RETURNS text[] AS $$
|
|
||||||
DECLARE
|
|
||||||
start_index INT = 1;
|
|
||||||
end_index INT = array_length(arr, 1);
|
|
||||||
BEGIN
|
|
||||||
WHILE start_index <= end_index AND arr[start_index] = '' LOOP
|
|
||||||
start_index := start_index + 1;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
WHILE end_index >= start_index AND arr[end_index] = '' LOOP
|
|
||||||
end_index := end_index - 1;
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
IF start_index > end_index THEN
|
|
||||||
RETURN ARRAY[]::text[];
|
|
||||||
ELSE
|
|
||||||
RETURN arr[start_index : end_index];
|
|
||||||
END IF;
|
|
||||||
END; $$
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
IMMUTABLE;
|
|
||||||
\"\"\")
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp set_ash_functions(snapshot, installed_extensions) do
|
|
||||||
if "ash-functions" in installed_extensions do
|
|
||||||
Map.put(snapshot, :ash_functions_version, @latest_ash_functions_version)
|
|
||||||
else
|
|
||||||
snapshot
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp create_migrations(snapshots, opts) do
|
defp create_migrations(snapshots, opts) do
|
||||||
snapshots
|
snapshots
|
||||||
|> Enum.group_by(& &1.repo)
|
|> Enum.group_by(& &1.repo)
|
||||||
|
@ -441,47 +307,16 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
exit({:shutdown, 1})
|
exit({:shutdown, 1})
|
||||||
end
|
end
|
||||||
|
|
||||||
operations
|
|
||||||
|> split_into_migrations()
|
|
||||||
|> Enum.each(fn operations ->
|
|
||||||
run_without_transaction? =
|
|
||||||
Enum.any?(operations, fn
|
|
||||||
%Operation.AddCustomIndex{index: %{concurrently: true}} ->
|
|
||||||
true
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
false
|
|
||||||
end)
|
|
||||||
|
|
||||||
operations
|
operations
|
||||||
|> organize_operations
|
|> organize_operations
|
||||||
|> build_up_and_down()
|
|> build_up_and_down()
|
||||||
|> write_migration!(repo, opts, run_without_transaction?)
|
|> write_migration!(repo, opts, false)
|
||||||
end)
|
|
||||||
|
|
||||||
create_new_snapshot(snapshots, repo_name(repo), opts)
|
create_new_snapshot(snapshots, repo_name(repo), opts)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp split_into_migrations(operations) do
|
|
||||||
operations
|
|
||||||
|> Enum.split_with(fn
|
|
||||||
%Operation.AddCustomIndex{index: %{concurrently: true}} ->
|
|
||||||
true
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
false
|
|
||||||
end)
|
|
||||||
|> case do
|
|
||||||
{[], ops} ->
|
|
||||||
[ops]
|
|
||||||
|
|
||||||
{concurrent_indexes, ops} ->
|
|
||||||
[ops, concurrent_indexes]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp add_order_to_operations({snapshot, operations}) do
|
defp add_order_to_operations({snapshot, operations}) do
|
||||||
operations_with_order = Enum.map(operations, &add_order_to_operation(&1, snapshot.attributes))
|
operations_with_order = Enum.map(operations, &add_order_to_operation(&1, snapshot.attributes))
|
||||||
|
|
||||||
|
@ -1104,9 +939,20 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
nil,
|
nil,
|
||||||
acc
|
acc
|
||||||
) do
|
) do
|
||||||
|
# this is kind of a hack
|
||||||
|
{has_to_be_in_this_phase, rest} =
|
||||||
|
Enum.split_with(rest, fn
|
||||||
|
%Operation.AddAttribute{table: ^table} -> true
|
||||||
|
_ -> false
|
||||||
|
end)
|
||||||
|
|
||||||
group_into_phases(
|
group_into_phases(
|
||||||
rest,
|
rest,
|
||||||
%Phase.Create{table: table, multitenancy: multitenancy},
|
%Phase.Create{
|
||||||
|
table: table,
|
||||||
|
multitenancy: multitenancy,
|
||||||
|
operations: has_to_be_in_this_phase
|
||||||
|
},
|
||||||
acc
|
acc
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -1240,18 +1086,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.AddCheckConstraint{
|
|
||||||
constraint: %{attribute: attribute_or_attributes},
|
|
||||||
table: table,
|
|
||||||
multitenancy: multitenancy
|
|
||||||
},
|
|
||||||
%Operation.AddAttribute{table: table, attribute: %{source: source}}
|
|
||||||
) do
|
|
||||||
source in List.wrap(attribute_or_attributes) ||
|
|
||||||
(multitenancy.attribute && multitenancy.attribute in List.wrap(attribute_or_attributes))
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
defp after?(
|
||||||
%Operation.AddCustomIndex{
|
%Operation.AddCustomIndex{
|
||||||
table: table
|
table: table
|
||||||
|
@ -1261,68 +1095,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.AddCustomIndex{
|
|
||||||
table: table,
|
|
||||||
index: %{
|
|
||||||
concurrently: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
%Operation.AddCustomIndex{
|
|
||||||
table: table,
|
|
||||||
index: %{
|
|
||||||
concurrently: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) do
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.AddCheckConstraint{table: table, constraint: %{name: name}},
|
|
||||||
%Operation.RemoveCheckConstraint{
|
|
||||||
table: table,
|
|
||||||
constraint: %{
|
|
||||||
name: name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
do: true
|
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.RemoveCheckConstraint{
|
|
||||||
table: table,
|
|
||||||
constraint: %{
|
|
||||||
name: name
|
|
||||||
}
|
|
||||||
},
|
|
||||||
%Operation.AddCheckConstraint{table: table, constraint: %{name: name}}
|
|
||||||
),
|
|
||||||
do: false
|
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.AddCheckConstraint{
|
|
||||||
constraint: %{attribute: attribute_or_attributes},
|
|
||||||
table: table
|
|
||||||
},
|
|
||||||
%Operation.AlterAttribute{table: table, new_attribute: %{source: source}}
|
|
||||||
) do
|
|
||||||
source in List.wrap(attribute_or_attributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.AddCheckConstraint{
|
|
||||||
constraint: %{attribute: attribute_or_attributes},
|
|
||||||
table: table
|
|
||||||
},
|
|
||||||
%Operation.RenameAttribute{
|
|
||||||
table: table,
|
|
||||||
new_attribute: %{source: source}
|
|
||||||
}
|
|
||||||
) do
|
|
||||||
source in List.wrap(attribute_or_attributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
defp after?(
|
||||||
%Operation.RemoveUniqueIndex{table: table},
|
%Operation.RemoveUniqueIndex{table: table},
|
||||||
%Operation.AddUniqueIndex{table: table}
|
%Operation.AddUniqueIndex{table: table}
|
||||||
|
@ -1337,29 +1109,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.RemoveCheckConstraint{
|
|
||||||
constraint: %{attribute: attributes},
|
|
||||||
table: table
|
|
||||||
},
|
|
||||||
%Operation.RemoveAttribute{table: table, attribute: %{source: source}}
|
|
||||||
) do
|
|
||||||
source in List.wrap(attributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
|
||||||
%Operation.RemoveCheckConstraint{
|
|
||||||
constraint: %{attribute: attributes},
|
|
||||||
table: table
|
|
||||||
},
|
|
||||||
%Operation.RenameAttribute{
|
|
||||||
table: table,
|
|
||||||
old_attribute: %{source: source}
|
|
||||||
}
|
|
||||||
) do
|
|
||||||
source in List.wrap(attributes)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(%Operation.AlterAttribute{table: table}, %Operation.DropForeignKey{
|
defp after?(%Operation.AlterAttribute{table: table}, %Operation.DropForeignKey{
|
||||||
table: table,
|
table: table,
|
||||||
direction: :up
|
direction: :up
|
||||||
|
@ -1583,12 +1332,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
),
|
),
|
||||||
do: true
|
do: true
|
||||||
|
|
||||||
defp after?(%Operation.AddCheckConstraint{table: table}, %Operation.CreateTable{
|
|
||||||
table: table
|
|
||||||
}) do
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
defp after?(
|
defp after?(
|
||||||
%Operation.AlterAttribute{new_attribute: %{references: references}, table: table},
|
%Operation.AlterAttribute{new_attribute: %{references: references}, table: table},
|
||||||
%{table: table}
|
%{table: table}
|
||||||
|
@ -1596,9 +1339,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
when not is_nil(references),
|
when not is_nil(references),
|
||||||
do: true
|
do: true
|
||||||
|
|
||||||
defp after?(%Operation.AddCheckConstraint{}, _), do: true
|
|
||||||
defp after?(%Operation.RemoveCheckConstraint{}, _), do: true
|
|
||||||
|
|
||||||
defp after?(_, _), do: false
|
defp after?(_, _), do: false
|
||||||
|
|
||||||
defp fetch_operations(snapshots, opts) do
|
defp fetch_operations(snapshots, opts) do
|
||||||
|
@ -1619,7 +1359,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
identities: [],
|
identities: [],
|
||||||
custom_indexes: [],
|
custom_indexes: [],
|
||||||
custom_statements: [],
|
custom_statements: [],
|
||||||
check_constraints: [],
|
|
||||||
table: snapshot.table,
|
table: snapshot.table,
|
||||||
repo: snapshot.repo,
|
repo: snapshot.repo,
|
||||||
base_filter: nil,
|
base_filter: nil,
|
||||||
|
@ -1770,33 +1509,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
}
|
}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
constraints_to_add =
|
|
||||||
snapshot.check_constraints
|
|
||||||
|> Enum.reject(fn constraint ->
|
|
||||||
Enum.find(old_snapshot.check_constraints, fn old_constraint ->
|
|
||||||
old_constraint.check == constraint.check && old_constraint.name == constraint.name
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|> Enum.map(fn constraint ->
|
|
||||||
%Operation.AddCheckConstraint{
|
|
||||||
constraint: constraint,
|
|
||||||
table: snapshot.table
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
constraints_to_remove =
|
|
||||||
old_snapshot.check_constraints
|
|
||||||
|> Enum.reject(fn old_constraint ->
|
|
||||||
Enum.find(snapshot.check_constraints, fn constraint ->
|
|
||||||
old_constraint.check == constraint.check && old_constraint.name == constraint.name
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|> Enum.map(fn old_constraint ->
|
|
||||||
%Operation.RemoveCheckConstraint{
|
|
||||||
constraint: old_constraint,
|
|
||||||
table: old_snapshot.table
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
|
|
||||||
[
|
[
|
||||||
pkey_operations,
|
pkey_operations,
|
||||||
|
@ -1804,8 +1516,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
attribute_operations,
|
attribute_operations,
|
||||||
unique_indexes_to_add,
|
unique_indexes_to_add,
|
||||||
unique_indexes_to_rename,
|
unique_indexes_to_rename,
|
||||||
constraints_to_remove,
|
|
||||||
constraints_to_add,
|
|
||||||
custom_indexes_to_add,
|
custom_indexes_to_add,
|
||||||
custom_indexes_to_remove,
|
custom_indexes_to_remove,
|
||||||
custom_statements_to_add,
|
custom_statements_to_add,
|
||||||
|
@ -1921,32 +1631,9 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
add_attribute_events =
|
add_attribute_events =
|
||||||
Enum.flat_map(attributes_to_add, fn attribute ->
|
Enum.flat_map(attributes_to_add, fn attribute ->
|
||||||
if attribute.references do
|
if attribute.references do
|
||||||
reference_ops =
|
|
||||||
if attribute.references.deferrable do
|
|
||||||
[
|
|
||||||
%Operation.AlterDeferrability{
|
|
||||||
table: snapshot.table,
|
|
||||||
references: attribute.references,
|
|
||||||
direction: :up
|
|
||||||
},
|
|
||||||
%Operation.AlterDeferrability{
|
|
||||||
table: snapshot.table,
|
|
||||||
references: Map.get(attribute, :references),
|
|
||||||
direction: :down
|
|
||||||
}
|
|
||||||
]
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
|
|
||||||
[
|
[
|
||||||
%Operation.AddAttribute{
|
%Operation.AddAttribute{
|
||||||
attribute: Map.delete(attribute, :references),
|
attribute: attribute,
|
||||||
table: snapshot.table
|
|
||||||
},
|
|
||||||
%Operation.AlterAttribute{
|
|
||||||
old_attribute: Map.delete(attribute, :references),
|
|
||||||
new_attribute: attribute,
|
|
||||||
table: snapshot.table
|
table: snapshot.table
|
||||||
},
|
},
|
||||||
%Operation.DropForeignKey{
|
%Operation.DropForeignKey{
|
||||||
|
@ -1955,7 +1642,7 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
multitenancy: Map.get(attribute, :multitenancy),
|
multitenancy: Map.get(attribute, :multitenancy),
|
||||||
direction: :down
|
direction: :down
|
||||||
}
|
}
|
||||||
] ++ reference_ops
|
]
|
||||||
else
|
else
|
||||||
[
|
[
|
||||||
%Operation.AddAttribute{
|
%Operation.AddAttribute{
|
||||||
|
@ -2281,9 +1968,7 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Enum.uniq()
|
|> Enum.uniq()
|
||||||
|> Enum.map(fn relationship ->
|
|> Enum.map(fn relationship ->
|
||||||
resource
|
resource
|
||||||
|> do_snapshot(
|
|> do_snapshot(relationship.context[:data_layer][:table])
|
||||||
relationship.context[:data_layer][:table]
|
|
||||||
)
|
|
||||||
|> Map.update!(:identities, fn identities ->
|
|> Map.update!(:identities, fn identities ->
|
||||||
identity_index_names = AshSqlite.DataLayer.Info.identity_index_names(resource)
|
identity_index_names = AshSqlite.DataLayer.Info.identity_index_names(resource)
|
||||||
|
|
||||||
|
@ -2342,7 +2027,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
attributes: attributes(resource, table),
|
attributes: attributes(resource, table),
|
||||||
identities: identities(resource),
|
identities: identities(resource),
|
||||||
table: table || AshSqlite.DataLayer.Info.table(resource),
|
table: table || AshSqlite.DataLayer.Info.table(resource),
|
||||||
check_constraints: check_constraints(resource),
|
|
||||||
custom_indexes: custom_indexes(resource),
|
custom_indexes: custom_indexes(resource),
|
||||||
custom_statements: custom_statements(resource),
|
custom_statements: custom_statements(resource),
|
||||||
repo: AshSqlite.DataLayer.Info.repo(resource),
|
repo: AshSqlite.DataLayer.Info.repo(resource),
|
||||||
|
@ -2365,48 +2049,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Enum.any?(&(&1.type == :create))
|
|> Enum.any?(&(&1.type == :create))
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_constraints(resource) do
|
|
||||||
resource
|
|
||||||
|> AshSqlite.DataLayer.Info.check_constraints()
|
|
||||||
|> Enum.filter(& &1.check)
|
|
||||||
|> case do
|
|
||||||
[] ->
|
|
||||||
[]
|
|
||||||
|
|
||||||
constraints ->
|
|
||||||
base_filter = Ash.Resource.Info.base_filter(resource)
|
|
||||||
|
|
||||||
if base_filter && !AshSqlite.DataLayer.Info.base_filter_sql(resource) do
|
|
||||||
raise """
|
|
||||||
Cannot create a check constraint for a resource with a base filter without also configuring `base_filter_sql`.
|
|
||||||
|
|
||||||
You must provide the `base_filter_sql` option, or manually create add the check constraint to your migrations.
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
constraints
|
|
||||||
end
|
|
||||||
|> Enum.map(fn constraint ->
|
|
||||||
attributes =
|
|
||||||
constraint.attribute
|
|
||||||
|> List.wrap()
|
|
||||||
|> Enum.map(fn attribute ->
|
|
||||||
attr =
|
|
||||||
resource
|
|
||||||
|> Ash.Resource.Info.attribute(attribute)
|
|
||||||
|
|
||||||
attr.source || attr.name
|
|
||||||
end)
|
|
||||||
|
|
||||||
%{
|
|
||||||
name: constraint.name,
|
|
||||||
attribute: attributes,
|
|
||||||
check: constraint.check,
|
|
||||||
base_filter: AshSqlite.DataLayer.Info.base_filter_sql(resource)
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp custom_indexes(resource) do
|
defp custom_indexes(resource) do
|
||||||
resource
|
resource
|
||||||
|> AshSqlite.DataLayer.Info.custom_indexes()
|
|> AshSqlite.DataLayer.Info.custom_indexes()
|
||||||
|
@ -2646,20 +2288,9 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Enum.map(&Map.put(&1, :base_filter, AshSqlite.DataLayer.Info.base_filter_sql(resource)))
|
|> Enum.map(&Map.put(&1, :base_filter, AshSqlite.DataLayer.Info.base_filter_sql(resource)))
|
||||||
end
|
end
|
||||||
|
|
||||||
@uuid_functions [&Ash.UUID.generate/0, &Ecto.UUID.generate/0]
|
|
||||||
|
|
||||||
defp default(%{name: name, default: default}, resource, repo) when is_function(default) do
|
defp default(%{name: name, default: default}, resource, _repo) when is_function(default) do
|
||||||
configured_default(resource, name) ||
|
configured_default(resource, name) || "nil"
|
||||||
cond do
|
|
||||||
default in @uuid_functions && "uuid-ossp" in (repo.config()[:installed_extensions] || []) ->
|
|
||||||
~S[fragment("uuid_generate_v4()")]
|
|
||||||
|
|
||||||
default == (&DateTime.utc_now/0) ->
|
|
||||||
~S[fragment("now()")]
|
|
||||||
|
|
||||||
true ->
|
|
||||||
"nil"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp default(%{name: name, default: {_, _, _}}, resource, _),
|
defp default(%{name: name, default: {_, _, _}}, resource, _),
|
||||||
|
@ -2770,8 +2401,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Map.update!(:custom_indexes, &load_custom_indexes/1)
|
|> Map.update!(:custom_indexes, &load_custom_indexes/1)
|
||||||
|> Map.put_new(:custom_statements, [])
|
|> Map.put_new(:custom_statements, [])
|
||||||
|> Map.update!(:custom_statements, &load_custom_statements/1)
|
|> Map.update!(:custom_statements, &load_custom_statements/1)
|
||||||
|> Map.put_new(:check_constraints, [])
|
|
||||||
|> Map.update!(:check_constraints, &load_check_constraints/1)
|
|
||||||
|> Map.update!(:repo, &String.to_atom/1)
|
|> Map.update!(:repo, &String.to_atom/1)
|
||||||
|> Map.put_new(:multitenancy, %{
|
|> Map.put_new(:multitenancy, %{
|
||||||
attribute: nil,
|
attribute: nil,
|
||||||
|
@ -2782,16 +2411,6 @@ defmodule AshSqlite.MigrationGenerator do
|
||||||
|> Map.put_new(:base_filter, nil)
|
|> Map.put_new(:base_filter, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp load_check_constraints(constraints) do
|
|
||||||
Enum.map(constraints, fn constraint ->
|
|
||||||
Map.update!(constraint, :attribute, fn attribute ->
|
|
||||||
attribute
|
|
||||||
|> List.wrap()
|
|
||||||
|> Enum.map(&String.to_atom/1)
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp load_custom_indexes(custom_indexes) do
|
defp load_custom_indexes(custom_indexes) do
|
||||||
Enum.map(custom_indexes || [], fn custom_index ->
|
Enum.map(custom_indexes || [], fn custom_index ->
|
||||||
custom_index
|
custom_index
|
||||||
|
|
|
@ -587,7 +587,6 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
||||||
join([
|
join([
|
||||||
option(:name, index.name),
|
option(:name, index.name),
|
||||||
option(:unique, index.unique),
|
option(:unique, index.unique),
|
||||||
option(:concurrently, index.concurrently),
|
|
||||||
option(:using, index.using),
|
option(:using, index.using),
|
||||||
option(:where, index.where),
|
option(:where, index.where),
|
||||||
option(:include, index.include)
|
option(:include, index.include)
|
||||||
|
@ -687,7 +686,6 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
||||||
join([
|
join([
|
||||||
option(:name, index.name),
|
option(:name, index.name),
|
||||||
option(:unique, index.unique),
|
option(:unique, index.unique),
|
||||||
option(:concurrently, index.concurrently),
|
|
||||||
option(:using, index.using),
|
option(:using, index.using),
|
||||||
option(:where, index.where),
|
option(:where, index.where),
|
||||||
option(:include, index.include)
|
option(:include, index.include)
|
||||||
|
@ -783,59 +781,4 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule AddCheckConstraint do
|
|
||||||
@moduledoc false
|
|
||||||
defstruct [:table, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
|
||||||
|
|
||||||
import Helper
|
|
||||||
|
|
||||||
def up(%{
|
|
||||||
constraint: %{
|
|
||||||
name: name,
|
|
||||||
check: check,
|
|
||||||
base_filter: base_filter
|
|
||||||
},
|
|
||||||
table: table
|
|
||||||
}) do
|
|
||||||
if base_filter do
|
|
||||||
"create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{base_filter} AND #{check}\")"])}"
|
|
||||||
else
|
|
||||||
"create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{check}\")"])}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def down(%{
|
|
||||||
constraint: %{name: name},
|
|
||||||
table: table
|
|
||||||
}) do
|
|
||||||
"drop_if_exists constraint(:#{as_atom(table)}, #{join([":#{as_atom(name)}"])})"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule RemoveCheckConstraint do
|
|
||||||
@moduledoc false
|
|
||||||
defstruct [:table, :constraint, :multitenancy, :old_multitenancy, no_phase: true]
|
|
||||||
|
|
||||||
import Helper
|
|
||||||
|
|
||||||
def up(%{constraint: %{name: name}, table: table}) do
|
|
||||||
"drop_if_exists constraint(:#{as_atom(table)}, #{join([":#{as_atom(name)}"])})"
|
|
||||||
end
|
|
||||||
|
|
||||||
def down(%{
|
|
||||||
constraint: %{
|
|
||||||
name: name,
|
|
||||||
check: check,
|
|
||||||
base_filter: base_filter
|
|
||||||
},
|
|
||||||
table: table
|
|
||||||
}) do
|
|
||||||
if base_filter do
|
|
||||||
"create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{base_filter} AND #{check}\")"])}"
|
|
||||||
else
|
|
||||||
"create constraint(:#{as_atom(table)}, :#{as_atom(name)}, #{join(["check: \"#{check}\")"])}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,7 +123,6 @@ defmodule AshSqlite.MixHelpers do
|
||||||
opts[:migrations_path] || repo.config()[:migrations_path] || derive_migrations_path(repo)
|
opts[:migrations_path] || repo.config()[:migrations_path] || derive_migrations_path(repo)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def derive_migrations_path(repo) do
|
def derive_migrations_path(repo) do
|
||||||
config = repo.config()
|
config = repo.config()
|
||||||
priv = config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}"
|
priv = config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}"
|
||||||
|
|
|
@ -50,7 +50,6 @@ defmodule AshSqlite.Repo do
|
||||||
|
|
||||||
def installed_extensions, do: []
|
def installed_extensions, do: []
|
||||||
def migrations_path, do: nil
|
def migrations_path, do: nil
|
||||||
def default_prefix, do: "public"
|
|
||||||
def override_migration_type(type), do: type
|
def override_migration_type(type), do: type
|
||||||
def min_pg_version, do: 10
|
def min_pg_version, do: 10
|
||||||
|
|
||||||
|
@ -59,7 +58,6 @@ defmodule AshSqlite.Repo do
|
||||||
config
|
config
|
||||||
|> Keyword.put(:installed_extensions, installed_extensions())
|
|> Keyword.put(:installed_extensions, installed_extensions())
|
||||||
|> Keyword.put(:migrations_path, migrations_path())
|
|> Keyword.put(:migrations_path, migrations_path())
|
||||||
|> Keyword.put(:default_prefix, default_prefix())
|
|
||||||
|
|
||||||
{:ok, new_config}
|
{:ok, new_config}
|
||||||
end
|
end
|
||||||
|
@ -164,7 +162,6 @@ defmodule AshSqlite.Repo do
|
||||||
defoverridable init: 2,
|
defoverridable init: 2,
|
||||||
on_transaction_begin: 1,
|
on_transaction_begin: 1,
|
||||||
installed_extensions: 0,
|
installed_extensions: 0,
|
||||||
default_prefix: 0,
|
|
||||||
override_migration_type: 1,
|
override_migration_type: 1,
|
||||||
min_pg_version: 0
|
min_pg_version: 0
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,7 @@ defmodule AshSqlite.Transformers.VerifyRepo do
|
||||||
match?({:error, _}, Code.ensure_compiled(repo)) ->
|
match?({:error, _}, Code.ensure_compiled(repo)) ->
|
||||||
{:error, "Could not find repo module #{repo}"}
|
{:error, "Could not find repo module #{repo}"}
|
||||||
|
|
||||||
repo.__adapter__() != Ecto.Adapters.Sqlite3 ->
|
repo.__adapter__() != Ecto.Adapters.SQLite3 ->
|
||||||
{:error, "Expected a repo using the sqlite adapter `Ecto.Adapters.SQLite3`"}
|
{:error, "Expected a repo using the sqlite adapter `Ecto.Adapters.SQLite3`"}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
|
|
7
mix.exs
7
mix.exs
|
@ -43,7 +43,10 @@ defmodule AshSqlite.MixProject do
|
||||||
|
|
||||||
if Mix.env() == :test do
|
if Mix.env() == :test do
|
||||||
def application() do
|
def application() do
|
||||||
[applications: [:ecto, :ecto_sql, :jason, :ash, :postgrex], mod: {AshSqlite.TestApp, []}]
|
[
|
||||||
|
applications: [:ecto, :ecto_sql, :ecto_sqlite3, :jason, :ash],
|
||||||
|
mod: {AshSqlite.TestApp, []}
|
||||||
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -145,7 +148,6 @@ defmodule AshSqlite.MixProject do
|
||||||
],
|
],
|
||||||
Introspection: [
|
Introspection: [
|
||||||
AshSqlite.DataLayer.Info,
|
AshSqlite.DataLayer.Info,
|
||||||
AshSqlite.CheckConstraint,
|
|
||||||
AshSqlite.CustomExtension,
|
AshSqlite.CustomExtension,
|
||||||
AshSqlite.CustomIndex,
|
AshSqlite.CustomIndex,
|
||||||
AshSqlite.Reference,
|
AshSqlite.Reference,
|
||||||
|
@ -173,7 +175,6 @@ defmodule AshSqlite.MixProject do
|
||||||
{:ecto_sqlite3, "~> 0.11"},
|
{:ecto_sqlite3, "~> 0.11"},
|
||||||
{:ecto, "~> 3.9"},
|
{:ecto, "~> 3.9"},
|
||||||
{:jason, "~> 1.0"},
|
{:jason, "~> 1.0"},
|
||||||
{:postgrex, ">= 0.0.0"},
|
|
||||||
{:ash, ash_version("~> 2.14 and >= 2.14.18")},
|
{:ash, ash_version("~> 2.14 and >= 2.14.18")},
|
||||||
{:git_ops, "~> 2.5", only: [:dev, :test]},
|
{:git_ops, "~> 2.5", only: [:dev, :test]},
|
||||||
{:ex_doc, "~> 0.22", only: [:dev, :test], runtime: false},
|
{:ex_doc, "~> 0.22", only: [:dev, :test], runtime: false},
|
||||||
|
|
1
mix.lock
1
mix.lock
|
@ -34,7 +34,6 @@
|
||||||
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
|
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
|
||||||
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
||||||
"picosat_elixir": {:hex, :picosat_elixir, "0.2.3", "bf326d0f179fbb3b706bb2c15fbc367dacfa2517157d090fdfc32edae004c597", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f76c9db2dec9d2561ffaa9be35f65403d53e984e8cd99c832383b7ab78c16c66"},
|
"picosat_elixir": {:hex, :picosat_elixir, "0.2.3", "bf326d0f179fbb3b706bb2c15fbc367dacfa2517157d090fdfc32edae004c597", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f76c9db2dec9d2561ffaa9be35f65403d53e984e8cd99c832383b7ab78c16c66"},
|
||||||
"postgrex": {:hex, :postgrex, "0.17.2", "a3ec9e3239d9b33f1e5841565c4eb200055c52cc0757a22b63ca2d529bbe764c", [: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", "80a918a9e9531d39f7bd70621422f3ebc93c01618c645f2d91306f50041ed90c"},
|
|
||||||
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
||||||
"sourceror": {:hex, :sourceror, "0.14.0", "b6b8552d0240400d66b6f107c1bab7ac1726e998efc797f178b7b517e928e314", [:mix], [], "hexpm", "809c71270ad48092d40bbe251a133e49ae229433ce103f762a2373b7a10a8d8b"},
|
"sourceror": {:hex, :sourceror, "0.14.0", "b6b8552d0240400d66b6f107c1bab7ac1726e998efc797f178b7b517e928e314", [:mix], [], "hexpm", "809c71270ad48092d40bbe251a133e49ae229433ce103f762a2373b7a10a8d8b"},
|
||||||
"spark": {:hex, :spark, "1.1.39", "f143b84a5b796bf2d83ec8fb4793ee9e66e67510c40d785f9a67050bb88e7677", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "d71bc26014c7e7abcdcf553f4cf7c5a5ff96f8365b1e20be3768ce503aafb203"},
|
"spark": {:hex, :spark, "1.1.39", "f143b84a5b796bf2d83ec8fb4793ee9e66e67510c40d785f9a67050bb88e7677", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.5 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "d71bc26014c7e7abcdcf553f4cf7c5a5ff96f8365b1e20be3768ce503aafb203"},
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "boolean",
|
||||||
|
"source": "is_active",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "user_id",
|
||||||
|
"references": {
|
||||||
|
"name": "accounts_user_id_fkey",
|
||||||
|
"table": "users",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "accounts",
|
||||||
|
"hash": "D9E9F02FE7FAA0A6245C109E6F60A30C6E1B869222B0D8F233F6DE0BB61208FC",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "first_name",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "last_name",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "map",
|
||||||
|
"source": "bio",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"text"
|
||||||
|
],
|
||||||
|
"source": "badges",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "authors",
|
||||||
|
"hash": "046788B41EC7355A3649FB5A7FFFDE7EA5AC7DB0A8D661455AE0EE47EDCB3954",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "score",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "resource_id",
|
||||||
|
"references": {
|
||||||
|
"name": "comment_ratings_resource_id_fkey",
|
||||||
|
"table": "comments",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": false,
|
||||||
|
"destination_attribute_default": "nil",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "comment_ratings",
|
||||||
|
"hash": "EA05462C665EF2CFA57E07758FEF9AB9244EBB75C3A75471BA457195E6018BFB",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
117
priv/resource_snapshots/test_repo/comments/20230923051130.json
Normal file
117
priv/resource_snapshots/test_repo/comments/20230923051130.json
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "title",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "likes",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "utc_datetime_usec",
|
||||||
|
"source": "arbitrary_timestamp",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "utc_datetime_usec",
|
||||||
|
"source": "created_at",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "post_id",
|
||||||
|
"references": {
|
||||||
|
"name": "special_name_fkey",
|
||||||
|
"table": "posts",
|
||||||
|
"on_delete": "delete",
|
||||||
|
"on_update": "update",
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "author_id",
|
||||||
|
"references": {
|
||||||
|
"name": "comments_author_id_fkey",
|
||||||
|
"table": "authors",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "comments",
|
||||||
|
"hash": "F8021D06DAA6DBAA04DD4560E664905182EA32587D0087EC9F8BD145E40A8432",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "title",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "integer_posts",
|
||||||
|
"hash": "A06710150BA7BDCA09FBD107B3F6B5174EA424D0317A4452BDB7BEF3DA1435F0",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
101
priv/resource_snapshots/test_repo/managers/20230923051130.json
Normal file
101
priv/resource_snapshots/test_repo/managers/20230923051130.json
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "name",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "code",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "must_be_present",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "role",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "organization_id",
|
||||||
|
"references": {
|
||||||
|
"name": "managers_organization_id_fkey",
|
||||||
|
"table": "orgs",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "managers",
|
||||||
|
"hash": "40BBC76EA6172776136FE98035C92E23033D6F758F642B0BBE86691E8016D1B2",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [
|
||||||
|
{
|
||||||
|
"name": "uniq_code",
|
||||||
|
"keys": [
|
||||||
|
"code"
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"index_name": "managers_uniq_code_index"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
37
priv/resource_snapshots/test_repo/orgs/20230923051130.json
Normal file
37
priv/resource_snapshots/test_repo/orgs/20230923051130.json
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "name",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "orgs",
|
||||||
|
"hash": "20DCD0C640F7BA5F64BEB236F05D79A091E1F3390507929060BAB2D38241C284",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "\"active\"",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "state",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "source_post_id",
|
||||||
|
"references": {
|
||||||
|
"name": "post_links_source_post_id_fkey",
|
||||||
|
"table": "posts",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "destination_post_id",
|
||||||
|
"references": {
|
||||||
|
"name": "post_links_destination_post_id_fkey",
|
||||||
|
"table": "posts",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "post_links",
|
||||||
|
"hash": "2583037B16689EDA7F8414C379C6D315D1E86BD4ED4FA6861E744F629E7CE8A3",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [
|
||||||
|
{
|
||||||
|
"name": "unique_link",
|
||||||
|
"keys": [
|
||||||
|
"source_post_id",
|
||||||
|
"destination_post_id"
|
||||||
|
],
|
||||||
|
"base_filter": null,
|
||||||
|
"index_name": "post_links_unique_link_index"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "score",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "resource_id",
|
||||||
|
"references": {
|
||||||
|
"name": "post_ratings_resource_id_fkey",
|
||||||
|
"table": "posts",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": false,
|
||||||
|
"destination_attribute_default": "nil",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "post_ratings",
|
||||||
|
"hash": "DE6056BA23D22810D95CCDB6FDF5F0FE9F558124FC8D9B08861B8F59099C0032",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "utc_datetime_usec",
|
||||||
|
"source": "time",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "browser",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "post_id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "post_views",
|
||||||
|
"hash": "25FC1D03DE747F86A8894536121520D288728618469978D90571337038FF2A23",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
274
priv/resource_snapshots/test_repo/posts/20230923051130.json
Normal file
274
priv/resource_snapshots/test_repo/posts/20230923051130.json
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "title",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "score",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "boolean",
|
||||||
|
"source": "public",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "category",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "\"sponsored\"",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "type",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "bigint",
|
||||||
|
"source": "price",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "\"0\"",
|
||||||
|
"size": null,
|
||||||
|
"type": "decimal",
|
||||||
|
"source": "decimal",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "status",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "status",
|
||||||
|
"source": "status_enum",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": [
|
||||||
|
"array",
|
||||||
|
"float"
|
||||||
|
],
|
||||||
|
"source": "point",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "map",
|
||||||
|
"source": "stuff",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "uniq_one",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "uniq_two",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "uniq_custom_one",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "uniq_custom_two",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "utc_datetime_usec",
|
||||||
|
"source": "created_at",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "utc_datetime_usec",
|
||||||
|
"source": "updated_at",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "organization_id",
|
||||||
|
"references": {
|
||||||
|
"name": "posts_organization_id_fkey",
|
||||||
|
"table": "orgs",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "author_id",
|
||||||
|
"references": {
|
||||||
|
"name": "posts_author_id_fkey",
|
||||||
|
"table": "authors",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "posts",
|
||||||
|
"hash": "53F023DD86C40482AB21DFD50A457BE677EAE3627B62F581357B24B4FE1D8611",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [
|
||||||
|
{
|
||||||
|
"message": "dude what the heck",
|
||||||
|
"name": null,
|
||||||
|
"table": null,
|
||||||
|
"include": null,
|
||||||
|
"fields": [
|
||||||
|
"uniq_custom_one",
|
||||||
|
"uniq_custom_two"
|
||||||
|
],
|
||||||
|
"where": null,
|
||||||
|
"unique": true,
|
||||||
|
"using": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"base_filter": "type = 'sponsored'",
|
||||||
|
"identities": [
|
||||||
|
{
|
||||||
|
"name": "uniq_one_and_two",
|
||||||
|
"keys": [
|
||||||
|
"uniq_one",
|
||||||
|
"uniq_two"
|
||||||
|
],
|
||||||
|
"base_filter": "type = 'sponsored'",
|
||||||
|
"index_name": "posts_uniq_one_and_two_index"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "text",
|
||||||
|
"source": "description",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "author_id",
|
||||||
|
"references": {
|
||||||
|
"name": "profile_author_id_fkey",
|
||||||
|
"table": "authors",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "profile",
|
||||||
|
"hash": "866B88FC262E758B5FA5C81951A000F31D0F0AB0AE6FFA2872C39EBC242CD097",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
62
priv/resource_snapshots/test_repo/users/20230923051130.json
Normal file
62
priv/resource_snapshots/test_repo/users/20230923051130.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "id",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": true,
|
||||||
|
"allow_nil?": false,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "boolean",
|
||||||
|
"source": "is_active",
|
||||||
|
"references": null,
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "nil",
|
||||||
|
"size": null,
|
||||||
|
"type": "uuid",
|
||||||
|
"source": "organization_id",
|
||||||
|
"references": {
|
||||||
|
"name": "users_organization_id_fkey",
|
||||||
|
"table": "orgs",
|
||||||
|
"on_delete": null,
|
||||||
|
"on_update": null,
|
||||||
|
"destination_attribute_generated": null,
|
||||||
|
"destination_attribute_default": null,
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"destination_attribute": "id",
|
||||||
|
"primary_key?": true,
|
||||||
|
"deferrable": false
|
||||||
|
},
|
||||||
|
"primary_key?": false,
|
||||||
|
"allow_nil?": true,
|
||||||
|
"generated?": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"table": "users",
|
||||||
|
"hash": "EBC30A0BFC23F11FEBED0038376C50027BEAF7FFE7B896CCFD20A09F37B39617",
|
||||||
|
"repo": "Elixir.AshSqlite.TestRepo",
|
||||||
|
"multitenancy": {
|
||||||
|
"global": null,
|
||||||
|
"attribute": null,
|
||||||
|
"strategy": null
|
||||||
|
},
|
||||||
|
"custom_indexes": [],
|
||||||
|
"base_filter": null,
|
||||||
|
"identities": [],
|
||||||
|
"custom_statements": [],
|
||||||
|
"has_create_action": true
|
||||||
|
}
|
231
priv/test_repo/migrations/20230923051130_migrate_resources1.exs
Normal file
231
priv/test_repo/migrations/20230923051130_migrate_resources1.exs
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
defmodule AshSqlite.TestRepo.Migrations.MigrateResources1 do
|
||||||
|
@moduledoc """
|
||||||
|
Updates resources based on their most recent snapshots.
|
||||||
|
|
||||||
|
This file was autogenerated with `mix ash_sqlite.generate_migrations`
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
create table(:users, primary_key: false) do
|
||||||
|
add :organization_id,
|
||||||
|
references(:orgs, column: :id, name: "users_organization_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :is_active, :boolean
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:profile, primary_key: false) do
|
||||||
|
add :author_id,
|
||||||
|
references(:authors, column: :id, name: "profile_author_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :description, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:posts, primary_key: false) do
|
||||||
|
add :author_id, references(:authors, column: :id, name: "posts_author_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :organization_id,
|
||||||
|
references(:orgs, column: :id, name: "posts_organization_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :updated_at, :utc_datetime_usec, null: false
|
||||||
|
add :created_at, :utc_datetime_usec, null: false
|
||||||
|
add :uniq_custom_two, :text
|
||||||
|
add :uniq_custom_one, :text
|
||||||
|
add :uniq_two, :text
|
||||||
|
add :uniq_one, :text
|
||||||
|
add :stuff, :map
|
||||||
|
add :point, {:array, :float}
|
||||||
|
add :status_enum, :status
|
||||||
|
add :status, :text
|
||||||
|
add :decimal, :decimal, default: "0"
|
||||||
|
add :price, :bigint
|
||||||
|
add :type, :text, default: "sponsored"
|
||||||
|
add :category, :text
|
||||||
|
add :public, :boolean
|
||||||
|
add :score, :bigint
|
||||||
|
add :title, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:post_views, primary_key: false) do
|
||||||
|
add :post_id, :uuid, null: false
|
||||||
|
add :browser, :text
|
||||||
|
add :time, :utc_datetime_usec, null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:post_ratings, primary_key: false) do
|
||||||
|
add :resource_id,
|
||||||
|
references(:posts, column: :id, name: "post_ratings_resource_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :score, :bigint
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:post_links, primary_key: false) do
|
||||||
|
add :destination_post_id,
|
||||||
|
references(:posts,
|
||||||
|
column: :id,
|
||||||
|
name: "post_links_destination_post_id_fkey",
|
||||||
|
type: :uuid
|
||||||
|
),
|
||||||
|
primary_key: true,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
add :source_post_id,
|
||||||
|
references(:posts, column: :id, name: "post_links_source_post_id_fkey", type: :uuid),
|
||||||
|
primary_key: true,
|
||||||
|
null: false
|
||||||
|
|
||||||
|
add :state, :text, default: "active"
|
||||||
|
end
|
||||||
|
|
||||||
|
create unique_index(:post_links, [:source_post_id, :destination_post_id],
|
||||||
|
name: "post_links_unique_link_index"
|
||||||
|
)
|
||||||
|
|
||||||
|
create table(:orgs, primary_key: false) do
|
||||||
|
add :name, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:managers, primary_key: false) do
|
||||||
|
add :organization_id,
|
||||||
|
references(:orgs, column: :id, name: "managers_organization_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :role, :text
|
||||||
|
add :must_be_present, :text, null: false
|
||||||
|
add :code, :text, null: false
|
||||||
|
add :name, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create unique_index(:managers, [:code], name: "managers_uniq_code_index")
|
||||||
|
|
||||||
|
create table(:integer_posts, primary_key: false) do
|
||||||
|
add :title, :text
|
||||||
|
add :id, :bigserial, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:comments, primary_key: false) do
|
||||||
|
add :author_id,
|
||||||
|
references(:authors, column: :id, name: "comments_author_id_fkey", type: :uuid)
|
||||||
|
|
||||||
|
add :post_id,
|
||||||
|
references(:posts,
|
||||||
|
column: :id,
|
||||||
|
name: "special_name_fkey",
|
||||||
|
type: :uuid,
|
||||||
|
on_delete: :delete_all,
|
||||||
|
on_update: :update_all
|
||||||
|
)
|
||||||
|
|
||||||
|
add :created_at, :utc_datetime_usec, null: false
|
||||||
|
add :arbitrary_timestamp, :utc_datetime_usec
|
||||||
|
add :likes, :bigint
|
||||||
|
add :title, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:comment_ratings, primary_key: false) do
|
||||||
|
add :resource_id,
|
||||||
|
references(:comments,
|
||||||
|
column: :id,
|
||||||
|
name: "comment_ratings_resource_id_fkey",
|
||||||
|
type: :uuid
|
||||||
|
)
|
||||||
|
|
||||||
|
add :score, :bigint
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create table(:authors, primary_key: false) do
|
||||||
|
add :badges, {:array, :text}
|
||||||
|
add :bio, :map
|
||||||
|
add :last_name, :text
|
||||||
|
add :first_name, :text
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create index(:posts, ["uniq_custom_one", "uniq_custom_two"], unique: true)
|
||||||
|
|
||||||
|
create unique_index(:posts, [:uniq_one, :uniq_two],
|
||||||
|
where: "type = 'sponsored'",
|
||||||
|
name: "posts_uniq_one_and_two_index"
|
||||||
|
)
|
||||||
|
|
||||||
|
create table(:accounts, primary_key: false) do
|
||||||
|
add :user_id, references(:users, column: :id, name: "accounts_user_id_fkey", type: :uuid)
|
||||||
|
add :is_active, :boolean
|
||||||
|
add :id, :uuid, null: false, primary_key: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop constraint(:accounts, "accounts_user_id_fkey")
|
||||||
|
|
||||||
|
drop table(:accounts)
|
||||||
|
|
||||||
|
drop_if_exists unique_index(:posts, [:uniq_one, :uniq_two],
|
||||||
|
name: "posts_uniq_one_and_two_index"
|
||||||
|
)
|
||||||
|
|
||||||
|
drop_if_exists index(:posts, ["uniq_custom_one", "uniq_custom_two"],
|
||||||
|
name: "posts_uniq_custom_one_uniq_custom_two_index"
|
||||||
|
)
|
||||||
|
|
||||||
|
drop table(:authors)
|
||||||
|
|
||||||
|
drop constraint(:comment_ratings, "comment_ratings_resource_id_fkey")
|
||||||
|
|
||||||
|
drop table(:comment_ratings)
|
||||||
|
|
||||||
|
drop constraint(:comments, "special_name_fkey")
|
||||||
|
|
||||||
|
drop constraint(:comments, "comments_author_id_fkey")
|
||||||
|
|
||||||
|
drop table(:comments)
|
||||||
|
|
||||||
|
drop table(:integer_posts)
|
||||||
|
|
||||||
|
drop_if_exists unique_index(:managers, [:code], name: "managers_uniq_code_index")
|
||||||
|
|
||||||
|
drop constraint(:managers, "managers_organization_id_fkey")
|
||||||
|
|
||||||
|
drop table(:managers)
|
||||||
|
|
||||||
|
drop table(:orgs)
|
||||||
|
|
||||||
|
drop_if_exists unique_index(:post_links, [:source_post_id, :destination_post_id],
|
||||||
|
name: "post_links_unique_link_index"
|
||||||
|
)
|
||||||
|
|
||||||
|
drop constraint(:post_links, "post_links_source_post_id_fkey")
|
||||||
|
|
||||||
|
drop constraint(:post_links, "post_links_destination_post_id_fkey")
|
||||||
|
|
||||||
|
drop table(:post_links)
|
||||||
|
|
||||||
|
drop constraint(:post_ratings, "post_ratings_resource_id_fkey")
|
||||||
|
|
||||||
|
drop table(:post_ratings)
|
||||||
|
|
||||||
|
drop table(:post_views)
|
||||||
|
|
||||||
|
drop constraint(:posts, "posts_organization_id_fkey")
|
||||||
|
|
||||||
|
drop constraint(:posts, "posts_author_id_fkey")
|
||||||
|
|
||||||
|
drop table(:posts)
|
||||||
|
|
||||||
|
drop constraint(:profile, "profile_author_id_fkey")
|
||||||
|
|
||||||
|
drop table(:profile)
|
||||||
|
|
||||||
|
drop constraint(:users, "users_organization_id_fkey")
|
||||||
|
|
||||||
|
drop table(:users)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,57 +0,0 @@
|
||||||
defmodule AshSqlite.Test.LockTest do
|
|
||||||
use AshSqlite.RepoCase, async: false
|
|
||||||
alias AshSqlite.Test.{Api, Post}
|
|
||||||
require Ash.Query
|
|
||||||
|
|
||||||
setup do
|
|
||||||
Application.put_env(:ash, :disable_async?, true)
|
|
||||||
|
|
||||||
on_exit(fn ->
|
|
||||||
Application.put_env(:ash, :disable_async?, false)
|
|
||||||
AshSqlite.TestNoSandboxRepo.delete_all(Post)
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "lock conflicts raise appropriate errors" do
|
|
||||||
post =
|
|
||||||
Post
|
|
||||||
|> Ash.Changeset.for_create(:create, %{title: "locked"})
|
|
||||||
|> Ash.Changeset.set_context(%{data_layer: %{repo: AshSqlite.TestNoSandboxRepo}})
|
|
||||||
|> Api.create!()
|
|
||||||
|
|
||||||
task1 =
|
|
||||||
Task.async(fn ->
|
|
||||||
AshSqlite.TestNoSandboxRepo.transaction(fn ->
|
|
||||||
Post
|
|
||||||
|> Ash.Query.lock("FOR UPDATE NOWAIT")
|
|
||||||
|> Ash.Query.set_context(%{data_layer: %{repo: AshSqlite.TestNoSandboxRepo}})
|
|
||||||
|> Ash.Query.filter(id == ^post.id)
|
|
||||||
|> Api.read!()
|
|
||||||
|
|
||||||
:timer.sleep(1000)
|
|
||||||
:ok
|
|
||||||
end)
|
|
||||||
end)
|
|
||||||
|
|
||||||
task2 =
|
|
||||||
Task.async(fn ->
|
|
||||||
try do
|
|
||||||
AshSqlite.TestNoSandboxRepo.transaction(fn ->
|
|
||||||
:timer.sleep(100)
|
|
||||||
|
|
||||||
Post
|
|
||||||
|> Ash.Query.lock("FOR UPDATE NOWAIT")
|
|
||||||
|> Ash.Query.set_context(%{data_layer: %{repo: AshSqlite.TestNoSandboxRepo}})
|
|
||||||
|> Ash.Query.filter(id == ^post.id)
|
|
||||||
|> Api.read!()
|
|
||||||
end)
|
|
||||||
rescue
|
|
||||||
e ->
|
|
||||||
{:error, e}
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
assert [{:ok, :ok}, {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Invalid.Unavailable{}]}}] =
|
|
||||||
Task.await_many([task1, task2], :infinity)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -151,50 +151,6 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "custom_indexes with `concurrently: true`" do
|
|
||||||
setup do
|
|
||||||
on_exit(fn ->
|
|
||||||
File.rm_rf!("test_snapshots_path")
|
|
||||||
File.rm_rf!("test_migration_path")
|
|
||||||
end)
|
|
||||||
|
|
||||||
defposts do
|
|
||||||
sqlite do
|
|
||||||
custom_indexes do
|
|
||||||
# need one without any opts
|
|
||||||
index([:title], concurrently: true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attributes do
|
|
||||||
uuid_primary_key(:id)
|
|
||||||
attribute(:title, :string)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defapi([Post])
|
|
||||||
Mix.shell(Mix.Shell.Process)
|
|
||||||
|
|
||||||
AshSqlite.MigrationGenerator.generate(Api,
|
|
||||||
snapshot_path: "test_snapshots_path",
|
|
||||||
migration_path: "test_migration_path",
|
|
||||||
quiet: true,
|
|
||||||
format: false
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it creates multiple migration files" do
|
|
||||||
assert [_, custom_index_migration] =
|
|
||||||
Enum.sort(Path.wildcard("test_migration_path/**/*_migrate_resources*.exs"))
|
|
||||||
|
|
||||||
file = File.read!(custom_index_migration)
|
|
||||||
|
|
||||||
assert file =~ ~S[@disable_ddl_transaction true]
|
|
||||||
|
|
||||||
assert file =~ ~S<create index(:posts, ["title"], concurrently: true)>
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "creating follow up migrations" do
|
describe "creating follow up migrations" do
|
||||||
setup do
|
setup do
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
|
@ -650,133 +606,6 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "check constraints" do
|
|
||||||
setup do
|
|
||||||
on_exit(fn ->
|
|
||||||
File.rm_rf!("test_snapshots_path")
|
|
||||||
File.rm_rf!("test_migration_path")
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "when added, the constraint is created" do
|
|
||||||
defposts do
|
|
||||||
attributes do
|
|
||||||
uuid_primary_key(:id)
|
|
||||||
attribute(:price, :integer)
|
|
||||||
end
|
|
||||||
|
|
||||||
sqlite do
|
|
||||||
check_constraints do
|
|
||||||
check_constraint(:price, "price_must_be_positive", check: "price > 0")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defapi([Post])
|
|
||||||
|
|
||||||
AshSqlite.MigrationGenerator.generate(Api,
|
|
||||||
snapshot_path: "test_snapshots_path",
|
|
||||||
migration_path: "test_migration_path",
|
|
||||||
quiet: true,
|
|
||||||
format: false
|
|
||||||
)
|
|
||||||
|
|
||||||
assert file =
|
|
||||||
"test_migration_path/**/*_migrate_resources*.exs"
|
|
||||||
|> Path.wildcard()
|
|
||||||
|> Enum.sort()
|
|
||||||
|> Enum.at(0)
|
|
||||||
|> File.read!()
|
|
||||||
|
|
||||||
assert file =~
|
|
||||||
~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")]
|
|
||||||
|
|
||||||
defposts do
|
|
||||||
attributes do
|
|
||||||
uuid_primary_key(:id)
|
|
||||||
attribute(:price, :integer)
|
|
||||||
end
|
|
||||||
|
|
||||||
sqlite do
|
|
||||||
check_constraints do
|
|
||||||
check_constraint(:price, "price_must_be_positive", check: "price > 1")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defapi([Post])
|
|
||||||
|
|
||||||
AshSqlite.MigrationGenerator.generate(Api,
|
|
||||||
snapshot_path: "test_snapshots_path",
|
|
||||||
migration_path: "test_migration_path",
|
|
||||||
quiet: true,
|
|
||||||
format: false
|
|
||||||
)
|
|
||||||
|
|
||||||
assert file =
|
|
||||||
"test_migration_path/**/*_migrate_resources*.exs"
|
|
||||||
|> Path.wildcard()
|
|
||||||
|> Enum.sort()
|
|
||||||
|> Enum.at(1)
|
|
||||||
|> File.read!()
|
|
||||||
|
|
||||||
assert [_, down] = String.split(file, "def down do")
|
|
||||||
|
|
||||||
assert [_, remaining] =
|
|
||||||
String.split(down, "drop_if_exists constraint(:posts, :price_must_be_positive)")
|
|
||||||
|
|
||||||
assert remaining =~
|
|
||||||
~S[create constraint(:posts, :price_must_be_positive, check: "price > 0")]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "when removed, the constraint is dropped before modification" do
|
|
||||||
defposts do
|
|
||||||
attributes do
|
|
||||||
uuid_primary_key(:id)
|
|
||||||
attribute(:price, :integer)
|
|
||||||
end
|
|
||||||
|
|
||||||
sqlite do
|
|
||||||
check_constraints do
|
|
||||||
check_constraint(:price, "price_must_be_positive", check: "price > 0")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defapi([Post])
|
|
||||||
|
|
||||||
AshSqlite.MigrationGenerator.generate(Api,
|
|
||||||
snapshot_path: "test_snapshots_path",
|
|
||||||
migration_path: "test_migration_path",
|
|
||||||
quiet: true,
|
|
||||||
format: false
|
|
||||||
)
|
|
||||||
|
|
||||||
defposts do
|
|
||||||
attributes do
|
|
||||||
uuid_primary_key(:id)
|
|
||||||
attribute(:price, :integer)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
AshSqlite.MigrationGenerator.generate(Api,
|
|
||||||
snapshot_path: "test_snapshots_path",
|
|
||||||
migration_path: "test_migration_path",
|
|
||||||
quiet: true,
|
|
||||||
format: false
|
|
||||||
)
|
|
||||||
|
|
||||||
assert file =
|
|
||||||
"test_migration_path/**/*_migrate_resources*.exs"
|
|
||||||
|> Path.wildcard()
|
|
||||||
|> Enum.sort()
|
|
||||||
|> Enum.at(1)
|
|
||||||
|
|
||||||
assert File.read!(file) =~
|
|
||||||
~S[drop_if_exists constraint(:posts, :price_must_be_positive)]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "polymorphic resources" do
|
describe "polymorphic resources" do
|
||||||
setup do
|
setup do
|
||||||
on_exit(fn ->
|
on_exit(fn ->
|
||||||
|
|
|
@ -18,17 +18,9 @@ defmodule AshSqlite.Test.Post do
|
||||||
repo(AshSqlite.TestRepo)
|
repo(AshSqlite.TestRepo)
|
||||||
base_filter_sql("type = 'sponsored'")
|
base_filter_sql("type = 'sponsored'")
|
||||||
|
|
||||||
check_constraints do
|
|
||||||
check_constraint(:price, "price_must_be_positive",
|
|
||||||
message: "yo, bad price",
|
|
||||||
check: "price > 0"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
custom_indexes do
|
custom_indexes do
|
||||||
index([:uniq_custom_one, :uniq_custom_two],
|
index([:uniq_custom_one, :uniq_custom_two],
|
||||||
unique: true,
|
unique: true,
|
||||||
concurrently: true,
|
|
||||||
message: "dude what the heck"
|
message: "dude what the heck"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -46,7 +38,7 @@ defmodule AshSqlite.Test.Post do
|
||||||
end
|
end
|
||||||
|
|
||||||
read :paginated do
|
read :paginated do
|
||||||
pagination(offset?: true, required?: true, countable: true)
|
pagination(offset?: true, required?: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
create :create do
|
create :create do
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
defmodule AshSqlite.TestNoSandboxRepo do
|
|
||||||
@moduledoc false
|
|
||||||
use AshSqlite.Repo,
|
|
||||||
otp_app: :ash_sqlite
|
|
||||||
|
|
||||||
def on_transaction_begin(data) do
|
|
||||||
send(self(), data)
|
|
||||||
end
|
|
||||||
|
|
||||||
def installed_extensions do
|
|
||||||
["ash-functions", AshSqlite.TestCustomExtension]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -6,8 +6,4 @@ defmodule AshSqlite.TestRepo do
|
||||||
def on_transaction_begin(data) do
|
def on_transaction_begin(data) do
|
||||||
send(self(), data)
|
send(self(), data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def installed_extensions do
|
|
||||||
["ash-functions", AshSqlite.TestCustomExtension]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,4 +2,5 @@ ExUnit.start()
|
||||||
ExUnit.configure(stacktrace_depth: 100)
|
ExUnit.configure(stacktrace_depth: 100)
|
||||||
|
|
||||||
AshSqlite.TestRepo.start_link()
|
AshSqlite.TestRepo.start_link()
|
||||||
AshSqlite.TestNoSandboxRepo.start_link()
|
|
||||||
|
Ecto.Adapters.SQL.Sandbox.mode(AshSqlite.TestRepo, :manual)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"ash_functions_version": 1,
|
|
||||||
"installed": [
|
|
||||||
"ash-functions",
|
|
||||||
"uuid-ossp",
|
|
||||||
"pg_trgm",
|
|
||||||
"citext",
|
|
||||||
"demo-functions_v1"
|
|
||||||
]
|
|
||||||
}
|
|
Loading…
Reference in a new issue