Skip to content

Commit f256da6

Browse files
authored
improvement: strict table support (#157)
Add option in the DSL to generate [strict table](https://www.sqlite.org/stricttables.html), which enforces types more strictly (default is false). Ecto already supports custom options that will be appended after the generated create table statement https://hexdocs.pm/ecto_sql/Ecto.Migration.html#table/2-options
1 parent 39f507b commit f256da6

7 files changed

Lines changed: 76 additions & 7 deletions

File tree

documentation/dsls/DSL-AshSqlite.DataLayer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ end
4848
| [`migration_ignore_attributes`](#sqlite-migration_ignore_attributes){: #sqlite-migration_ignore_attributes } | `list(atom)` | `[]` | A list of attributes that will be ignored when generating migrations. |
4949
| [`table`](#sqlite-table){: #sqlite-table } | `String.t` | | The table to store and read the resource from. If this is changed, the migration generator will not remove the old table. |
5050
| [`polymorphic?`](#sqlite-polymorphic?){: #sqlite-polymorphic? } | `boolean` | `false` | Declares this resource as polymorphic. See the [polymorphic resources guide](/documentation/topics/resources/polymorphic-resources.md) for more. |
51+
| [`strict?`](#sqlite-strict?){: #sqlite-strict? } | `boolean` | `false` | Whether the migration generator should create a [strict table](https://www.sqlite.org/stricttables.html), which enforces types more strictly. |
5152

5253

5354
### sqlite.custom_indexes

lib/data_layer.ex

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,13 @@ defmodule AshSqlite.DataLayer do
278278
doc: """
279279
Declares this resource as polymorphic. See the [polymorphic resources guide](/documentation/topics/resources/polymorphic-resources.md) for more.
280280
"""
281+
],
282+
strict?: [
283+
type: :boolean,
284+
default: false,
285+
doc: """
286+
Whether the migration generator should create a [strict table](https://www.sqlite.org/stricttables.html), which enforces types more strictly.
287+
"""
281288
]
282289
]
283290
}

lib/data_layer/info.ex

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,9 @@ defmodule AshSqlite.DataLayer.Info do
114114
def skip_unique_indexes(resource) do
115115
Extension.get_opt(resource, [:sqlite], :skip_unique_indexes, [])
116116
end
117+
118+
@doc "Whether the migration generator should create a strict table"
119+
def strict?(resource) do
120+
Extension.get_opt(resource, [:sqlite], :strict?, false)
121+
end
117122
end

lib/migration_generator/migration_generator.ex

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,8 @@ defmodule AshSqlite.MigrationGenerator do
11031103

11041104
defp group_into_phases(
11051105
[
1106-
%Operation.CreateTable{table: table, multitenancy: multitenancy} | rest
1106+
%Operation.CreateTable{table: table, options: options, multitenancy: multitenancy}
1107+
| rest
11071108
],
11081109
nil,
11091110
acc
@@ -1120,6 +1121,7 @@ defmodule AshSqlite.MigrationGenerator do
11201121
%Phase.Create{
11211122
table: table,
11221123
multitenancy: multitenancy,
1124+
options: options,
11231125
operations: has_to_be_in_this_phase
11241126
},
11251127
acc
@@ -1543,7 +1545,8 @@ defmodule AshSqlite.MigrationGenerator do
15431545
%Operation.CreateTable{
15441546
table: snapshot.table,
15451547
multitenancy: snapshot.multitenancy,
1546-
old_multitenancy: empty_snapshot.multitenancy
1548+
old_multitenancy: empty_snapshot.multitenancy,
1549+
options: [strict?: snapshot.strict?]
15471550
}
15481551
| acc
15491552
])
@@ -2204,7 +2207,8 @@ defmodule AshSqlite.MigrationGenerator do
22042207
repo: AshSqlite.DataLayer.Info.repo(resource),
22052208
multitenancy: multitenancy(resource),
22062209
base_filter: AshSqlite.DataLayer.Info.base_filter_sql(resource),
2207-
has_create_action: has_create_action?(resource)
2210+
has_create_action: has_create_action?(resource),
2211+
strict?: AshSqlite.DataLayer.Info.strict?(resource)
22082212
}
22092213

22102214
hash =

lib/migration_generator/operation.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ defmodule AshSqlite.MigrationGenerator.Operation do
6767

6868
defmodule CreateTable do
6969
@moduledoc false
70-
defstruct [:table, :multitenancy, :old_multitenancy]
70+
defstruct [:table, :multitenancy, :old_multitenancy, options: []]
7171
end
7272

7373
defmodule AddAttribute do

lib/migration_generator/phase.ex

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,17 @@ defmodule AshSqlite.MigrationGenerator.Phase do
33

44
defmodule Create do
55
@moduledoc false
6-
defstruct [:table, :multitenancy, operations: [], commented?: false]
6+
defstruct [:table, :multitenancy, operations: [], options: [], commented?: false]
77

88
import AshSqlite.MigrationGenerator.Operation.Helper, only: [as_atom: 1]
99

10-
def up(%{table: table, operations: operations}) do
11-
opts = ""
10+
def up(%{table: table, operations: operations, options: options}) do
11+
opts =
12+
if options[:strict?] do
13+
~s', options: "STRICT"'
14+
else
15+
""
16+
end
1217

1318
"create table(:#{as_atom(table)}, primary_key: false#{opts}) do\n" <>
1419
Enum.map_join(operations, "\n", fn operation -> operation.__struct__.up(operation) end) <>

test/migration_generator_test.exs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,53 @@ defmodule AshSqlite.MigrationGeneratorTest do
145145
end
146146
end
147147

148+
describe "strict table" do
149+
setup do
150+
on_exit(fn ->
151+
File.rm_rf!("test_snapshots_path")
152+
File.rm_rf!("test_migration_path")
153+
end)
154+
155+
defposts do
156+
sqlite do
157+
strict?(true)
158+
end
159+
160+
attributes do
161+
uuid_primary_key(:id)
162+
attribute(:title, :string)
163+
end
164+
end
165+
166+
defdomain([Post])
167+
168+
Mix.shell(Mix.Shell.Process)
169+
170+
AshSqlite.MigrationGenerator.generate(Domain,
171+
snapshot_path: "test_snapshots_path",
172+
migration_path: "test_migration_path",
173+
quiet: true,
174+
format: false,
175+
auto_name: true
176+
)
177+
178+
:ok
179+
end
180+
181+
test "creates the table with the strict option" do
182+
# the snapshot exists and contains valid json
183+
assert File.read!(Path.wildcard("test_snapshots_path/test_repo/posts/*.json"))
184+
|> Jason.decode!(keys: :atoms!)
185+
186+
assert [file] = Path.wildcard("test_migration_path/**/*_migrate_resources*.exs")
187+
188+
file_contents = File.read!(file)
189+
190+
# the migration creates the table
191+
assert file_contents =~ ~s'create table(:posts, primary_key: false, options: "STRICT") do'
192+
end
193+
end
194+
148195
describe "creating follow up migrations" do
149196
setup do
150197
on_exit(fn ->

0 commit comments

Comments
 (0)