Attribute Reference¶
All Data Store attributes live in the Deepstaging.DataStore namespace. See also the Generated Code and Effects Composition pages for what these attributes produce.
[DataStore]¶
Marks a static partial class as the data store container. Only one [DataStore] per assembly is allowed.
| Property | Type | Default | Description |
|---|---|---|---|
Instrumented |
bool |
true |
Enables OpenTelemetry tracing spans on generated effect methods via .WithActivity() |
| Requirement | Diagnostic |
|---|---|
Must be partial |
DSDS01 (Error) |
Should be static |
DSDS02 (Warning) |
| One per assembly | DSDS05 (Error) |
[StoredEntity]¶
Marks a class or record as a persistent entity. The entity must have a property with a [TypedId] type, which becomes the primary key.
| Property | Type | Default | Description |
|---|---|---|---|
PluralName |
string? |
Inferred (e.g., Articles) |
Override the nested class name used for effect methods and store grouping |
| Requirement | Diagnostic |
|---|---|
Must be partial |
DSDS03 (Error) |
Must have a [TypedId] property |
DSDS04 (Error) |
Requires [DataStore] in assembly |
DSDS08 (Error) |
TypedId requirement
Every [StoredEntity] needs a property whose type is marked with [TypedId]. See the Typed IDs module for details.
[ForeignKey<TEntity>]¶
Declares a relationship between stored entities. The generic parameter must reference another [StoredEntity].
[StoredEntity]
public partial record Comment(
CommentId Id,
[ForeignKey<Article>] ArticleId ArticleId,
string Body);
| Requirement | Diagnostic |
|---|---|
Target must be a [StoredEntity] |
DSDS06 (Error) |
[CompositeKey]¶
Declares a composite primary key instead of a single [TypedId] property. The named properties must exist on the entity.
[StoredEntity]
[CompositeKey(nameof(UserId), nameof(ArticleId))]
public partial record Bookmark(UserId UserId, ArticleId ArticleId, DateTimeOffset CreatedAt);
For composite key entities, GetByIdAsync and DeleteAsync accept all key properties as separate parameters. See Generated Code for the generated interface shape.
| Requirement | Diagnostic |
|---|---|
| Named properties must exist | DSDS07 (Error) |
[Lookup]¶
Marks a property for indexed lookup. The generator emits a GetBy{Property} method returning StoreQuery<T> on the store interface and all implementations. In the Postgres layer, HasIndex is also configured on the property in OnModelCreating.
[StoredEntity]
public partial record CatalogItem(
CatalogItemId Id,
string Name,
[Lookup] CatalogBrandId BrandId);
This generates:
// On ICatalogItemStore — returns a composable query with the lookup predicate pre-applied
StoreQuery<CatalogItem> GetByCatalogBrandId(CatalogBrandId catalogBrandId);
// Usage — further filter, sort, paginate as needed
var page = await store.GetByCatalogBrandId(brandId)
.OrderBy(i => i.Name)
.ToPageAsync(1, 20);
On the effects layer, five terminal methods are generated per lookup:
// All accept optional additional filter/orderBy
CatalogStore.CatalogItems.QueryPageByBrandId<RT>(brandId, page, pageSize, filter?, orderBy?)
CatalogStore.CatalogItems.QueryListByBrandId<RT>(brandId, filter?, orderBy?)
CatalogStore.CatalogItems.QueryCursorByBrandId<RT>(brandId, cursor, limit, filter?)
CatalogStore.CatalogItems.QueryFirstByBrandId<RT>(brandId, filter?)
CatalogStore.CatalogItems.QueryCountByBrandId<RT>(brandId, filter?)
And in the Postgres DbContext:
| Target | Applies To |
|---|---|
AttributeTargets.Property |
Any property on a [StoredEntity] |
Multiple lookups
You can apply [Lookup] to multiple properties on the same entity. Each generates its own GetBy{Prop} method and database index.
Rules and Constraints¶
- Exactly one
[DataStore]per assembly — it acts as the root container for all entities. - Every
[StoredEntity]must bepartialso the generator can extend it. - Every
[StoredEntity]needs either a[TypedId]property or a[CompositeKey]attribute. [ForeignKey<T>]targets must themselves be[StoredEntity]types.- The
[DataStore]class should bestatic(warning if not) and must bepartial(error if not).