@resourcefulColumn
The @resourcefulColumn decorator enhances AdonisJS Lucid column decorators with validation, access control, and metadata functionality. It provides both a generic decorator and type-specific variants for common data types.
For complete API reference, see resourcefulColumn.
Overview
The @resourcefulColumn decorator combines the functionality of Lucid's @column decorator with resourceful features:
- Type Validation: Joi schema validation based on the specified ResourcefulDataType
- Access Control: Field-level read/write permissions
- Data Transformation: Automatic prepare/consume functions for type safety
- OpenAPI Integration: Schema generation for API documentation
- Metadata Storage: Rich metadata for runtime introspection
Basic Usage
Generic Column
import { resourcefulColumn } from '@nhtio/lucid-resourceful'
import { ResourcefulStringType } from '@nhtio/lucid-resourceful/definitions'
class User extends compose(BaseModel, withResourceful({ name: 'User' })) {
@resourcefulColumn({
type: ResourcefulStringType({ minLength: 2, maxLength: 100 }),
nullable: false,
columnName: 'user_name' // Maps to 'user_name' column in database
})
declare name: string
}Primary Key Column
import { ResourcefulUnsignedIntegerType } from '@nhtio/lucid-resourceful/definitions'
@resourcefulColumn({
isPrimary: true,
type: ResourcefulUnsignedIntegerType({ readOnly: true }),
nullable: false
})
declare id: numberType-Specific Variants
String Columns
// Basic string column
@resourcefulColumn.string({
type: ResourcefulStringType({ minLength: 3, maxLength: 255 }),
nullable: false
})
declare name: string
// Email column with validation
@resourcefulColumn.string({
type: ResourcefulStringType({ format: 'email' }),
nullable: false,
serializeAs: 'email_address'
})
declare email: string
// Optional text field
@resourcefulColumn.string({
type: ResourcefulStringType({ maxLength: 1000 }),
nullable: true
})
declare description: string | nullNumeric Columns
// Regular number
@resourcefulColumn.number({
type: ResourcefulNumberType({ min: 0, max: 999.99 }),
nullable: false
})
declare price: number
// Integer
@resourcefulColumn.integer({
type: ResourcefulIntegerType({ min: 18, max: 120 }),
nullable: false
})
declare age: number
// Unsigned integer
@resourcefulColumn.unsignedint({
type: ResourcefulUnsignedIntegerType({ min: 1 }),
nullable: false
})
declare count: number
// BigInt for large numbers
@resourcefulColumn.bigint({
type: ResourcefulBigintType(),
nullable: false
})
declare largeValue: bigintBoolean Columns
@resourcefulColumn.boolean({
type: ResourcefulBooleanType(),
nullable: false,
default: false
})
declare isActive: booleanDate and DateTime Columns
// Date column
@resourcefulColumn.date({
type: ResourcefulDateType(),
nullable: true
})
declare birthDate: Date | null
// DateTime with auto-timestamps
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true,
nullable: false
})
declare createdAt: DateTime
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true,
autoUpdate: true,
nullable: false
})
declare updatedAt: DateTimeBinary Columns
@resourcefulColumn.binary({
type: ResourcefulBinaryType(),
nullable: true
})
declare fileData: Buffer | nullJSON Columns
// JSON object
@resourcefulColumn.object({
type: ResourcefulObjectType({
properties: {
settings: { type: 'object' },
preferences: { type: 'object' }
}
}),
nullable: true
})
declare metadata: Record<string, any> | null
// JSON array
@resourcefulColumn.array({
type: ResourcefulArrayType({
items: { type: 'string' }
}),
nullable: true
})
declare tags: string[] | nullConfiguration Options
Required Options
type
- Type:
ResourcefulDataType - Required: Yes
The ResourcefulDataType instance that defines the field's validation schema and type information. See Data Type Definitions for available types and their configuration options.
@resourcefulColumn({
type: ResourcefulStringType({ minLength: 1, maxLength: 255 })
})
declare name: stringLucid Column Options
All standard Lucid column options are supported:
@resourcefulColumn({
type: ResourcefulStringType(),
columnName: 'custom_column_name', // Database column name
isPrimary: true, // Primary key
serializeAs: 'serialized_name', // Serialization name
meta: { custom: 'metadata' } // Custom metadata
})
declare field: stringResourceful Options
nullable
- Type:
boolean - Default:
false
Whether the field can be null.
@resourcefulColumn.string({
type: ResourcefulStringType(),
nullable: true
})
declare optionalField: string | nulldescription
- Type:
string - Optional: Yes
Description for OpenAPI documentation.
@resourcefulColumn.string({
type: ResourcefulStringType(),
description: 'The user\'s full name'
})
declare name: stringdefault
- Type:
any - Optional: Yes
Default value for the field.
@resourcefulColumn.boolean({
type: ResourcefulBooleanType(),
default: false
})
declare isActive: booleandeprecated
- Type:
boolean - Optional: Yes
Mark the field as deprecated in OpenAPI documentation.
@resourcefulColumn.string({
type: ResourcefulStringType(),
deprecated: true
})
declare oldField: stringexample
- Type:
string - Optional: Yes
Example value for OpenAPI documentation.
@resourcefulColumn.string({
type: ResourcefulStringType(),
example: 'john.doe@example.com'
})
declare email: stringexternalDocs
- Type:
ExternalDocumentationObject - Optional: Yes
External documentation reference.
@resourcefulColumn.string({
type: ResourcefulStringType(),
externalDocs: {
description: 'Email format specification',
url: 'https://tools.ietf.org/html/rfc5322'
}
})
declare email: stringAccess Control
Read Access Control
Control who can read the field value:
@resourcefulColumn.string({
type: ResourcefulStringType(),
readAccessControlFilters: [
// Only the user themselves can read their email
(ctx, app, instance) => ctx.auth.user?.id === instance?.id,
// Or admins can read any email
(ctx) => ctx.auth.user?.role === 'admin'
]
})
declare email: stringWrite Access Control
Control who can modify the field value:
@resourcefulColumn.string({
type: ResourcefulStringType(),
writeAccessControlFilters: [
// Only admins can modify user roles
(ctx) => ctx.auth.user?.role === 'admin'
]
})
declare role: stringCombined Access Control
@resourcefulColumn.string({
type: ResourcefulStringType(),
readAccessControlFilters: [
(ctx, app, instance) => ctx.auth.user?.id === instance?.id || ctx.auth.user?.role === 'admin'
],
writeAccessControlFilters: [
(ctx, app, instance) => ctx.auth.user?.id === instance?.id
]
})
declare personalNote: stringValidation Scoping
Dynamically modify validation based on context:
@resourcefulColumn.string({
type: ResourcefulStringType(),
validationScoper: (schema, ctx, operation) => {
if (operation === 'create') {
// Require minimum length on creation
return schema.min(3)
}
if (ctx.auth.user?.role === 'admin') {
// Admins can use longer strings
return schema.max(500)
}
return schema.max(100)
}
})
declare title: stringDate Column Specific Options
Auto-timestamps
Date and DateTime columns support automatic timestamp management:
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true, // Set on creation
autoUpdate: false, // Don't update on save
nullable: false
})
declare createdAt: DateTime
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true, // Set on creation
autoUpdate: true, // Update on every save
nullable: false
})
declare updatedAt: DateTimeComplete Example
import { DateTime } from 'luxon'
import { BaseModel } from '@adonisjs/lucid/orm'
import { compose } from '@adonisjs/core/helpers'
import { withResourceful, resourcefulColumn } from '@nhtio/lucid-resourceful'
import {
ResourcefulUnsignedIntegerType,
ResourcefulStringType,
ResourcefulBooleanType,
ResourcefulDateTimeType,
ResourcefulObjectType
} from '@nhtio/lucid-resourceful/definitions'
export default class User extends compose(BaseModel, withResourceful({
name: 'User'
})) {
@resourcefulColumn({
isPrimary: true,
type: ResourcefulUnsignedIntegerType({ readOnly: true }),
nullable: false
})
declare id: number
@resourcefulColumn.string({
type: ResourcefulStringType({ minLength: 2, maxLength: 100 }),
nullable: false,
description: 'User\'s full name',
example: 'John Doe'
})
declare name: string
@resourcefulColumn.string({
type: ResourcefulStringType({ format: 'email' }),
nullable: false,
description: 'User\'s email address',
readAccessControlFilters: [
(ctx, app, user) => ctx.auth.user?.id === user?.id || ctx.auth.user?.role === 'admin'
],
writeAccessControlFilters: [
(ctx, app, user) => ctx.auth.user?.id === user?.id
]
})
declare email: string
@resourcefulColumn.boolean({
type: ResourcefulBooleanType(),
nullable: false,
default: true,
writeAccessControlFilters: [
(ctx) => ctx.auth.user?.role === 'admin'
]
})
declare isActive: boolean
@resourcefulColumn.object({
type: ResourcefulObjectType(),
nullable: true,
description: 'User preferences and settings',
readAccessControlFilters: [
(ctx, app, user) => ctx.auth.user?.id === user?.id
]
})
declare preferences: Record<string, any> | null
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true,
nullable: false
})
declare createdAt: DateTime
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
autoCreate: true,
autoUpdate: true,
nullable: false
})
declare updatedAt: DateTime
}Common Patterns
Audit Fields
@resourcefulColumn.string({
type: ResourcefulStringType(),
nullable: true,
readAccessControlFilters: [(ctx) => ctx.auth.user?.role === 'admin']
})
declare createdBy: string | null
@resourcefulColumn.string({
type: ResourcefulStringType(),
nullable: true,
readAccessControlFilters: [(ctx) => ctx.auth.user?.role === 'admin']
})
declare updatedBy: string | nullSoft Deletes
@resourcefulColumn.dateTime({
type: ResourcefulDateTimeType(),
nullable: true,
serializeAs: null, // Don't serialize in responses
writeAccessControlFilters: [(ctx) => ctx.auth.user?.role === 'admin']
})
declare deletedAt: DateTime | nullMulti-tenant Fields
@resourcefulColumn.unsignedint({
type: ResourcefulUnsignedIntegerType(),
nullable: false,
serializeAs: null, // Don't expose in API
writeAccessControlFilters: [() => false] // Never allow direct writes
})
declare tenantId: numberBest Practices
- Always specify nullable: Be explicit about whether fields can be null
- Use appropriate types: Choose the most specific ResourcefulDataType for your use case
- Secure sensitive fields: Use access control filters for sensitive information
- Provide descriptions: Add descriptions for better API documentation
- Use validation scoping: Implement context-aware validation when needed
- Consider serialization: Use
serializeAsto control API field names - Implement audit trails: Add audit fields for tracking changes