or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bookshelf-instance.mdcollections.mdevents.mdindex.mdmodels.mdquery-building.mdrelationships.md
tile.json

models.mddocs/

Models

Individual database records with complete CRUD operations, attribute management, query building, and relationship definitions.

Capabilities

Model Creation

Create model instances using the constructor or static forge method.

/**
 * Model constructor
 * @param {object} [attributes] - Initial attribute values
 * @param {object} [options] - Configuration options
 * @param {string} [options.tableName] - Override table name
 * @param {boolean|Array} [options.hasTimestamps] - Enable timestamp columns
 * @param {boolean} [options.parse] - Parse attributes on construction
 * @param {Array} [options.visible] - Visible attributes for serialization
 * @param {Array} [options.hidden] - Hidden attributes for serialization
 * @param {boolean} [options.requireFetch] - Require explicit fetch before save/destroy
 */
new Model(attributes?: object, options?: object);

/**
 * Create model instance without 'new' keyword
 * @param {object} [attributes] - Initial attribute values  
 * @param {object} [options] - Configuration options
 * @returns {Model} New model instance
 */
Model.forge(attributes?: object, options?: object): Model;

Usage Examples:

// Using constructor
const user = new User({name: 'Alice', email: 'alice@example.com'});

// Using forge
const user = User.forge({name: 'Bob', email: 'bob@example.com'});

// With options
const user = User.forge({name: 'Charlie'}, {
  hasTimestamps: true,
  visible: ['name', 'email'],
  hidden: ['password']
});

Model Properties

Core properties for model configuration and state.

interface ModelProperties {
  /** Database table name (required) */
  tableName: string;
  
  /** Primary key column name (default: 'id') */
  idAttribute: string;
  
  /** Enable automatic timestamp columns */
  hasTimestamps: boolean | Array<string>;
  
  /** Default attribute values */
  defaults: object;
  
  /** Attributes to hide during serialization */
  hidden: Array<string>;
  
  /** Attributes to show during serialization (overrides hidden) */
  visible: Array<string>;
  
  /** Require explicit fetch before save/destroy operations */
  requireFetch: boolean;
  
  /** Current attribute values */
  attributes: object;
  
  /** Changed attributes since last save */
  changed: object;
  
  /** Loaded relationship data */
  relations: object;
  
  /** Primary key value */
  id: any;
  
  /** Client-side unique identifier */
  cid: string;
}

Static Query Methods

Class-level methods for querying without instantiation.

/**
 * Create collection of this model type
 * @param {Model[]} [models] - Initial models for collection
 * @param {object} [options] - Collection options
 * @returns {Collection} New collection instance
 */
Model.collection(models?: Model[], options?: object): Collection;

/**
 * Count records matching current query
 * @param {string} [column='*'] - Column to count
 * @param {object} [options] - Query options
 * @returns {Promise<number>} Record count
 */
Model.count(column?: string, options?: object): Promise<number>;

/**
 * Fetch all records as collection
 * @param {object} [options] - Fetch options
 * @returns {Promise<Collection>} Collection of all records
 */
Model.fetchAll(options?: object): Promise<Collection>;

/**
 * Fetch paginated results
 * @param {object} [options] - Pagination options
 * @param {number} [options.page=1] - Page number
 * @param {number} [options.pageSize=10] - Items per page
 * @returns {Promise<{models: Collection, pagination: object}>} Paginated results
 */
Model.fetchPage(options?: object): Promise<{models: Collection, pagination: object}>;

/**
 * Add where clause and return query instance
 * @param {...*} args - Where clause arguments
 * @returns {Model} Query instance for chaining
 */
Model.where(...args: any[]): Model;

/**
 * Access underlying query builder
 * @param {...*} args - Query builder arguments
 * @returns {Model} Query instance for chaining
 */
Model.query(...args: any[]): Model;

CRUD Operations

Core database operations for fetching, saving, and deleting records.

/**
 * Fetch model from database
 * @param {object} [options] - Fetch options
 * @param {string[]} [options.withRelated] - Relations to eager load
 * @param {string} [options.require=false] - Throw if not found
 * @param {object} [options.transacting] - Transaction object
 * @returns {Promise<Model>} Fetched model
 */
fetch(options?: {
  withRelated?: string[],
  require?: boolean,
  transacting?: Transaction,
  columns?: string[],
  debug?: boolean
}): Promise<Model>;

/**
 * Save model to database
 * @param {string|object} [key] - Attribute name or attributes object
 * @param {*} [value] - Attribute value (if key is string)
 * @param {object} [options] - Save options
 * @returns {Promise<Model>} Saved model
 */
save(key?: string | object, value?: any, options?: {
  method?: 'insert' | 'update',
  defaults?: object,
  patch?: boolean,
  transacting?: Transaction,
  debug?: boolean
}): Promise<Model>;

/**
 * Delete model from database
 * @param {object} [options] - Delete options
 * @returns {Promise<Model>} Deleted model
 */
destroy(options?: {
  require?: boolean,
  transacting?: Transaction,
  debug?: boolean
}): Promise<Model>;

/**
 * Load specific relations after initial fetch
 * @param {string|string[]} relations - Relation names to load
 * @param {object} [options] - Load options
 * @returns {Promise<Model>} Model with loaded relations
 */
load(relations: string | string[], options?: object): Promise<Model>;

Usage Examples:

// Fetch with relations
const user = await new User({id: 1}).fetch({
  withRelated: ['posts', 'profile'],
  require: true
});

// Save new record
const user = await new User({name: 'Alice', email: 'alice@example.com'}).save();

// Update existing record  
await user.save({name: 'Alice Smith'});

// Delete record
await user.destroy();

// Load relations after fetch
await user.load(['posts.comments', 'profile']);

Attribute Management

Methods for getting, setting, and manipulating model attributes.

/**
 * Get attribute value
 * @param {string} attribute - Attribute name
 * @returns {*} Attribute value
 */
get(attribute: string): any;

/**
 * Set attribute value(s)
 * @param {string|object} key - Attribute name or attributes object
 * @param {*} [value] - Attribute value (if key is string)
 * @param {object} [options] - Set options
 * @returns {Model} Model instance for chaining
 */
set(key: string | object, value?: any, options?: {
  unset?: boolean,
  silent?: boolean
}): Model;

/**
 * Check if attribute exists and is not null/undefined
 * @param {string} attribute - Attribute name
 * @returns {boolean} True if attribute exists
 */
has(attribute: string): boolean;

/**
 * Remove specific attribute
 * @param {string} attribute - Attribute name to remove
 * @param {object} [options] - Unset options
 * @returns {Model} Model instance for chaining
 */
unset(attribute: string, options?: object): Model;

/**
 * Clear all attributes
 * @param {object} [options] - Clear options
 * @returns {Model} Model instance for chaining
 */
clear(options?: object): Model;

/**
 * Get escaped attribute value for SQL
 * @param {string} attribute - Attribute name
 * @returns {string} Escaped attribute value
 */
escape(attribute: string): string;

/**
 * Get subset of attributes
 * @param {...string} attributes - Attribute names to include
 * @returns {object} Object with specified attributes
 */
pick(...attributes: string[]): object;

/**
 * Get attributes excluding specified ones
 * @param {...string} attributes - Attribute names to exclude  
 * @returns {object} Object without specified attributes
 */
omit(...attributes: string[]): object;

State and Validation

Methods for checking model state and changes.

/**
 * Check if model is new (not persisted to database)
 * @returns {boolean} True if model is new
 */
isNew(): boolean;

/**
 * Check if attributes have changed since last fetch/save
 * @param {string} [attribute] - Specific attribute to check
 * @returns {boolean} True if changed
 */
hasChanged(attribute?: string): boolean;

/**
 * Get hash of changed attributes
 * @returns {object} Object containing changed attributes
 */
changed(): object;

/**
 * Get previous attribute value(s)
 * @param {string} [attribute] - Specific attribute
 * @returns {*|object} Previous value or all previous values
 */
previous(attribute?: string): any;

/**
 * Get all previous attributes
 * @returns {object} Previous attributes object
 */
previousAttributes(): object;

Serialization

Methods for converting models to JSON and handling data formatting.

/**
 * Convert model to JSON object
 * @param {object} [options] - Serialization options
 * @returns {object} JSON representation
 */
toJSON(options?: {
  shallow?: boolean,
  omitPivot?: boolean
}): object;

/**
 * Serialize model and relations
 * @param {object} [options] - Serialization options
 * @returns {object} Serialized model data
 */
serialize(options?: object): object;

/**
 * Parse attributes from database
 * @param {object} attributes - Raw database attributes
 * @param {object} [options] - Parse options
 * @returns {object} Parsed attributes
 */
parse(attributes: object, options?: object): object;

/**
 * Format attributes for database
 * @param {object} attributes - Model attributes
 * @param {object} [options] - Format options
 * @returns {object} Formatted attributes for database
 */
format(attributes: object, options?: object): object;

Query Building

Methods for building database queries on model instances.

/**
 * Access or modify underlying query builder
 * @param {Function} [callback] - Function to modify query builder
 * @returns {Model} Model instance for chaining
 */
query(callback?: (queryBuilder: Knex.QueryBuilder) => void): Model;

/**
 * Add where clause to query
 * @param {...*} args - Where clause arguments
 * @returns {Model} Model instance for chaining
 */
where(...args: any[]): Model;

/**
 * Add order by clause
 * @param {string} column - Column to order by
 * @param {string} [direction='asc'] - Sort direction
 * @returns {Model} Model instance for chaining
 */
orderBy(column: string, direction?: 'asc' | 'desc'): Model;

Utility Methods

Additional utility methods for model manipulation.

/**
 * Create shallow copy of model
 * @returns {Model} Cloned model instance
 */
clone(): Model;

/**
 * Re-fetch model from database, updating current instance
 * @param {object} [options] - Refresh options  
 * @returns {Promise<Model>} Refreshed model
 */
refresh(options?: object): Promise<Model>;

/**
 * Count related records
 * @param {string} [column='*'] - Column to count
 * @param {object} [options] - Count options
 * @returns {Promise<number>} Count of related records
 */
count(column?: string, options?: object): Promise<number>;

/**
 * Get related model or collection by name
 * @param {string} relationName - Name of the relation
 * @returns {Model|Collection} Related model or collection
 */
related(relationName: string): Model | Collection;

/**
 * Set automatic timestamp attributes
 * @param {object} [options] - Timestamp options
 * @returns {object} Timestamp attributes object
 */
timestamp(options?: object): object;

Model Definition Example

const User = bookshelf.model('User', {
  // Required: table name
  tableName: 'users',
  
  // Optional: custom primary key
  idAttribute: 'user_id',
  
  // Optional: enable timestamps
  hasTimestamps: true,
  
  // Optional: default values
  defaults: {
    active: true,
    role: 'user'
  },
  
  // Optional: serialization control
  hidden: ['password', 'token'],
  visible: ['id', 'name', 'email', 'created_at'],
  
  // Custom instance methods
  posts() {
    return this.hasMany('Post');
  },
  
  profile() {
    return this.hasOne('Profile');
  },
  
  // Custom validation
  initialize() {
    this.on('saving', this.validateSave);
  },
  
  validateSave(model, attrs, options) {
    if (!attrs.email) {
      throw new Error('Email is required');
    }
  }
}, {
  // Static methods
  findByEmail(email) {
    return this.where('email', email).fetch();
  },
  
  active() {
    return this.where('active', true);
  }
});