Entities & Columns
Every persisted model starts the same way: a class marked @Entity, fields marked @Column. This page covers the decorators that shape what a piece of data actually looks like, its identity, its indexes, and which fields exist at all. Validating the values those fields actually hold is a separate concern, covered next in Validation.
@Entity(options?)
Marks a class as persistable:
@Entity({collation: {locale: 'en', strength: 2}})
export class Pet extends BaseMongoEntity {
@Column()
name: string = '';
}
options.name overrides the collection/table name, which otherwise defaults to the snake_cased class name. options.collation sets a MongoDB collation, ignored on SQL datastores.
@DataStore(name)
Says which configured datastore an entity's data lives in, name matching a key under datastores in your configuration, covered fully in Datastores & Connections:
@Entity({collation: {locale: 'en', strength: 2}})
@DataStore('mongo')
export class Pet extends BaseMongoEntity {
@Column()
name: string = '';
}
@Column(options?)
Marks a property as persisted:
export interface ColumnOptions {
name?: string; // override the stored field name
nullable?: boolean;
primary?: boolean;
isObjectId?: boolean; // MongoDB ObjectId fields, e.g. `_id`
}
@Column({isObjectId: true})
@Nullable
_id?: any;
@PrimaryColumn(options?)
Shorthand for @Column({...options, primary: true}), for identifier fields:
@Identifier
@Index('uid', {unique: true})
@PrimaryColumn()
uid: string = uuid.v4();
@Index and @Unique
@Index takes one of a few forms, depending on whether you're indexing a single property or defining a class-level compound index:
// Property-level
@Index() // unnamed single-field index
@Index('myIndexName') // named
@Index({unique: true}) // unnamed, unique
// Class-level compound index
@Index(['firstName', 'lastName'])
@Index('fullName', ['firstName', 'lastName'], {unique: true})
IndexOptions also accepts sparse, background, and expireAfterSeconds (MongoDB-specific, for TTL indexes).
@Unique is shorthand for an index with {unique: true}, in the same property-level or class-level forms:
@Unique('email')
@RequiresScope
RequiresScope(scope: string | string[]) marks a property as readable only by callers whose token carries at least one of the given OAuth-style scopes. Unlike a failed permission check, a missing scope doesn't reject the request, the property is just silently stripped from the response:
@Column()
@RequiresScope('profile:email')
contacts: Contact[] = [];
This runs automatically inside RepoUtils.find()/findOne(), nothing to wire up in your route. It's how @rapidrest/auth's Profile model keeps contacts and preferences behind profile:email and profile:preferences scopes.
This is a different thing from the route-level @RequiresScope in Authorization, that one gates an entire endpoint, this one hides one field.
A complete example
import {BaseMongoEntity, PersistenceDecorators, ModelDecorators} from '@rapidrest/service-core';
const {Entity, Column, Index} = PersistenceDecorators;
const {DataStore, Identifier} = ModelDecorators;
@Entity()
@DataStore('mongo')
export class Pet extends BaseMongoEntity {
@Identifier
@Index()
@Column()
name: string = '';
@Column()
species: string = '';
}
Nothing here checks that name is actually present, or that species is one of a known set of values, that's what Validation is for.