PaperTiger.Store.Subscriptions (PaperTiger v1.5.1)

Copy Markdown View Source

ETS-backed storage for Subscription resources.

Uses the shared store pattern via use PaperTiger.Store which provides:

  • GenServer wraps ETS table
  • Reads go directly to ETS (concurrent, fast)
  • Writes go through GenServer (serialized, safe)

Architecture

  • ETS Table: :paper_tiger_subscriptions (public, read_concurrency: true)
  • GenServer: Serializes writes, handles initialization
  • Shared Implementation: All CRUD operations via PaperTiger.Store

Examples

# Direct read (no GenServer bottleneck)
{:ok, subscription} = PaperTiger.Store.Subscriptions.get("sub_123")

# Serialized write
subscription = %{id: "sub_123", customer: "cus_123", status: "active", ...}
{:ok, subscription} = PaperTiger.Store.Subscriptions.insert(subscription)

# Query helpers (direct ETS access)
subscriptions = PaperTiger.Store.Subscriptions.find_by(:customer, "cus_123")
active_subscriptions = PaperTiger.Store.Subscriptions.find_by(:status, "active")

Summary

Functions

Returns a specification to start this module under a supervisor.

Clears all subscriptions from the store (all namespaces).

Clears all subscriptions for a specific namespace.

Counts total subscriptions in current namespace.

Deletes a subscription from the store.

find_active() deprecated

Finds all subscriptions in the current namespace whose field equals value.

Retrieves a subscription by ID.

Retrieves a subscription only when it belongs to the given owner.

Inserts a subscription into the store.

Lists all subscriptions with optional pagination.

Returns all items in a specific namespace.

Validates and applies child-resource mutations in one serialized store call.

Lists every storage namespace that currently holds subscriptions.

Returns the ID prefix for this resource.

Starts the subscription store GenServer.

Returns the ETS table name for this store.

Updates a subscription in the store.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

clear()

@spec clear() :: :ok

Clears all subscriptions from the store (all namespaces).

Serialized write - goes through GenServer.

Useful for test cleanup. Note: This clears ALL data, not just the current namespace. For namespace-specific cleanup, use clear_namespace/1.

clear_namespace(namespace)

@spec clear_namespace(pid() | :global | {pid() | :global, String.t()}) :: :ok

Clears all subscriptions for a specific namespace.

Used by PaperTiger.Test to clean up after each test.

count()

@spec count() :: non_neg_integer()

Counts total subscriptions in current namespace.

Direct ETS access - does not go through GenServer.

delete(id)

@spec delete(String.t()) :: :ok

Deletes a subscription from the store.

Serialized write - goes through GenServer. Data is scoped to the current test namespace.

find_active()

This function is deprecated. Use find_by/2.

find_by(field, value)

@spec find_by(atom(), term()) :: [map()]

Finds all subscriptions in the current namespace whose field equals value.

Direct ETS access - does not go through GenServer. Returns an empty list when value is nil, since a nil reference never identifies a parent resource.

Examples

find_by(:customer, "cus_123")
find_by(:status, "active")

find_by_customer(value)

This function is deprecated. Use find_by/2.

get(id)

@spec get(String.t()) :: {:ok, map()} | {:error, :not_found}

Retrieves a subscription by ID.

Direct ETS access - does not go through GenServer. Data is scoped to the current test namespace.

get_owned(id, owner_field, owner_id)

@spec get_owned(String.t(), atom(), term()) :: {:ok, map()} | {:error, :not_found}

Retrieves a subscription only when it belongs to the given owner.

Missing resources and resources owned by a different parent both return {:error, :not_found} so nested endpoints do not disclose foreign IDs.

insert(item)

@spec insert(map()) :: {:ok, map()}

Inserts a subscription into the store.

Serialized write - goes through GenServer to prevent race conditions. Data is scoped to the current test namespace.

list(opts \\ %{})

@spec list(keyword() | map()) :: PaperTiger.List.t()

Lists all subscriptions with optional pagination.

Direct ETS access - does not go through GenServer. Data is scoped to the current test namespace.

Options

  • :limit - Number of items (default: 10, max: 100)
  • :starting_after - Cursor for pagination
  • :ending_before - Reverse cursor

list_namespace(namespace)

@spec list_namespace(pid() | :global | {pid() | :global, String.t()}) :: [map()]

Returns all items in a specific namespace.

Useful for debugging test isolation.

mutate_owned(owner_field, owner_id, operations)

@spec mutate_owned(atom(), term(), [
  {:insert | :update, map()} | {:delete, String.t()}
]) ::
  :ok
  | {:error,
     {:already_exists | :duplicate_operation | :not_found | :not_owned,
      String.t()}}

Validates and applies child-resource mutations in one serialized store call.

Every operation is checked before any write occurs. Inserts must use new IDs, updates and deletes must target existing resources owned by owner_id, and an ID may appear only once in the batch.

namespaces()

@spec namespaces() :: [PaperTiger.Connect.storage_namespace()]

Lists every storage namespace that currently holds subscriptions.

Direct ETS access - does not go through GenServer.

prefix()

@spec prefix() :: String.t() | nil

Returns the ID prefix for this resource.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts the subscription store GenServer.

table_name()

@spec table_name() :: atom()

Returns the ETS table name for this store.

update(item)

@spec update(map()) :: {:ok, map()}

Updates a subscription in the store.

Serialized write - goes through GenServer. Data is scoped to the current test namespace.