Skip to content

Commit 54e9b50

Browse files
committed
[schema] Adding Schema module
1 parent c2e8bc3 commit 54e9b50

File tree

1 file changed

+193
-0
lines changed

1 file changed

+193
-0
lines changed

lib/instream/schema.ex

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
defmodule StatusApi.InfluxDB.Schema do
2+
@moduledoc """
3+
Defines a schema (series struct).
4+
5+
## Usage
6+
7+
defmodule MySchema
8+
use StatusApi.InfluxDB.Schema
9+
10+
schema do
11+
database "my_database_optional"
12+
measurement "cpu_load"
13+
14+
tag :host, default: "www"
15+
tag :core
16+
17+
field :value, default: 100
18+
field :value_desc
19+
end
20+
end
21+
22+
## Metadata
23+
24+
The metadata of a schema (i.e. the measurement) can
25+
be retrieved using the `__meta__/1` method.
26+
27+
## Struct
28+
29+
Every schema will be registered as a struct.
30+
Following the above usage example you will get the following struct:
31+
32+
%MySchema{
33+
value: 100,
34+
value_desc: nil,
35+
host: "www",
36+
core: nil,
37+
timestamp: nil
38+
}
39+
40+
`:timestamp` is expected to be a unix nanosecond timestamp.
41+
"""
42+
43+
defmacro __using__(_opts) do
44+
quote do
45+
@after_compile unquote(__MODULE__)
46+
47+
import unquote(__MODULE__), only: [ schema: 1 ]
48+
end
49+
end
50+
51+
defmacro __after_compile__(%{ module: module }, _bytecode) do
52+
quote do
53+
Instream.Schema.Validator.proper_schema?(unquote(module))
54+
end
55+
end
56+
57+
58+
@doc """
59+
Defines the schema.
60+
"""
61+
defmacro schema(do: block) do
62+
quote do
63+
@behaviour unquote(__MODULE__)
64+
65+
@database nil
66+
@measurement nil
67+
68+
Module.register_attribute(__MODULE__, :fields_raw, accumulate: true)
69+
Module.register_attribute(__MODULE__, :tags_raw, accumulate: true)
70+
71+
try do
72+
# scoped import
73+
import unquote(__MODULE__)
74+
unquote(block)
75+
after
76+
:ok
77+
end
78+
79+
@fields_names @fields_raw |> Keyword.keys() |> Enum.sort()
80+
@fields_struct @fields_raw |> Enum.sort( &unquote(__MODULE__).__sort_fields__/2 )
81+
82+
@tags_names @tags_raw |> Keyword.keys() |> Enum.sort()
83+
@tags_struct @tags_raw |> Enum.sort( &unquote(__MODULE__).__sort_fields__/2 )
84+
85+
def __meta__(:database), do: @database
86+
def __meta__(:measurement), do: @measurement
87+
def __meta__(:fields), do: @fields_names
88+
def __meta__(:tags), do: @tags_names
89+
90+
Module.eval_quoted __ENV__, [
91+
unquote(__MODULE__).__struct_fields__(@fields_struct),
92+
unquote(__MODULE__).__struct_tags__(@tags_struct),
93+
unquote(__MODULE__).__struct__(@fields_struct ++ @tags_struct),
94+
]
95+
end
96+
end
97+
98+
99+
@doc """
100+
Provides metadata access for a schema.
101+
102+
## Available information
103+
104+
- `:database` - the database where the schema is stored (optional)
105+
- `:fields` - the fields in the schema
106+
- `:measurement` - the measurement of the schema
107+
- `:tags` - the available tags defining the schema
108+
"""
109+
@callback __meta__(atom) :: any
110+
111+
@doc """
112+
Defines the database for the schema.
113+
"""
114+
defmacro database(name) do
115+
quote do
116+
unquote(__MODULE__).__attribute__(__MODULE__, :database, unquote(name))
117+
end
118+
end
119+
120+
@doc """
121+
Defines a field in the schema.
122+
"""
123+
defmacro field(name, opts \\ []) do
124+
quote do
125+
unquote(__MODULE__).__attribute__(
126+
__MODULE__, :fields_raw,
127+
{ unquote(name), unquote(opts[:default]) }
128+
)
129+
end
130+
end
131+
132+
@doc """
133+
Defines the measurement of the schema.
134+
"""
135+
defmacro measurement(name) do
136+
quote do
137+
unquote(__MODULE__).__attribute__(__MODULE__, :measurement, unquote(name))
138+
end
139+
end
140+
141+
@doc """
142+
Defines a tag in the schema.
143+
"""
144+
defmacro tag(name, opts \\ []) do
145+
quote do
146+
unquote(__MODULE__).__attribute__(
147+
__MODULE__, :tags_raw,
148+
{ unquote(name), unquote(opts[:default]) }
149+
)
150+
end
151+
end
152+
153+
154+
@doc false
155+
def __attribute__(mod, name, value) do
156+
Module.put_attribute(mod, name, value)
157+
end
158+
159+
160+
@doc false
161+
def __sort_fields__({ left, _ }, { right, _ }), do: left > right
162+
163+
164+
@doc false
165+
def __struct__(fields) do
166+
quote do
167+
defstruct unquote(Macro.escape(fields)) ++ [ timestamp: nil ]
168+
end
169+
end
170+
171+
@doc false
172+
def __struct_fields__(fields) do
173+
quote do
174+
defmodule Fields do
175+
@type t :: %__MODULE__{}
176+
177+
defstruct unquote(Macro.escape(fields))
178+
end
179+
end
180+
end
181+
182+
@doc false
183+
def __struct_tags__(tags) do
184+
quote do
185+
defmodule Tags do
186+
@type t :: %__MODULE__{}
187+
188+
defstruct unquote(Macro.escape(tags))
189+
end
190+
end
191+
end
192+
193+
end

0 commit comments

Comments
 (0)