Skip to content

Commit 9fd101b

Browse files
authored
Merge pull request #1079 from eddbbt/appenginge_ecto_schema
Appengine ecto schemas
2 parents c05b520 + 429f4c0 commit 9fd101b

File tree

13 files changed

+502
-53
lines changed

13 files changed

+502
-53
lines changed

apps/astarte_appengine_api/config/config.exs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Config
88
# General application configuration
99
config :astarte_appengine_api, namespace: Astarte.AppEngine.API
1010

11+
config :astarte_appengine_api, ecto_repos: [Astarte.AppEngine.API.Repo]
12+
1113
# Configures the endpoint
1214
config :astarte_appengine_api, Astarte.AppEngine.APIWeb.Endpoint,
1315
url: [host: "localhost"],

apps/astarte_appengine_api/lib/astarte_appengine_api/application.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ defmodule Astarte.AppEngine.API.Application do
5555
Astarte.AppEngine.API.Rooms.AMQPClient,
5656
Astarte.AppEngine.APIWeb.Endpoint,
5757
{Xandra.Cluster, ae_xandra_opts},
58-
{Astarte.DataAccess, data_access_opts}
58+
{Astarte.DataAccess, data_access_opts},
59+
{Astarte.AppEngine.API.Repo, xandra_options}
5960
]
6061

6162
# See https://hexdocs.pm/elixir/Supervisor.html
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
defmodule Astarte.AppEngine.API.Device.DeletionInProgress do
19+
use TypedEctoSchema
20+
alias Astarte.AppEngine.API.UUID
21+
22+
@primary_key {:device_id, UUID, autogenerate: false}
23+
typed_schema "deletion_in_progress" do
24+
field :vmq_ack, :boolean
25+
field :dup_start_ack, :boolean
26+
field :dup_end_ack, :boolean
27+
end
28+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
defmodule Astarte.AppEngine.API.Devices.Device do
20+
use TypedEctoSchema
21+
alias Astarte.AppEngine.API.UUID
22+
23+
@primary_key {:device_id, UUID, autogenerate: false}
24+
typed_schema "devices" do
25+
field :aliases, Exandra.Map, key: :string, value: :string
26+
field :attributes, Exandra.Map, key: :string, value: :string
27+
field :cert_aki, :string
28+
field :cert_serial, :string
29+
field :connected, :boolean
30+
field :credentials_secret, :string
31+
32+
field :exchanged_bytes_by_interface, Exandra.Map,
33+
key: Exandra.Tuple,
34+
types: [:string, :integer],
35+
value: :integer
36+
37+
field :exchanged_msgs_by_interface, Exandra.Map,
38+
key: Exandra.Tuple,
39+
types: [:string, :integer],
40+
value: :integer
41+
42+
field :first_credentials_request, :utc_datetime_usec
43+
field :first_registration, :utc_datetime_usec
44+
field :groups, Exandra.Map, key: :string, value: UUID
45+
field :inhibit_credentials_request, :boolean
46+
field :introspection, Exandra.Map, key: :string, value: :integer
47+
field :introspection_minor, Exandra.Map, key: :string, value: :integer
48+
field :last_connection, :utc_datetime_usec
49+
field :last_credentials_request_ip, Exandra.Inet
50+
51+
field :last_disconnection, :utc_datetime_usec
52+
field :last_seen_ip, Exandra.Inet
53+
54+
field :old_introspection,
55+
Exandra.Map,
56+
key: Exandra.Tuple,
57+
types: [:string, :integer],
58+
value: :integer
59+
60+
field :pending_empty_cache, :boolean
61+
field :protocol_revision, :integer
62+
field :total_received_bytes, :integer
63+
field :total_received_msgs, :integer
64+
end
65+
end
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
defmodule Astarte.AppEngine.API.Groups.GroupedDevice do
20+
use TypedEctoSchema
21+
alias Astarte.AppEngine.API.UUID
22+
23+
@primary_key false
24+
typed_schema "grouped_devices" do
25+
field :group_name, :string, primary_key: true
26+
field :insertion_uuid, UUID, primary_key: true
27+
field :device_id, UUID, primary_key: true
28+
end
29+
end
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# TODO: Copied from astarte_data_access PR #71, see: https://github.com/astarte-platform/astarte_data_access/pull/71
19+
# use `astarte_data_access` when it will be merged
20+
defmodule Astarte.AppEngine.API.KvStore do
21+
use TypedEctoSchema
22+
23+
alias Astarte.AppEngine.API.Repo
24+
25+
import Ecto.Query
26+
27+
@type value_type :: :binary | :integer | :big_integer | :string
28+
@source "kv_store"
29+
30+
@primary_key false
31+
typed_schema @source do
32+
field :group, :string, primary_key: true
33+
field :key, :string, primary_key: true
34+
field :value, :binary
35+
end
36+
37+
@doc """
38+
Insert a KvStore, allowing type conversion at the database level.
39+
40+
The Ecto mindset is to finalize the struct on the Elixir side before sending it to \
41+
the database. This does not work well with the KvStore, where we need to store many types as \
42+
a blob, but don't care about their actual value on the database side.
43+
44+
By delegating the conversion to the database, we do not need to manually re-implement all the \
45+
conversion functions on the elixir side.
46+
"""
47+
@spec insert(
48+
%{
49+
optional(:value_type) => value_type(),
50+
group: String.t(),
51+
key: String.t(),
52+
value: term()
53+
},
54+
Keyword.t()
55+
) :: :ok | {:error, Exception.t()}
56+
def insert(kv_store_map, opts \\ []) do
57+
%{
58+
group: group,
59+
key: key,
60+
value: value
61+
} = kv_store_map
62+
63+
value_type = Map.get(kv_store_map, :value_type, :binary)
64+
65+
value_expr =
66+
case value_type do
67+
:binary -> "?"
68+
:integer -> "intAsBlob(?)"
69+
:big_integer -> "bigintAsBlob(?)"
70+
:string -> "varcharAsBlob(?)"
71+
end
72+
73+
{keyspace, opts} = Keyword.pop!(opts, :prefix)
74+
75+
sql =
76+
"""
77+
INSERT INTO #{keyspace}.#{@source} (group, key, value)
78+
VALUES (?, ?, #{value_expr})
79+
"""
80+
81+
params = [group, key, value]
82+
83+
with {:ok, _} <- Repo.query(sql, params, opts) do
84+
:ok
85+
end
86+
end
87+
88+
@spec fetch_value(String.t(), String.t(), value_type(), Keyword.t()) ::
89+
{:ok, term()} | {:error, term()}
90+
def fetch_value(group, key, value_type \\ :binary, opts \\ []) do
91+
value_expr =
92+
case value_type do
93+
:binary -> dynamic([kv], kv.value)
94+
:integer -> dynamic([kv], fragment("blobAsInt(?)", kv.value))
95+
:big_integer -> dynamic([kv], fragment("blobAsBigint(?)", kv.value))
96+
:string -> dynamic([kv], fragment("blobAsVarChar(?)", kv.value))
97+
end
98+
99+
query = from __MODULE__, select: ^value_expr
100+
primary_key = [group: group, key: key]
101+
102+
Repo.fetch_by(query, primary_key, opts)
103+
end
104+
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
# TODO: Copied from astarte_data_access PR #71, see: https://github.com/astarte-platform/astarte_data_access/pull/71
20+
# use `astarte_data_access` when it will be merged
21+
defmodule Astarte.AppEngine.API.Endpoint do
22+
use TypedEctoSchema
23+
24+
alias Astarte.Core.Interface.Type, as: InterfaceType
25+
alias Astarte.Core.Mapping.DatabaseRetentionPolicy
26+
alias Astarte.Core.Mapping.Reliability
27+
alias Astarte.Core.Mapping.Retention
28+
alias Astarte.Core.Mapping.ValueType
29+
30+
@primary_key false
31+
typed_schema "endpoints" do
32+
field :interface_id, Astarte.AppEngine.API.UUID, primary_key: true
33+
field :endpoint_id, Astarte.AppEngine.API.UUID, primary_key: true
34+
field :allow_unset, :boolean
35+
field :database_retention_policy, DatabaseRetentionPolicy
36+
field :database_retention_ttl, :integer
37+
field :description, :string
38+
field :doc, :string
39+
field :endpoint, :string
40+
field :expiry, :integer
41+
field :explicit_timestamp, :boolean
42+
field :interface_major_version, :integer
43+
field :interface_minor_version, :integer
44+
field :interface_name, :string
45+
field :interface_type, InterfaceType
46+
field :reliability, Reliability
47+
field :retention, Retention
48+
field :value_type, ValueType
49+
end
50+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# This file is part of Astarte.
3+
#
4+
# Copyright 2025 SECO Mind Srl
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# TODO: Copied from astarte_data_access PR #71, see: https://github.com/astarte-platform/astarte_data_access/pull/71
19+
# use `astarte_data_access` when it will be merged
20+
defmodule Astarte.AppEngine.API.Realm do
21+
use TypedEctoSchema
22+
23+
alias Astarte.Core.CQLUtils
24+
alias Astarte.DataAccess.Config
25+
26+
@primary_key {:realm_name, :string, autogenerate: false}
27+
typed_schema "realms" do
28+
field :device_registration_limit, :integer
29+
end
30+
31+
@spec keyspace_name(String.t()) :: String.t()
32+
def keyspace_name(realm_name) do
33+
CQLUtils.realm_name_to_keyspace_name(realm_name, Config.astarte_instance_id!())
34+
end
35+
end

0 commit comments

Comments
 (0)