Licet.Relationship (Licet v0.1.0)

Copy Markdown View Source

A relationship: one stored fact linking a resource to a subject.

Licet functions accept relationships as text, in SpiceDB's format, or as this struct. Licet.read/3 returns structs.

TextMeaning
document:roadmap#owner@user:anneAnne is an owner of the roadmap
document:roadmap#viewer@team:eng#membermembers of team eng are viewers
document:roadmap#viewer@user:*every user is a viewer
document:roadmap#viewer@user:anne[expiration:2027-01-01T00:00:00Z]Anne is a viewer until 2027

A subject written user:anne#... is the same as user:anne. In the struct, subject_relation is "" when the subject has no relation.

Relation names are lowercase, 3 to 64 characters. Type names follow the same rule, and may be namespaced as prefix/name, up to 128 characters in total, as in SpiceDB. Ids are 1 to 1024 characters from A-Z, a-z, 0-9, and /_|=-+, or * for a wildcard subject. Names stay strings; Licet never turns them into atoms.

Summary

Functions

Parses relationship text.

Parses an object, such as "document:1", or a userset, such as "team:eng#member", into its type, id, and relation.

Renders a relationship as text, the inverse of parse/1.

Types

t()

@type t() :: %Licet.Relationship{
  expires_at: DateTime.t() | nil,
  relation: String.t(),
  resource_id: String.t(),
  resource_type: String.t(),
  subject_id: String.t(),
  subject_relation: String.t(),
  subject_type: String.t()
}

Functions

parse(value)

@spec parse(String.t()) :: {:ok, t()} | {:error, Licet.Error.t()}

Parses relationship text.

This checks the format only. Whether the types and relations exist in the schema is checked when the relationship is written.

Examples

iex> {:ok, rel} = Licet.Relationship.parse("document:1#viewer@team:eng#member")
iex> {rel.resource_type, rel.resource_id, rel.relation}
{"document", "1", "viewer"}
iex> {rel.subject_type, rel.subject_id, rel.subject_relation}
{"team", "eng", "member"}

iex> {:ok, rel} = Licet.Relationship.parse("document:1#viewer@user:ada[expiration:2027-01-01T00:00:00Z]")
iex> rel.expires_at
~U[2027-01-01 00:00:00Z]

iex> {:error, %Licet.Error{reason: reason}} = Licet.Relationship.parse("document:1")
iex> reason
:invalid_relationship

parse_object(value)

@spec parse_object(String.t()) ::
  {:ok, String.t(), String.t(), String.t()} | {:error, Licet.Error.t()}

Parses an object, such as "document:1", or a userset, such as "team:eng#member", into its type, id, and relation.

The relation is "" for a plain object.

Examples

iex> Licet.Relationship.parse_object("document:1")
{:ok, "document", "1", ""}

iex> Licet.Relationship.parse_object("team:eng#member")
{:ok, "team", "eng", "member"}

to_string(rel)

@spec to_string(t()) :: String.t()

Renders a relationship as text, the inverse of parse/1.

Examples

iex> {:ok, rel} = Licet.Relationship.parse("document:1#viewer@team:eng#member")
iex> Licet.Relationship.to_string(rel)
"document:1#viewer@team:eng#member"