Documentation
¶
Overview ¶
Package quarkdatasource implements Orbit's datasource contract (orbit ADR-001) over a Quark ORM client, so Data Studio browses and edits Quark-managed models (quantum QADR-0006, Caso 2).
It is the second implementation of the contract — the one that validates the abstraction did not keep Nucleus's shape. The catalogue comes from the model structs' Quark tags (db/pk/quark), not from table introspection, so Data Studio sees the same Go-level metadata Quark itself uses.
Registration is generic, per model ¶
Quark's query API is typed (quark.For[T]; its ADR-0002/0014 design), so a model's CRUD operations cannot be bound from a reflect.Type at runtime. Each model is registered with a generic call, which monomorphizes the typed query path once at wiring time:
ds := quarkdatasource.New(client)
quarkdatasource.Register[User](ds)
quarkdatasource.Register[Post](ds)
app := nucleus.New().
Mount(orbit.Module(orbit.Config{Prefix: "/admin", DataSource: ds})).
Build()
New accepts any quark.ClientProvider: a *quark.Client, or a *quark.TenantRouter so every Data Studio query runs under Quark's own tenant scoping (WHERE-injection or native RLS, per the router's strategy).
Semantics ¶
- IDs are strings at the boundary (ADR-001 D1) and are narrowed to the PK field's Go kind. Models with a composite primary key are listed read-only: List/Count work, Get/Create/Update/Delete return an error.
- Records are the model's JSON object (ADR-001 D2), with every schema field re-keyed to its storage column: Quark models normally carry no json tags, so the raw object would use Go-case keys ("CustomerID") while Data Studio reads cells by column ("customer_id"). Values (including quark.Nullable) and keys outside the schema — relations, extra JSON — pass through unchanged.
- Delete follows Quark's semantics: soft delete when the model has a deleted_at column, hard delete otherwise.
- A Quark client is bound to one database, so an adapter serves exactly one database alias (WithDatabaseAlias, default "default"): every ModelInfo carries it, and Store refuses any other alias instead of silently answering from the wrong database. Use one adapter per client if you browse several.
Index ¶
Constants ¶
const DefaultDatabaseAlias = "default"
DefaultDatabaseAlias is the alias an adapter answers to when WithDatabaseAlias is not given; it matches the panel's default alias.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter implements datasource.DataSource over a Quark client. Populate it with Register[T] for each model; registration order is preserved in All.
func New ¶
func New(provider quark.ClientProvider, opts ...Option) *Adapter
New returns an empty adapter bound to provider (a *quark.Client or a *quark.TenantRouter). Register models with Register[T].
func (*Adapter) All ¶
func (a *Adapter) All() []datasource.ModelInfo
All returns the registered models in registration order.
func (*Adapter) DatabaseAlias ¶
DatabaseAlias returns the alias this adapter serves.
func (*Adapter) Get ¶
func (a *Adapter) Get(name string) (datasource.ModelInfo, bool)
Get returns one model by name.
func (*Adapter) Store ¶
func (a *Adapter) Store(modelName, dbAlias string) (datasource.RecordStore, error)
Store returns the RecordStore for a model. An empty dbAlias means the adapter's own alias; any other alias is an error, because the Quark client behind this adapter is bound to one database and answering from it under a different name would show the operator the wrong data.
type Option ¶
type Option func(*Adapter)
Option configures the adapter.
func WithDatabaseAlias ¶
WithDatabaseAlias names the database alias this adapter serves. The panel resolves an alias per request (?db=, or the model's declared alias) and passes it to Store; the adapter honours it by refusing every other alias.
func WithTenantColumn ¶
WithTenantColumn names the column that scopes models to a tenant. Models carrying it get ModelInfo.TenantField set, so Data Studio's tenant filter applies. This complements — it does not replace — passing a *quark.TenantRouter as the provider, which enforces scoping in Quark itself.