Packages

Elixir client for SpacetimeDB — BSATN binary protocol, WebSocket subscriptions, reducer calls, live ETS table mirrors

Current section

Files

Jump to
spacetimedb_ex lib mix tasks spacetimedb.gen.ex
Raw

lib/mix/tasks/spacetimedb.gen.ex

defmodule Mix.Tasks.Spacetimedb.Gen do
use Mix.Task
@shortdoc "Generate BSATN schema modules from a live SpacetimeDB database"
@moduledoc ~S"""
Connects to a SpacetimeDB instance, fetches the module schema, and generates
one `SpacetimeDB.BSATN.Schema` Elixir module per table.
## Usage
mix spacetimedb.gen --host HOST --database NAME [options]
## Options
| Flag | Default | Description |
|------|---------|-------------|
| `--host` | required | SpacetimeDB host |
| `--database` | required | Database name or address |
| `--port` | `3000` | Port |
| `--tls` | false | Use TLS (`wss://`) |
| `--token` || Auth token |
| `--namespace` | `SpacetimeDB` | Elixir module namespace prefix |
| `--out` | `lib/spacetimedb/` | Output directory |
## Examples
# Local dev server
mix spacetimedb.gen --host localhost --database my-module
# With custom namespace and output directory
mix spacetimedb.gen \
--host localhost \
--database my-module \
--namespace MyApp.SpacetimeDB \
--out lib/my_app/spacetimedb/
# Production with TLS and auth token
mix spacetimedb.gen \
--host mainnet.spacetimedb.com \
--database my-prod-module \
--tls \
--token $SPACETIMEDB_TOKEN \
--namespace MyApp.SpacetimeDB \
--out lib/my_app/spacetimedb/
## Generated files
For a table called `Player` with a `--namespace` of `MyApp.SpacetimeDB`:
# lib/my_app/spacetimedb/player.ex
defmodule MyApp.SpacetimeDB.Player do
@moduledoc "Live mirror of the `Player` SpacetimeDB table. Auto-generated."
use SpacetimeDB.BSATN.Schema
bsatn_schema do
field :id, :u32
field :name, :string
field :health, :u32
end
def primary_key, do: :id
def table_name, do: "Player"
end
Re-run the task any time the SpacetimeDB module schema changes. Files are
overwritten, so avoid hand-editing generated modules — extend them in
separate files instead.
"""
@switches [
host: :string,
database: :string,
port: :integer,
tls: :boolean,
token: :string,
namespace: :string,
out: :string
]
@impl Mix.Task
def run(args) do
# Ensure the app is started so Jason etc. are available
Mix.Task.run("app.start", [])
{opts, _rest, _invalid} = OptionParser.parse(args, strict: @switches)
host = opts[:host] || Mix.raise("--host is required")
database = opts[:database] || Mix.raise("--database is required")
gen_opts = [
port: opts[:port] || 3000,
tls: opts[:tls] || false,
token: opts[:token],
namespace: opts[:namespace] || "SpacetimeDB",
out: opts[:out] || "lib/spacetimedb/"
]
Mix.shell().info("Fetching schema from #{host} / #{database}...")
case SpacetimeDB.CodeGen.run([host: host, database: database] ++ gen_opts) do
:ok ->
Mix.shell().info("Done.")
{:error, {:http_error, status, body}} ->
Mix.raise("HTTP #{status}: #{body}")
{:error, reason} ->
Mix.raise("Failed: #{inspect(reason)}")
end
end
end