Skip to main content

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.