mirror of
https://github.com/ash-project/ash_sqlite.git
synced 2024-09-08 13:40:48 +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 = [
|
||||
base_filter_sql: 1,
|
||||
check: 1,
|
||||
check_constraint: 2,
|
||||
check_constraint: 3,
|
||||
code?: 1,
|
||||
concurrently: 1,
|
||||
create?: 1,
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -25,3 +25,6 @@ ash_sqlite-*.tar
|
|||
test_migration_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_sqlite, AshSqlite.TestRepo,
|
||||
username: "sqlite",
|
||||
database: "ash_sqlite",
|
||||
hostname: "localhost",
|
||||
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,
|
||||
database: Path.join(__DIR__, "../test/test.db"),
|
||||
pool_size: 1,
|
||||
migration_lock: false,
|
||||
pool: Ecto.Adapters.SQL.Sandbox,
|
||||
migration_primary_key: [name: :id, type: :binary_id]
|
||||
|
||||
config :ash_sqlite,
|
||||
ecto_repos: [AshSqlite.TestRepo, AshSqlite.TestNoSandboxRepo],
|
||||
ecto_repos: [AshSqlite.TestRepo],
|
||||
ash_apis: [
|
||||
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,
|
||||
:name,
|
||||
:unique,
|
||||
:concurrently,
|
||||
:using,
|
||||
:where,
|
||||
:include,
|
||||
|
@ -30,11 +29,6 @@ defmodule AshSqlite.CustomIndex do
|
|||
doc: "indicates whether the index should be unique.",
|
||||
default: false
|
||||
],
|
||||
concurrently: [
|
||||
type: :boolean,
|
||||
doc: "indicates whether the index should be created/dropped concurrently.",
|
||||
default: false
|
||||
],
|
||||
using: [
|
||||
type: :string,
|
||||
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{
|
||||
name: :references,
|
||||
describe: """
|
||||
|
@ -217,8 +179,7 @@ defmodule AshSqlite.DataLayer do
|
|||
sections: [
|
||||
@custom_indexes,
|
||||
@custom_statements,
|
||||
@references,
|
||||
@check_constraints
|
||||
@references
|
||||
],
|
||||
modules: [
|
||||
:repo
|
||||
|
@ -364,20 +325,9 @@ defmodule AshSqlite.DataLayer do
|
|||
import Ecto.Query, only: [from: 2, subquery: 1]
|
||||
|
||||
@impl true
|
||||
def can?(_, :async_engine), do: true
|
||||
def can?(_, :async_engine), do: false
|
||||
def can?(_, :bulk_create), do: true
|
||||
def can?(_, {:lock, :for_update}), do: true
|
||||
|
||||
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?(_, {:lock, _}), do: false
|
||||
|
||||
def can?(_, :transact), do: true
|
||||
def can?(_, :composite_primary_key), do: true
|
||||
|
@ -470,7 +420,7 @@ defmodule AshSqlite.DataLayer do
|
|||
data_layer_query
|
||||
end
|
||||
|
||||
default_bindings(data_layer_query, resource, context)
|
||||
{:ok, default_bindings(data_layer_query, resource, context)}
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
@ -545,8 +495,8 @@ defmodule AshSqlite.DataLayer do
|
|||
defp no_table?(_), do: false
|
||||
|
||||
defp repo_opts(timeout, nil, _resource) do
|
||||
[]
|
||||
|> add_timeout(timeout)
|
||||
[]
|
||||
|> add_timeout(timeout)
|
||||
end
|
||||
|
||||
defp repo_opts(timeout, _resource) do
|
||||
|
@ -563,7 +513,7 @@ defmodule AshSqlite.DataLayer do
|
|||
def functions(_resource) do
|
||||
[
|
||||
AshSqlite.Functions.Fragment,
|
||||
AshSqlite.Functions.Like,
|
||||
AshSqlite.Functions.Like
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -623,7 +573,6 @@ defmodule AshSqlite.DataLayer do
|
|||
else
|
||||
{:ok,
|
||||
Stream.zip_with(results, changesets, fn result, changeset ->
|
||||
|
||||
Ash.Resource.put_metadata(
|
||||
result,
|
||||
:bulk_create_index,
|
||||
|
@ -717,7 +666,6 @@ defmodule AshSqlite.DataLayer do
|
|||
|> Map.update!(:filters, &Map.merge(&1, filters))
|
||||
|> add_configured_foreign_key_constraints(record.__struct__)
|
||||
|> add_unique_indexes(record.__struct__, changeset)
|
||||
|> add_check_constraints(record.__struct__)
|
||||
|> add_exclusion_constraints(record.__struct__)
|
||||
|
||||
case type do
|
||||
|
@ -769,17 +717,16 @@ defmodule AshSqlite.DataLayer do
|
|||
changeset.context[:data_layer][:table] ||
|
||||
AshSqlite.DataLayer.Info.table(record.__struct__)
|
||||
|
||||
if table do
|
||||
Ecto.put_meta(record, source: table)
|
||||
if table do
|
||||
Ecto.put_meta(record, source: table)
|
||||
else
|
||||
if table_error? do
|
||||
raise_table_error!(changeset.resource, operation)
|
||||
else
|
||||
if table_error? do
|
||||
raise_table_error!(changeset.resource, operation)
|
||||
else
|
||||
record
|
||||
end
|
||||
record
|
||||
end
|
||||
|
||||
else
|
||||
end
|
||||
else
|
||||
record
|
||||
end
|
||||
end
|
||||
|
@ -847,21 +794,6 @@ defmodule AshSqlite.DataLayer do
|
|||
|
||||
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
|
||||
resource
|
||||
|> AshSqlite.DataLayer.Info.exclusion_constraint_names()
|
||||
|
@ -999,34 +931,34 @@ defmodule AshSqlite.DataLayer do
|
|||
|
||||
@impl true
|
||||
def upsert(resource, changeset, keys \\ nil) do
|
||||
keys = keys || Ash.Resource.Info.primary_key(resource)
|
||||
keys = keys || Ash.Resource.Info.primary_key(resource)
|
||||
|
||||
explicitly_changing_attributes =
|
||||
Enum.map(
|
||||
Map.keys(changeset.attributes) -- Map.get(changeset, :defaults, []) -- keys,
|
||||
fn key ->
|
||||
{key, Ash.Changeset.get_attribute(changeset, key)}
|
||||
end
|
||||
)
|
||||
explicitly_changing_attributes =
|
||||
Enum.map(
|
||||
Map.keys(changeset.attributes) -- Map.get(changeset, :defaults, []) -- keys,
|
||||
fn key ->
|
||||
{key, Ash.Changeset.get_attribute(changeset, key)}
|
||||
end
|
||||
)
|
||||
|
||||
on_conflict =
|
||||
changeset
|
||||
|> update_defaults()
|
||||
|> Keyword.merge(explicitly_changing_attributes)
|
||||
on_conflict =
|
||||
changeset
|
||||
|> update_defaults()
|
||||
|> Keyword.merge(explicitly_changing_attributes)
|
||||
|
||||
case bulk_create(resource, [changeset], %{
|
||||
single?: true,
|
||||
upsert?: true,
|
||||
upsert_keys: keys,
|
||||
upsert_fields: Keyword.keys(on_conflict),
|
||||
return_records?: true
|
||||
}) do
|
||||
{:ok, [result]} ->
|
||||
{:ok, result}
|
||||
case bulk_create(resource, [changeset], %{
|
||||
single?: true,
|
||||
upsert?: true,
|
||||
upsert_keys: keys,
|
||||
upsert_fields: Keyword.keys(on_conflict),
|
||||
return_records?: true
|
||||
}) do
|
||||
{:ok, [result]} ->
|
||||
{:ok, result}
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
end
|
||||
|
||||
defp conflict_target(resource, keys) do
|
||||
|
@ -1264,41 +1196,6 @@ defmodule AshSqlite.DataLayer do
|
|||
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
|
||||
def sort(query, sort, _resource) do
|
||||
{:ok, Map.update!(query, :__ash_bindings__, &Map.put(&1, :sort, sort))}
|
||||
|
@ -1374,7 +1271,6 @@ defmodule AshSqlite.DataLayer do
|
|||
:with_ctes,
|
||||
:limit,
|
||||
:offset,
|
||||
:lock,
|
||||
:preload,
|
||||
:update,
|
||||
:where
|
||||
|
|
|
@ -13,7 +13,6 @@ defmodule AshSqlite.DataLayer.Info do
|
|||
Extension.get_opt(resource, [:sqlite], :table, nil, true)
|
||||
end
|
||||
|
||||
|
||||
@doc "The configured references for a resource"
|
||||
def references(resource) do
|
||||
Extension.get_entities(resource, [:sqlite, :references])
|
||||
|
@ -41,10 +40,6 @@ defmodule AshSqlite.DataLayer.Info do
|
|||
Extension.get_opt(resource, [:sqlite], :migration_ignore_attributes, [])
|
||||
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"
|
||||
def custom_indexes(resource) do
|
||||
|
@ -120,5 +115,4 @@ defmodule AshSqlite.DataLayer.Info do
|
|||
def skip_unique_indexes(resource) do
|
||||
Extension.get_opt(resource, [:sqlite], :skip_unique_indexes, [])
|
||||
end
|
||||
|
||||
end
|
||||
|
|
70
lib/expr.ex
70
lib/expr.ex
|
@ -385,24 +385,7 @@ defmodule AshSqlite.Expr do
|
|||
type
|
||||
) do
|
||||
if options[:trim?] do
|
||||
require_ash_functions!(query, "string_split(..., trim?: true)")
|
||||
|
||||
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
|
||||
)
|
||||
raise "trim?: true not supported by AshSqlite"
|
||||
else
|
||||
do_dynamic_expr(
|
||||
query,
|
||||
|
@ -641,44 +624,10 @@ defmodule AshSqlite.Expr do
|
|||
)
|
||||
|
||||
:|| ->
|
||||
require_ash_functions!(query, "||")
|
||||
|
||||
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
|
||||
)
|
||||
raise "|| operator not supported by AshSqlite"
|
||||
|
||||
:&& ->
|
||||
require_ash_functions!(query, "&&")
|
||||
|
||||
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
|
||||
)
|
||||
raise "&& operator not supported by AshSqlite"
|
||||
|
||||
other ->
|
||||
raise "Operator not implemented #{other}"
|
||||
|
@ -1289,19 +1238,6 @@ defmodule AshSqlite.Expr do
|
|||
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
|
||||
repo = AshSqlite.DataLayer.Info.repo(query.__ash_bindings__.resource)
|
||||
|
||||
|
|
|
@ -579,6 +579,7 @@ defmodule AshSqlite.Join do
|
|||
relationship_destination =
|
||||
relationship_destination
|
||||
|> Ecto.Queryable.to_query()
|
||||
|
||||
binding_kinds =
|
||||
case kind do
|
||||
:left ->
|
||||
|
|
|
@ -25,7 +25,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|
||||
all_resources = Enum.uniq(Enum.flat_map(apis, &Ash.Api.Info.resources/1))
|
||||
|
||||
snapshots =
|
||||
snapshots =
|
||||
all_resources
|
||||
|> Enum.filter(fn resource ->
|
||||
Ash.DataLayer.data_layer(resource) == AshSqlite.DataLayer &&
|
||||
|
@ -142,8 +142,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv", "resource_snapshots"])
|
||||
end
|
||||
|
||||
@latest_ash_functions_version 1
|
||||
|
||||
defp create_extension_migrations(repos, opts) do
|
||||
for repo <- repos do
|
||||
snapshot_path = snapshot_path(opts, repo)
|
||||
|
@ -158,7 +156,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
[]
|
||||
end
|
||||
|
||||
{extensions_snapshot, installed_extensions} =
|
||||
{_extensions_snapshot, installed_extensions} =
|
||||
case installed_extensions do
|
||||
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.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
|
||||
Mix.shell().info("No extensions to install")
|
||||
:ok
|
||||
|
@ -227,26 +216,20 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|
||||
install =
|
||||
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) ->
|
||||
up_fn.(version)
|
||||
|
||||
extension ->
|
||||
"execute(\"CREATE EXTENSION IF NOT EXISTS \\\"#{extension}\\\"\")"
|
||||
raise "only custom extensions supported currently. Got #{inspect(extension)}"
|
||||
end)
|
||||
|
||||
uninstall =
|
||||
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) ->
|
||||
down_fn.(version)
|
||||
|
||||
extension ->
|
||||
"# execute(\"DROP EXTENSION IF EXISTS \\\"#{extension}\\\"\")"
|
||||
raise "only custom extensions supported currently. Got #{inspect(extension)}"
|
||||
end)
|
||||
|
||||
contents = """
|
||||
|
@ -277,8 +260,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
Jason.encode!(
|
||||
%{
|
||||
installed: installed
|
||||
}
|
||||
|> set_ash_functions(installed),
|
||||
},
|
||||
pretty: true
|
||||
)
|
||||
|
||||
|
@ -289,122 +271,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
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
|
||||
snapshots
|
||||
|> Enum.group_by(& &1.repo)
|
||||
|
@ -442,46 +308,15 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
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
|
||||
|> organize_operations
|
||||
|> build_up_and_down()
|
||||
|> write_migration!(repo, opts, run_without_transaction?)
|
||||
end)
|
||||
|> organize_operations
|
||||
|> build_up_and_down()
|
||||
|> write_migration!(repo, opts, false)
|
||||
|
||||
create_new_snapshot(snapshots, repo_name(repo), opts)
|
||||
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
|
||||
operations_with_order = Enum.map(operations, &add_order_to_operation(&1, snapshot.attributes))
|
||||
|
||||
|
@ -828,13 +663,13 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
config = repo.config()
|
||||
app = Keyword.fetch!(config, :otp_app)
|
||||
|
||||
if opts.migration_path do
|
||||
opts.migration_path
|
||||
else
|
||||
Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv"])
|
||||
end
|
||||
|> Path.join(repo_name)
|
||||
|> Path.join("migrations")
|
||||
if opts.migration_path do
|
||||
opts.migration_path
|
||||
else
|
||||
Path.join([Mix.Project.deps_paths()[app] || File.cwd!(), "priv"])
|
||||
end
|
||||
|> Path.join(repo_name)
|
||||
|> Path.join("migrations")
|
||||
end
|
||||
|
||||
defp repo_name(repo) do
|
||||
|
@ -877,7 +712,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Path.join(migration_name <> ".exs")
|
||||
|
||||
module_name =
|
||||
Module.concat([repo, Migrations, Macro.camelize(last_part)])
|
||||
Module.concat([repo, Migrations, Macro.camelize(last_part)])
|
||||
|
||||
module_attributes =
|
||||
if run_without_transaction? do
|
||||
|
@ -953,9 +788,9 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
snapshot_binary = snapshot_to_binary(snapshot)
|
||||
|
||||
snapshot_folder =
|
||||
opts
|
||||
|> snapshot_path(snapshot.repo)
|
||||
|> Path.join(repo_name)
|
||||
opts
|
||||
|> snapshot_path(snapshot.repo)
|
||||
|> Path.join(repo_name)
|
||||
|
||||
snapshot_file = Path.join(snapshot_folder, "#{snapshot.table}/#{timestamp()}.json")
|
||||
|
||||
|
@ -1104,9 +939,20 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
nil,
|
||||
acc
|
||||
) 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(
|
||||
rest,
|
||||
%Phase.Create{table: table, multitenancy: multitenancy},
|
||||
%Phase.Create{
|
||||
table: table,
|
||||
multitenancy: multitenancy,
|
||||
operations: has_to_be_in_this_phase
|
||||
},
|
||||
acc
|
||||
)
|
||||
end
|
||||
|
@ -1240,18 +1086,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
true
|
||||
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?(
|
||||
%Operation.AddCustomIndex{
|
||||
table: table
|
||||
|
@ -1261,68 +1095,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
true
|
||||
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?(
|
||||
%Operation.RemoveUniqueIndex{table: table},
|
||||
%Operation.AddUniqueIndex{table: table}
|
||||
|
@ -1337,29 +1109,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
true
|
||||
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{
|
||||
table: table,
|
||||
direction: :up
|
||||
|
@ -1386,7 +1135,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|
||||
defp after?(%Operation.AddAttribute{table: table}, %Operation.CreateTable{
|
||||
table: table
|
||||
}) do
|
||||
}) do
|
||||
true
|
||||
end
|
||||
|
||||
|
@ -1583,12 +1332,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
),
|
||||
do: true
|
||||
|
||||
defp after?(%Operation.AddCheckConstraint{table: table}, %Operation.CreateTable{
|
||||
table: table
|
||||
}) do
|
||||
true
|
||||
end
|
||||
|
||||
defp after?(
|
||||
%Operation.AlterAttribute{new_attribute: %{references: references}, table: table},
|
||||
%{table: table}
|
||||
|
@ -1596,9 +1339,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
when not is_nil(references),
|
||||
do: true
|
||||
|
||||
defp after?(%Operation.AddCheckConstraint{}, _), do: true
|
||||
defp after?(%Operation.RemoveCheckConstraint{}, _), do: true
|
||||
|
||||
defp after?(_, _), do: false
|
||||
|
||||
defp fetch_operations(snapshots, opts) do
|
||||
|
@ -1619,7 +1359,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
identities: [],
|
||||
custom_indexes: [],
|
||||
custom_statements: [],
|
||||
check_constraints: [],
|
||||
table: snapshot.table,
|
||||
repo: snapshot.repo,
|
||||
base_filter: nil,
|
||||
|
@ -1770,33 +1509,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
}
|
||||
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,
|
||||
|
@ -1804,8 +1516,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
attribute_operations,
|
||||
unique_indexes_to_add,
|
||||
unique_indexes_to_rename,
|
||||
constraints_to_remove,
|
||||
constraints_to_add,
|
||||
custom_indexes_to_add,
|
||||
custom_indexes_to_remove,
|
||||
custom_statements_to_add,
|
||||
|
@ -1874,8 +1584,8 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|
||||
if must_drop_pkey? do
|
||||
[
|
||||
%Operation.RemovePrimaryKey{ table: snapshot.table},
|
||||
%Operation.RemovePrimaryKeyDown{ table: snapshot.table}
|
||||
%Operation.RemovePrimaryKey{table: snapshot.table},
|
||||
%Operation.RemovePrimaryKeyDown{table: snapshot.table}
|
||||
]
|
||||
else
|
||||
[]
|
||||
|
@ -1921,32 +1631,9 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
add_attribute_events =
|
||||
Enum.flat_map(attributes_to_add, fn attribute ->
|
||||
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{
|
||||
attribute: Map.delete(attribute, :references),
|
||||
table: snapshot.table
|
||||
},
|
||||
%Operation.AlterAttribute{
|
||||
old_attribute: Map.delete(attribute, :references),
|
||||
new_attribute: attribute,
|
||||
attribute: attribute,
|
||||
table: snapshot.table
|
||||
},
|
||||
%Operation.DropForeignKey{
|
||||
|
@ -1955,7 +1642,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
multitenancy: Map.get(attribute, :multitenancy),
|
||||
direction: :down
|
||||
}
|
||||
] ++ reference_ops
|
||||
]
|
||||
else
|
||||
[
|
||||
%Operation.AddAttribute{
|
||||
|
@ -2137,9 +1824,9 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
repo_name = snapshot.repo |> Module.split() |> List.last() |> Macro.underscore()
|
||||
|
||||
folder =
|
||||
opts
|
||||
|> snapshot_path(snapshot.repo)
|
||||
|> Path.join(repo_name)
|
||||
opts
|
||||
|> snapshot_path(snapshot.repo)
|
||||
|> Path.join(repo_name)
|
||||
|
||||
snapshot_folder = Path.join(folder, snapshot.table)
|
||||
|
||||
|
@ -2281,9 +1968,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Enum.uniq()
|
||||
|> Enum.map(fn relationship ->
|
||||
resource
|
||||
|> do_snapshot(
|
||||
relationship.context[:data_layer][:table]
|
||||
)
|
||||
|> do_snapshot(relationship.context[:data_layer][:table])
|
||||
|> Map.update!(:identities, fn identities ->
|
||||
identity_index_names = AshSqlite.DataLayer.Info.identity_index_names(resource)
|
||||
|
||||
|
@ -2342,7 +2027,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
attributes: attributes(resource, table),
|
||||
identities: identities(resource),
|
||||
table: table || AshSqlite.DataLayer.Info.table(resource),
|
||||
check_constraints: check_constraints(resource),
|
||||
custom_indexes: custom_indexes(resource),
|
||||
custom_statements: custom_statements(resource),
|
||||
repo: AshSqlite.DataLayer.Info.repo(resource),
|
||||
|
@ -2365,48 +2049,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Enum.any?(&(&1.type == :create))
|
||||
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
|
||||
resource
|
||||
|> AshSqlite.DataLayer.Info.custom_indexes()
|
||||
|
@ -2590,7 +2232,7 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
defp foreign_key?(relationship) do
|
||||
Ash.DataLayer.data_layer(relationship.source) == AshSqlite.DataLayer &&
|
||||
AshSqlite.DataLayer.Info.repo(relationship.source) ==
|
||||
AshSqlite.DataLayer.Info.repo(relationship.destination)
|
||||
AshSqlite.DataLayer.Info.repo(relationship.destination)
|
||||
end
|
||||
|
||||
defp identities(resource) do
|
||||
|
@ -2646,20 +2288,9 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Enum.map(&Map.put(&1, :base_filter, AshSqlite.DataLayer.Info.base_filter_sql(resource)))
|
||||
end
|
||||
|
||||
@uuid_functions [&Ash.UUID.generate/0, &Ecto.UUID.generate/0]
|
||||
|
||||
defp default(%{name: name, default: default}, resource, repo) when is_function(default) do
|
||||
configured_default(resource, name) ||
|
||||
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
|
||||
defp default(%{name: name, default: default}, resource, _repo) when is_function(default) do
|
||||
configured_default(resource, name) || "nil"
|
||||
end
|
||||
|
||||
defp default(%{name: name, default: {_, _, _}}, resource, _),
|
||||
|
@ -2770,8 +2401,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Map.update!(:custom_indexes, &load_custom_indexes/1)
|
||||
|> Map.put_new(:custom_statements, [])
|
||||
|> 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.put_new(:multitenancy, %{
|
||||
attribute: nil,
|
||||
|
@ -2782,16 +2411,6 @@ defmodule AshSqlite.MigrationGenerator do
|
|||
|> Map.put_new(:base_filter, nil)
|
||||
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
|
||||
Enum.map(custom_indexes || [], fn custom_index ->
|
||||
custom_index
|
||||
|
|
|
@ -72,7 +72,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
|
||||
defmodule AddAttribute do
|
||||
@moduledoc false
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy]
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy]
|
||||
|
||||
import Helper
|
||||
|
||||
|
@ -273,7 +273,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
multitenancy: multitenancy,
|
||||
old_attribute: old_attribute,
|
||||
new_attribute: attribute
|
||||
}) do
|
||||
}) do
|
||||
type_or_reference =
|
||||
if AshSqlite.MigrationGenerator.has_reference?(multitenancy, attribute) and
|
||||
Map.get(old_attribute, :references) != Map.get(attribute, :references) do
|
||||
|
@ -295,7 +295,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
destination_attribute: reference_attribute
|
||||
} = reference
|
||||
} = attribute
|
||||
) do
|
||||
) do
|
||||
with_match =
|
||||
if destination_attribute != reference_attribute do
|
||||
"with: [#{as_atom(source_attribute)}: :#{as_atom(destination_attribute)}], match: :full"
|
||||
|
@ -327,7 +327,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
destination_attribute: destination_attribute
|
||||
} = reference
|
||||
} = attribute
|
||||
) do
|
||||
) do
|
||||
size =
|
||||
if attribute[:size] do
|
||||
"size: #{attribute[:size]}"
|
||||
|
@ -360,7 +360,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
# We only run this migration in one direction, based on the input
|
||||
# This is because the creation of a foreign key is handled by `references/3`
|
||||
# We only need to drop it before altering an attribute with `references/3`
|
||||
defstruct [:attribute, :table, :multitenancy, :direction, no_phase: true]
|
||||
defstruct [:attribute, :table, :multitenancy, :direction, no_phase: true]
|
||||
|
||||
import Helper
|
||||
|
||||
|
@ -420,7 +420,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
|
||||
defmodule RemoveAttribute do
|
||||
@moduledoc false
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy, commented?: true]
|
||||
defstruct [:attribute, :table, :multitenancy, :old_multitenancy, commented?: true]
|
||||
|
||||
def up(%{attribute: attribute, commented?: true}) do
|
||||
"""
|
||||
|
@ -587,7 +587,6 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
join([
|
||||
option(:name, index.name),
|
||||
option(:unique, index.unique),
|
||||
option(:concurrently, index.concurrently),
|
||||
option(:using, index.using),
|
||||
option(:where, index.where),
|
||||
option(:include, index.include)
|
||||
|
@ -619,7 +618,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
@moduledoc false
|
||||
defstruct [:table, no_phase: true]
|
||||
|
||||
def up(%{ table: table}) do
|
||||
def up(%{table: table}) do
|
||||
"drop constraint(#{inspect(table)}, \"#{table}_pkey\")"
|
||||
end
|
||||
|
||||
|
@ -637,7 +636,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
end
|
||||
|
||||
def down(%{table: table}) do
|
||||
"drop constraint(#{inspect(table)}, \"#{table}_pkey\")"
|
||||
"drop constraint(#{inspect(table)}, \"#{table}_pkey\")"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -687,7 +686,6 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
join([
|
||||
option(:name, index.name),
|
||||
option(:unique, index.unique),
|
||||
option(:concurrently, index.concurrently),
|
||||
option(:using, index.using),
|
||||
option(:where, index.where),
|
||||
option(:include, index.include)
|
||||
|
@ -783,59 +781,4 @@ defmodule AshSqlite.MigrationGenerator.Operation do
|
|||
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
|
||||
|
|
|
@ -8,17 +8,17 @@ defmodule AshSqlite.MigrationGenerator.Phase do
|
|||
import AshSqlite.MigrationGenerator.Operation.Helper, only: [as_atom: 1]
|
||||
|
||||
def up(%{table: table, operations: operations}) do
|
||||
opts = ""
|
||||
opts = ""
|
||||
|
||||
"create table(:#{as_atom(table)}, primary_key: false#{opts}) do\n" <>
|
||||
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <>
|
||||
"\nend"
|
||||
"create table(:#{as_atom(table)}, primary_key: false#{opts}) do\n" <>
|
||||
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <>
|
||||
"\nend"
|
||||
end
|
||||
|
||||
def down(%{ table: table}) do
|
||||
opts = ""
|
||||
def down(%{table: table}) do
|
||||
opts = ""
|
||||
|
||||
"drop table(:#{as_atom(table)}#{opts})"
|
||||
"drop table(:#{as_atom(table)}#{opts})"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,11 +37,11 @@ defmodule AshSqlite.MigrationGenerator.Phase do
|
|||
if body == "" do
|
||||
""
|
||||
else
|
||||
opts = ""
|
||||
opts = ""
|
||||
|
||||
"alter table(:#{as_atom(table)}#{opts}) do\n" <>
|
||||
body <>
|
||||
"\nend"
|
||||
"alter table(:#{as_atom(table)}#{opts}) do\n" <>
|
||||
body <>
|
||||
"\nend"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -123,7 +123,6 @@ defmodule AshSqlite.MixHelpers do
|
|||
opts[:migrations_path] || repo.config()[:migrations_path] || derive_migrations_path(repo)
|
||||
end
|
||||
|
||||
|
||||
def derive_migrations_path(repo) do
|
||||
config = repo.config()
|
||||
priv = config[:priv] || "priv/#{repo |> Module.split() |> List.last() |> Macro.underscore()}"
|
||||
|
|
|
@ -90,6 +90,6 @@ defmodule Mix.Tasks.AshSqlite.GenerateMigrations do
|
|||
|> Keyword.put(:format, !opts[:no_format])
|
||||
|> Keyword.delete(:no_format)
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(apis, opts)
|
||||
AshSqlite.MigrationGenerator.generate(apis, opts)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -102,13 +102,13 @@ defmodule Mix.Tasks.AshSqlite.Migrate do
|
|||
|> AshSqlite.MixHelpers.delete_arg("--apis")
|
||||
|> AshSqlite.MixHelpers.delete_arg("--migrations-path")
|
||||
|
||||
for repo <- repos do
|
||||
Mix.Task.run(
|
||||
"ecto.migrate",
|
||||
repo_args ++ rest_opts ++ ["--migrations-path", migrations_path(opts, repo)]
|
||||
)
|
||||
for repo <- repos do
|
||||
Mix.Task.run(
|
||||
"ecto.migrate",
|
||||
repo_args ++ rest_opts ++ ["--migrations-path", migrations_path(opts, repo)]
|
||||
)
|
||||
|
||||
Mix.Task.reenable("ecto.migrate")
|
||||
end
|
||||
Mix.Task.reenable("ecto.migrate")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -67,13 +67,13 @@ defmodule Mix.Tasks.AshSqlite.Rollback do
|
|||
|> AshSqlite.MixHelpers.delete_arg("--apis")
|
||||
|> AshSqlite.MixHelpers.delete_arg("--migrations-path")
|
||||
|
||||
for repo <- repos do
|
||||
Mix.Task.run(
|
||||
"ecto.rollback",
|
||||
repo_args ++ rest_opts ++ ["--migrations-path", migrations_path(opts, repo)]
|
||||
)
|
||||
for repo <- repos do
|
||||
Mix.Task.run(
|
||||
"ecto.rollback",
|
||||
repo_args ++ rest_opts ++ ["--migrations-path", migrations_path(opts, repo)]
|
||||
)
|
||||
|
||||
Mix.Task.reenable("ecto.rollback")
|
||||
end
|
||||
Mix.Task.reenable("ecto.rollback")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,7 +50,6 @@ defmodule AshSqlite.Repo do
|
|||
|
||||
def installed_extensions, do: []
|
||||
def migrations_path, do: nil
|
||||
def default_prefix, do: "public"
|
||||
def override_migration_type(type), do: type
|
||||
def min_pg_version, do: 10
|
||||
|
||||
|
@ -59,7 +58,6 @@ defmodule AshSqlite.Repo do
|
|||
config
|
||||
|> Keyword.put(:installed_extensions, installed_extensions())
|
||||
|> Keyword.put(:migrations_path, migrations_path())
|
||||
|> Keyword.put(:default_prefix, default_prefix())
|
||||
|
||||
{:ok, new_config}
|
||||
end
|
||||
|
@ -164,7 +162,6 @@ defmodule AshSqlite.Repo do
|
|||
defoverridable init: 2,
|
||||
on_transaction_begin: 1,
|
||||
installed_extensions: 0,
|
||||
default_prefix: 0,
|
||||
override_migration_type: 1,
|
||||
min_pg_version: 0
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ defmodule AshSqlite.Transformers.VerifyRepo do
|
|||
match?({:error, _}, Code.ensure_compiled(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`"}
|
||||
|
||||
true ->
|
||||
|
|
7
mix.exs
7
mix.exs
|
@ -43,7 +43,10 @@ defmodule AshSqlite.MixProject do
|
|||
|
||||
if Mix.env() == :test 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
|
||||
|
||||
|
@ -145,7 +148,6 @@ defmodule AshSqlite.MixProject do
|
|||
],
|
||||
Introspection: [
|
||||
AshSqlite.DataLayer.Info,
|
||||
AshSqlite.CheckConstraint,
|
||||
AshSqlite.CustomExtension,
|
||||
AshSqlite.CustomIndex,
|
||||
AshSqlite.Reference,
|
||||
|
@ -173,7 +175,6 @@ defmodule AshSqlite.MixProject do
|
|||
{:ecto_sqlite3, "~> 0.11"},
|
||||
{:ecto, "~> 3.9"},
|
||||
{:jason, "~> 1.0"},
|
||||
{:postgrex, ">= 0.0.0"},
|
||||
{:ash, ash_version("~> 2.14 and >= 2.14.18")},
|
||||
{:git_ops, "~> 2.5", only: [:dev, :test]},
|
||||
{: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"},
|
||||
"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"},
|
||||
"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"},
|
||||
"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"},
|
||||
|
|
|
@ -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
|
|
@ -93,7 +93,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -151,50 +151,6 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
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
|
||||
setup do
|
||||
on_exit(fn ->
|
||||
|
@ -217,7 +173,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -245,7 +201,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -274,7 +230,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -300,7 +256,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
send(self(), {:mix_shell_input, :yes?, true})
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -325,7 +281,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
send(self(), {:mix_shell_input, :yes?, false})
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -353,7 +309,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
send(self(), {:mix_shell_input, :yes?, true})
|
||||
send(self(), {:mix_shell_input, :prompt, "subject"})
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -383,7 +339,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
send(self(), {:mix_shell_input, :yes?, false})
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -414,7 +370,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Post2])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -449,7 +405,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -528,7 +484,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Post2])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -563,7 +519,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Post2])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -598,7 +554,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Post2])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -650,133 +606,6 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
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
|
||||
setup do
|
||||
on_exit(fn ->
|
||||
|
@ -835,7 +664,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Comment])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -880,7 +709,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -989,7 +818,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
Mix.shell(Mix.Shell.Process)
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
@ -1028,7 +857,7 @@ defmodule AshSqlite.MigrationGeneratorTest do
|
|||
|
||||
defapi([Post, Comment])
|
||||
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
AshSqlite.MigrationGenerator.generate(Api,
|
||||
snapshot_path: "test_snapshots_path",
|
||||
migration_path: "test_migration_path",
|
||||
quiet: true,
|
||||
|
|
|
@ -18,17 +18,9 @@ defmodule AshSqlite.Test.Post do
|
|||
repo(AshSqlite.TestRepo)
|
||||
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
|
||||
index([:uniq_custom_one, :uniq_custom_two],
|
||||
unique: true,
|
||||
concurrently: true,
|
||||
message: "dude what the heck"
|
||||
)
|
||||
end
|
||||
|
@ -46,7 +38,7 @@ defmodule AshSqlite.Test.Post do
|
|||
end
|
||||
|
||||
read :paginated do
|
||||
pagination(offset?: true, required?: true, countable: true)
|
||||
pagination(offset?: true, required?: true)
|
||||
end
|
||||
|
||||
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
|
||||
send(self(), data)
|
||||
end
|
||||
|
||||
def installed_extensions do
|
||||
["ash-functions", AshSqlite.TestCustomExtension]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,4 +2,5 @@ ExUnit.start()
|
|||
ExUnit.configure(stacktrace_depth: 100)
|
||||
|
||||
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