# `MishkaCmsCore.Runtime.States.AssetsState`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core/runtime/states/assets_state.ex#L5)

High-performance ETS-based state manager for multi-site asset storage and retrieval.

Manages runtime asset data (themes, CSS, JavaScript, configurations) with optimized
storage using composite keys for multi-tenant applications. Designed for fast asset
retrieval, efficient memory usage, and concurrent read/write operations.

## Architecture

Uses a single ETS table with composite key structure:
- **Composite Key**: `{site_name, type}` ensures uniqueness per site and asset type
- **Value Storage**: Arbitrary data structures (maps, strings, binaries)
- **Metadata**: Hash validation and timestamp tracking
- **Concurrent Access**: Optimized for high read concurrency

## Data Structure

Each asset record contains:
- `id`: Site identifier for multi-tenant isolation
- `type`: Asset type classification (theme, css, js, config, etc.)
- `value`: Asset content (maps, strings, or any serializable data)
- `hash`: Content hash for validation and change detection
- `updated_at`: Last modification timestamp

## Key Features

- **O(1) Asset Lookups**: Direct access by site and type combination
- **Multi-tenant Isolation**: Site-based asset separation
- **Flexible Storage**: Support for any serializable data structure
- **Batch Operations**: Efficient bulk asset loading
- **Hash Validation**: Content integrity verification
- **Memory Optimization**: Direct value access without full record retrieval
- **Concurrent Safety**: Read/write concurrency optimization

## Performance Characteristics

- Direct lookups: O(1)
- Site-based queries: O(n) where n = assets per site
- Memory usage: ~100-200 bytes per asset + content size
- Concurrent reads: Fully optimized
- Batch operations: ~5x faster than individual saves

## Usage Examples

```elixir
# Save theme assets
AssetsState.save(%{
  id: "myblog",
  type: "theme",
  value: %{
    css: "body { color: #333; }",
    js: "console.log('Theme loaded');",
    config: %{dark_mode: true}
  },
  hash: "abc123",
  updated_at: DateTime.utc_now()
})

# Fast asset retrieval
{:ok, theme} = AssetsState.get("myblog", "theme")

# Direct value access for performance
css_content = AssetsState.get_value("myblog", "css")

# Site-wide asset management
all_assets = AssetsState.get_by_site("myblog")

# Batch loading for performance
AssetsState.save_batch([
  %{id: "site1", type: "theme", value: theme_data, hash: "hash1", updated_at: now},
  %{id: "site1", type: "config", value: config_data, hash: "hash2", updated_at: now}
])
```

## Asset Type Examples

- **theme**: Complete theme packages with CSS, JS, and configuration
- **css**: Compiled CSS stylesheets
- **js**: JavaScript bundles and libraries
- **config**: Site-specific configuration data
- **templates**: Compiled template data
- **metadata**: SEO and meta information
- **cache**: Processed content cache

## Integration Patterns

- **Theme Engine**: Dynamic theme loading and switching
- **Asset Pipeline**: Runtime asset compilation and serving
- **Multi-site Management**: Site-isolated asset storage
- **CDN Integration**: Asset hash-based cache invalidation
- **Development Tools**: Hot-reload asset updates

## Production Considerations

- Monitor memory usage with `stats/0` function
- Implement asset cleanup strategies for unused sites
- Use hash validation for content integrity
- Consider asset size limits for memory management
- Leverage batch operations for bulk updates
- Use direct value access for performance-critical paths

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear`

Clears all data from the table.

# `count`

Returns the number of assets in the table.

# `delete`

Deletes an asset by ID and type. A no-op while this cache is not running.

# `delete_by_site`

Deletes all assets for a specific site.
Returns the number of deleted assets.

# `exists?`

Fast check if an asset exists by site_name and type.

# `get`

Gets asset data by ID (site_name) and type using direct lookup (O(1)).
Returns {:ok, asset} or {:error, :not_found}.

# `get!`

Gets asset data by ID (site_name) and type, returns nil if not found.
Optimized for read performance.

# `get_all`

Gets all assets in the table.
Note: Use with caution for large datasets.

# `get_by_site`

Gets all assets for a specific site (all types).
Returns a list of assets for the site.

# `get_by_type`

Gets all assets of a specific type across all sites.
Note: This is less efficient than direct lookups.

# `get_many`

Gets multiple assets by their composite keys {site_name, type}.
Returns a list of found assets.

# `get_value`

Gets only the value field for maximum read performance.
Returns the raw value or nil if not found.

# `hash`

```elixir
@spec hash(String.t(), String.t()) :: String.t() | nil
```

The `hash` of an asset without reading its (large) value — `nil` if absent.

One lookup that copies the hash alone, for the paths that run on every page render.

# `save`

Saves asset data to the ETS table with composite key (site_name, type).

## Examples

    MishkaCmsCore.Runtime.States.AssetsState.save(%{
      id: "example_site",
      type: "theme",
      value: %{css: "body { color: red; }", js: "console.log('hello');"},
      hash: "hash_value",
      updated_at: ~U[2024-01-01 10:00:00Z]
    })

# `save_batch`

Batch save multiple assets for better performance.

# `start_link`

Starts the MishkaCmsCore.Runtime.States.AssetsState GenServer and creates the ETS table.

# `stats`

Returns detailed statistics about the assets table.

# `touch`

Updates the updated_at timestamp for an asset.

# `types`

```elixir
@spec types(String.t()) :: [String.t()]
```

The types stored for a site, without reading their values.

# `update_value`

Updates only the value field of an existing asset.
Returns :ok if updated, {:error, :not_found} if asset doesn't exist.

# `updated_at`

The `updated_at` of an asset without reading its (large) value — `nil` if absent.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
