diff --git a/docs/06-concepts/02-models/01-models.md b/docs/06-concepts/02-models/01-models.md index ef0e9846..08826105 100644 --- a/docs/06-concepts/02-models/01-models.md +++ b/docs/06-concepts/02-models/01-models.md @@ -547,7 +547,7 @@ fields: | [**type (index)**](database/indexing) | The type of index to create. | ✅ | | | | [**parameters (index)**](database/indexing#vector-indexes) | Parameters for specialized index types like HNSW and IVFFLAT vector indexes. | ✅ | | | | [**distanceFunction (index)**](database/indexing#vector-indexes) | Distance function for vector indexes. Allowed values depend on the field's vector type and index type — see [vector indexes](database/indexing#vector-indexes). | ✅ | | | -| [**unique**](database/indexing) | Boolean flag to make the entries unique in the database. | ✅ | | | +| [**unique**](database/indexing) | Creates a unique index. | ✅ | | | | [**default**](#default-values) | Sets the default value for both the model and the database. This keyword cannot be used with **relation**. | ✅ | | | | [**defaultModel**](#default-values) | Sets the default value for the model side. This keyword cannot be used with **relation**. | ✅ | | | | [**defaultPersist**](#default-values) | Sets the default value for the database side. This keyword cannot be used with **relation** and **!persist**. | ✅ | | | diff --git a/docs/06-concepts/06-database/04-indexing.md b/docs/06-concepts/06-database/04-indexing.md index 1556c3f5..ab1c3cac 100644 --- a/docs/06-concepts/06-database/04-indexing.md +++ b/docs/06-concepts/06-database/04-indexing.md @@ -59,6 +59,46 @@ fields: name: String, unique ``` +### Composite unique constraints + +When a value should be unique only within a scope (for example, a setting key that is unique per user), use `unique(per=...)` on the field that must be unique within that scope. Serverpod auto-generates a composite unique index with the `per` columns first, followed by the annotated field. + +```yaml +class: UserSetting +table: user_setting +fields: + userId: int + key: String, unique(per=userId) +``` + +In this example, two rows can share the same `key` if they belong to different users, but the same user cannot have two rows with the same `key`. + +For a scope that spans multiple columns, pass a list of field names: + +```yaml +class: Product +table: product +fields: + tenantId: int + category: String + sku: String, unique(per=[tenantId, category]) +``` + +You can also use the equivalent expanded form, where you name the index yourself: + +```yaml +class: Product +table: product +fields: + tenantId: int + category: String + sku: String +indexes: + product_unique_idx: + fields: tenantId, category, sku + unique: true +``` + ## Specifying index type It is possible to add a type key to specify the index type.