Packages

Declarative Ecto embedded schemas for data validation, coercion, and manipulation.

Current section

12 Versions

Jump to

Compare versions

7 files changed
+57 additions
-140 deletions
  @@ -31,7 +31,7 @@ Declarative [`Ecto`](https://github.com/elixir-ecto/ecto) `embedded_schema`s for
31 31 ```elixir
32 32 def deps do
33 33 [
34 - {:flint, "~> 0.4"}
34 + {:flint, "~> 0.5"}
35 35 ]
36 36 end
37 37 ```
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/acalejos/flint">>}]}.
2 2 {<<"name">>,<<"flint">>}.
3 - {<<"version">>,<<"0.4.3">>}.
3 + {<<"version">>,<<"0.5.0">>}.
4 4 {<<"description">>,
5 5 <<"Declarative Ecto embedded schemas for data validation, coercion, and manipulation.">>}.
6 6 {<<"elixir">>,<<"~> 1.14">>}.
  @@ -32,8 +32,7 @@
32 32 <<"lib/flint.ex">>,<<"lib/flint">>,<<"lib/flint/types">>,
33 33 <<"lib/flint/types/union.ex">>,<<"lib/flint/extension">>,
34 34 <<"lib/flint/extension/field.ex">>,<<"lib/flint/extension/dsl.ex">>,
35 - <<"lib/flint/extension/entity.ex">>,<<"lib/flint/extensions">>,
36 - <<"lib/flint/extensions/pre_transforms.ex">>,
35 + <<"lib/flint/extensions">>,<<"lib/flint/extensions/pre_transforms.ex">>,
37 36 <<"lib/flint/extensions/post_transforms.ex">>,
38 37 <<"lib/flint/extensions/ecto_validations.ex">>,
39 38 <<"lib/flint/extensions/when.ex">>,<<"lib/flint/extensions/json.ex">>,
  @@ -99,14 +99,17 @@ defmodule Flint.Extension do
99 99 ]
100 100 ```
101 101
102 - ## Default `field` and `field!` definitions
102 + ## Default `embedded_schema` definitions
103 103
104 104 Sometimes you might want to always have one of more fields defined for a given schema type without having
105 105 to write it each time. Much in the same way that, by default, the `@prmimary_key` attribute will set an `:id` field
106 106 for the schema, you might wish to template out some fields and values.
107 107
108 - If you want to define fields that are defined by default in a schema that uses your extension, just use the
109 - `field` and `field!` macros. These accept the same arguments as their counterparts in `Flint.Schema`, and will be
108 + If you want to define fields that are defined by default in a schema that uses your extension, you can use the
109 + `embedded_schema` macro within an extension and all `field`, `embeds_one` and `embeds_many` declarations will be
110 + merged into the target schema that uses your extension.
111 +
112 + These accept the same arguments as their counterparts in `Flint.Schema`, and will be
110 113 added at the end of the `embedded_schema` definition.
111 114
112 115 > #### Duplicate Fields {: .info}
  @@ -122,8 +125,10 @@ defmodule Flint.Extension do
122 125 defmodule Event do
123 126 use Flint.Extension
124 127
125 - field! :timestamp, :utc_datetime_usec
126 - field! :id, :binary_id
128 + embedded_schema do
129 + field! :timestamp, :utc_datetime_usec
130 + field! :id, :binary_id
131 + end
127 132 end
128 133 ```
129 134
  @@ -172,34 +177,19 @@ defmodule Flint.Extension do
172 177 many_extension_kinds: [:extensions],
173 178 default_extensions: [extensions: Flint.Extension.Dsl]
174 179
175 - @doc """
176 - Registers a default field to be added to any `embedded_schema` using this extension
177 - """
178 - defmacro field(name, type \\ :string, opts \\ []) do
179 - quote do
180 - entity do
181 - name(unquote(name))
182 - type(unquote(type))
183 - opts(unquote(opts))
184 - end
185 - end
180 + @doc false
181 + defmacro embedded_schema(do: {:__block__, _, contents}) do
182 + Module.put_attribute(__CALLER__.module, :embedded_schema, contents)
186 183 end
187 184
188 - @doc """
189 - Same as `field` but marks the field as required
190 - """
191 - defmacro field!(name, type \\ :string, opts \\ []) do
192 - quote do
193 - entity do
194 - name(unquote(name))
195 - type(unquote(type))
196 - opts(unquote(opts))
197 - required(true)
198 - end
199 - end
185 + @doc false
186 + defmacro embedded_schema(do: block) do
187 + Module.put_attribute(__CALLER__.module, :embedded_schema, [block])
200 188 end
201 189
202 190 defmacro __using__(opts) do
191 + Module.put_attribute(__CALLER__.module, :embedded_schema, [])
192 +
203 193 quote do
204 194 import Flint.Extension
205 195 unquote_splicing(super(opts))
  @@ -211,6 +201,10 @@ defmodule Flint.Extension do
211 201
212 202 defoverridable __using__: 1
213 203
204 + def template_schema() do
205 + @embedded_schema
206 + end
207 +
214 208 @doc false
215 209 def option_names(),
216 210 do: Spark.Dsl.Extension.get_entities(__MODULE__, :options) |> Enum.map(& &1.name)
  @@ -218,9 +212,6 @@ defmodule Flint.Extension do
218 212 @doc false
219 213 def attribute_names(),
220 214 do: Spark.Dsl.Extension.get_entities(__MODULE__, :attributes) |> Enum.map(& &1.name)
221 -
222 - def field_names(),
223 - do: Spark.Dsl.Extension.get_entities(__MODULE__, :fields) |> Enum.map(& &1.name)
224 215 end
225 216 end
226 217 end
  @@ -41,43 +41,12 @@ defmodule Flint.Extension.Dsl do
41 41 args: [:name],
42 42 schema: @common_schema
43 43 }
44 - @field %Spark.Dsl.Entity{
45 - name: :entity,
46 - target: Flint.Extension.Entity,
47 - schema: [
48 - name: [
49 - type: :atom,
50 - required: true,
51 - doc: "The name as an atom."
52 - ],
53 - type: [
54 - required: false,
55 - default: :string,
56 - # Let the call to `field` inside the schema handle validating
57 - type: :any
58 - ],
59 - opts: [
60 - type: :keyword_list,
61 - default: [],
62 - required: false
63 - ],
64 - required: [
65 - type: :boolean,
66 - default: false,
67 - doc:
68 - "Whether the field is required. If it is required and not provided there will be a compile time error thrown."
69 - ]
70 - ]
71 - }
44 +
72 45 @attributes %Spark.Dsl.Section{
73 46 name: :attributes,
74 47 entities: [@attribute],
75 48 top_level?: true
76 49 }
77 - @fields %Spark.Dsl.Section{
78 - name: :fields,
79 - entities: [@field],
80 - top_level?: true
81 - }
82 - use Spark.Dsl.Extension, sections: [@attributes, @options, @fields]
50 +
51 + use Spark.Dsl.Extension, sections: [@attributes, @options]
83 52 end
  @@ -1,9 +0,0 @@
1 - defmodule Flint.Extension.Entity do
2 - @moduledoc false
3 - defstruct [
4 - :name,
5 - type: :string,
6 - required: false,
7 - opts: []
8 - ]
9 - end
Loading more files…