DynamicWhere.ex
DynamicWhere.exv3.0.0·docs

Policy Attributes

The compile-time half of the feature. Every attribute below is sealed by default — no runtime rule can lift it unless you write Overridable = true. See Precedence.

Type level

AttributeEffect
[DwEntity(RequirePolicy = true)]Querying this type without a policy context throws PolicyRequired instead of returning rows.
This is the one that catches a forgotten guard
Without it, a code path that never calls ApplyPolicy returns everything, and nothing complains. With it, the omission is a startup- loud failure on the first call rather than a silent disclosure.

Access control

AttributeEffect
[DwDeny(features)]The composable primitive. Refuse any combination of the six features.
[DwDenied]Refuse all six.
[DwNoWhere]Refuse filtering.
[DwNoSelect]Refuse projection. The field stays filterable and countable.
[DwNoOrder]Refuse sorting. The fix startup validation names for a masked field.
[DwNoGroup]Refuse grouping.
[DwNoAggregate]Refuse aggregation.
[DwOperators(Allow = ..., Deny = ...)]Restrict which operators may target the field. Restrictions from several sources intersect.
// Confirmable, not searchable: a caller can check a code it already knows
// and cannot sweep for one it does not.
[DwOperators(Allow = new[] { Operator.Equal, Operator.In })]
public string EmployeeCode { get; set; }

Injection

AttributeEffect
[DwAlias("name")]A public name, accepted anywhere a field path is. Renamed back on the way out, after materialization.
[DwForceWhere(op, Value =, ContextValue =)]A predicate ANDed into every guarded query, whether the caller asked or not.
[DwRequireWhere(Operators =)]The caller must filter on this field. Throws in both tiers.
// The row-level boundary. ContextValue reads from DwPolicyContext.Values,
// so the tenant comes from the request rather than from the source.
[DwForceWhere(Operator.Equal, ContextValue = "TenantId")]
public int TenantId { get; set; }

// Not a denial: an unscoped read of every department is the query worth
// refusing, and a requirement refuses it without blocking the scoped one.
[DwRequireWhere]
public string Department { get; set; }
Forced predicates are ANDed, never elected
Several sources can each force a predicate on the same field, and all of them apply. A conjunction can only narrow, so a low-authority rule can tighten a tenant scope and can never discard one.

Transformation

Covered in full on Transforms & masking.

AttributeEffect
[DwMask(strategy)]Obscure the value. Eight strategies.
[DwMutate(typeof(T))]Hand the value to your own IValueTransformer.
[DwDefault] / [DwDefault("v")]Replace with the type default or a constant.
[DwGeneralize(mode)]Reduce precision, keeping the type.
[DwTruncate(n)]Shorten text.
[DwFormat("fmt")]Render through a .NET format string.

All six also carry AllowAggregate and MinGroupSize — see Security, because those two are the k-anonymity control and are easy to miss.

Discovery, cost and audit

AttributeEffect
[DwDescribe(Label =, Description =, Group =, Order =)]Describes the field for the schema endpoint, so a front end builds its filter UI from the entity rather than a hand-maintained copy.
[DwAllowedValues(...)]Offer a list rather than a free-text box.
[DwCost(weight)]Charge the field against the query budget, so an expensive field costs more of a caller allowance.
[DwAudit(features)]Record every use to IDwAuditSink.

Overridable

Every policy attribute carries Overridable, which defaults to false. One attribute can be sealed while another on the same member is replaceable.

// The mask is absolute; the description is a suggestion an operator may change.
[DwMask(MaskStrategy.Full)]
[DwDescribe(Label = "National ID", Overridable = true)]
public string NationalId { get; set; }
A carrier on a self-referencing type
[DwAlias], [DwRequireWhere] and [DwForceWhere] describe the entity being queried, so they are not replicated onto reflections of a type reached from itself — Employee.Manager, Category.Parent. A scope declared one navigation away on a different type, such as Order.Buyer.TenantId, still applies.