@@ -5,74 +5,6 @@ defmodule Drops.Relation.Plugins.Schema do
55 This plugin adds the `schema/1` and `schema/2` macros for defining relation schemas.
66 It supports both automatic schema inference from database tables and manual schema
77 definition with Ecto.Schema syntax.
8-
9- ## Examples
10-
11- ### Automatic Schema Inference
12- defmodule MyApp.Users do
13- use Drops.Relation, otp_app: :my_app
14-
15- schema("users", infer: true)
16- end
17-
18- iex> schema = MyApp.Users.schema()
19- iex> schema.source
20- :users
21- iex> %{name: name, type: type, meta: %{default: default}} = MyApp.Users.schema(:email)
22- iex> name
23- :email
24- iex> type
25- :string
26- iex> default
27- nil
28-
29- ### Manual Schema Definition
30-
31- You can also define schemas manually using familiar Ecto.Schema syntax:
32-
33- schema("users") do
34- field(:name, :string)
35- field(:email, :string)
36- field(:active, :boolean, default: true)
37-
38- timestamps()
39- end
40-
41- This gives you full control over field definitions, types, and options.
42-
43- ## Hybrid Approach
44-
45- Combine automatic inference with manual customizations:
46-
47- defmodule MyApp.Users do
48- use Drops.Relation, repo: MyApp.Repo
49-
50- schema("users", infer: true) do
51- field(:full_name, :string, virtual: true)
52-
53- has_many(:posts, MyApp.Posts)
54- end
55- end
56-
57- ### Schema Access and Struct Generation
58-
59- iex> schema_module = MyApp.Users.__schema_module__()
60- iex> is_atom(schema_module)
61- true
62-
63- iex> user = MyApp.Users.struct(%{name: "John", email: "[email protected] "}) 64- iex> user.__struct__
65- MyApp.Users.User
66- iex> user.name
67- "John"
68- iex> user.email
69- 70-
71- ## Options
72-
73- - `infer: true` - Automatically infer schema from database (default)
74- - `struct: "CustomName"` - Use custom struct module name
75- - Standard Ecto.Schema options are supported in manual definitions
768 """
779
7810 alias Drops.Relation.Schema
@@ -87,7 +19,7 @@ defmodule Drops.Relation.Plugins.Schema do
8719
8820 use Drops.Relation.Plugin.MacroStruct ,
8921 key: :schema ,
90- struct: [ :name , block: nil , fields: nil , opts: [ ] , infer: true ]
22+ struct: [ :name , block: nil , fields: nil , opts: [ ] , infer: false ]
9123
9224 def new ( name ) when is_binary ( name ) do
9325 % Macros.Schema { name: name }
@@ -99,7 +31,7 @@ defmodule Drops.Relation.Plugins.Schema do
9931
10032 def new ( name , opts ) when is_binary ( name ) and is_list ( opts ) do
10133 opts = Keyword . delete ( opts , :do )
102- infer = Keyword . get ( opts , :infer , true )
34+ infer = Keyword . get ( opts , :infer , false )
10335
10436 % { new ( name ) | opts: opts , infer: infer }
10537 end
@@ -109,7 +41,80 @@ defmodule Drops.Relation.Plugins.Schema do
10941 end
11042 end
11143
112- defmacro schema ( fields , opts \\ [ ] )
44+ @ doc """
45+ Defines a schema for the relation.
46+
47+ By default, this creates an empty schema that you must populate with manual field
48+ definitions. Use `infer: true` option to automatically introspect the database table.
49+
50+ ## Parameters
51+
52+ - `table_name` - String name of the database table
53+ - `opts` - Keyword list of options (optional)
54+
55+ ## Options
56+
57+ - `infer: false` - Use only manual field definitions (default: false)
58+ - `infer: true` - Automatically infer schema from database table
59+ - `struct: "CustomName"` - Use custom struct module name instead of default
60+
61+ ## Returns
62+
63+ Sets up the relation to generate:
64+ - A `schema/0` function that returns the complete schema metadata
65+ - A `schema/1` function that returns a specific field by name
66+
67+ ## Examples
68+
69+ Manual schema definition:
70+
71+ iex> defmodule Relations.Users do
72+ ...> use Drops.Relation, repo: MyApp.Repo
73+ ...>
74+ ...> schema("users") do
75+ ...> field(:name, :string)
76+ ...> field(:email, :string)
77+ ...> end
78+ ...> end
79+ ...>
80+ iex> user = Relations.Users.struct(%{name: "Alice Johnson", email: "[email protected] "}) 81+ iex> user.__struct__
82+ Relations.Users.User
83+ iex> user.name
84+ "Alice Johnson"
85+ iex> user.email
86+ 87+
88+ With automatic inference:
89+
90+ iex> defmodule Relations.Users do
91+ ...> use Drops.Relation, repo: MyApp.Repo
92+ ...>
93+ ...> schema("users", infer: true)
94+ ...> end
95+ iex> schema = Relations.Users.schema()
96+ iex> schema.source
97+ :users
98+ iex> length(schema.fields) > 0
99+ true
100+
101+ With custom struct name:
102+
103+ iex> defmodule Relations.People do
104+ ...> use Drops.Relation, repo: MyApp.Repo
105+ ...>
106+ ...> schema("users", struct: "Person", infer: true)
107+ ...> end
108+ ...>
109+ iex> user = Relations.People.struct(%{name: "Alice Johnson", email: "[email protected] "}) 110+ iex> user.__struct__
111+ Relations.People.Person
112+ iex> user.name
113+ "Alice Johnson"
114+ iex> user.email
115+ 116+ """
117+ defmacro schema ( name , opts \\ [ ] )
113118
114119 defmacro schema ( name , opts ) when is_binary ( name ) do
115120 block = opts [ :do ]
@@ -129,6 +134,47 @@ defmodule Drops.Relation.Plugins.Schema do
129134 end
130135 end
131136
137+ @ doc """
138+ Defines a schema with manual field definitions or combines inference with custom fields.
139+
140+ This form allows you to either define a completely manual schema using Ecto.Schema
141+ syntax, or combine automatic inference with additional custom fields and associations.
142+
143+ ## Parameters
144+
145+ - `table_name` - String name of the database table
146+ - `opts` - Keyword list of options
147+ - `block` - Schema definition block using Ecto.Schema syntax
148+
149+ ## Options
150+
151+ - `infer: false` - Use only the manual field definitions in the block (default: false)
152+ - `infer: true` - Automatically infer schema from database and merge with block
153+ - `struct: "CustomName"` - Use custom struct module name
154+
155+ ## Returns
156+
157+ Sets up the relation with either a purely manual schema or a merged schema
158+ combining inference with custom definitions.
159+
160+ ## Examples
161+
162+ iex> defmodule Relations.Users do
163+ ...> use Drops.Relation, repo: MyApp.Repo
164+ ...>
165+ ...> schema("users", infer: true) do
166+ ...> field(:role, :string, default: "member")
167+ ...> field(:full_name, :string, virtual: true)
168+ ...> end
169+ ...> end
170+ ...>
171+ iex> schema = Relations.Users.schema()
172+ iex> %{name: name, meta: %{default: default}} = schema[:role]
173+ iex> name
174+ :role
175+ iex> default
176+ "member"
177+ """
132178 defmacro schema ( name , opts , block ) when is_binary ( name ) do
133179 block = block [ :do ]
134180
@@ -153,6 +199,7 @@ defmodule Drops.Relation.Plugins.Schema do
153199 end
154200 end
155201
202+ @ doc false
156203 def put_schema ( relation , opts ) do
157204 schema =
158205 case context ( relation , :schema ) do
@@ -174,6 +221,15 @@ defmodule Drops.Relation.Plugins.Schema do
174221 else
175222 source_schema
176223 end
224+
225+ % { name: name , infer: false , block: block } when not is_nil ( block ) ->
226+ Generator . schema_from_block ( name , block )
227+
228+ % { name: name , infer: false , block: nil } ->
229+ Schema . new ( % { source: String . to_atom ( name ) } )
230+
231+ % { name: name , block: nil } ->
232+ Schema . new ( % { source: String . to_atom ( name ) } )
177233 end
178234
179235 Module . put_attribute ( relation , :schema , schema )
0 commit comments