Utilities
Lucid Resourceful provides a comprehensive set of utilities for data type casting, preparation, consumption, and type checking through the @nhtio/lucid-resourceful/utils module. These utilities are essential for ensuring data integrity and type safety when working with database operations and API interactions.
Overview
The utilities module is organized into four main namespaces:
casters- Type casting utilities for converting unknown values to specific typespreparers- Data preparation utilities for database storageconsumers- Data consumption utilities for retrieving values from database resultsguards- Type guard utilities for runtime type checking
import { casters, preparers, consumers, guards } from '@nhtio/lucid-resourceful/utils'
// Cast unknown values to specific types
const stringValue = casters.castValueAsString(unknownValue)
// Prepare values for database storage
const preparedValue = preparers.prepareString('name', inputValue, false)
// Consume values from database results
const consumedValue = consumers.consumeString('name', dbValue, true)
// Check types at runtime
if (guards.isObject(value)) {
// value is guaranteed to be an object
}Casters
The casters namespace provides utilities for converting unknown values to specific data types with comprehensive error handling. These functions are primarily used internally by Lucid Resourceful but are available for custom data processing needs.
Available Casters
All caster functions throw E_UNCASTABLE errors when values cannot be cast to the target type.
String Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
// Cast values to string
const result = casters.castValueAsString('hello') // 'hello'
const result2 = casters.castValueAsString(123) // '123'
// Throws E_UNCASTABLE for incompatible types
try {
casters.castValueAsString({ key: 'value' })
} catch (error) {
// E_UNCASTABLE: Cannot cast value to String
}Numeric Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
// Cast to number
const num = casters.castValueAsNumber('123.45') // 123.45
const num2 = casters.castValueAsNumber(456) // 456
// Cast to integer (truncated)
const int = casters.castValueAsInteger(123.89) // 123
const int2 = casters.castValueAsInteger('456.78') // 456
// Cast to bigint
const big = casters.castValueAsBigint('123') // 123n
const big2 = casters.castValueAsBigint(456) // 456n
// Cast to unsigned integer (32-bit)
const uint = casters.castValueAsUnsignedInt(-5) // 4294967291 (wrapped)
const uint2 = casters.castValueAsUnsignedInt('123') // 123Date and Time Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
import { DateTime } from 'luxon'
// Cast to Luxon DateTime with enhanced parsing
const date1 = casters.castValueAsDate('2023-12-25') // From SQL format
const date2 = casters.castValueAsDate('2023-12-25T10:30:00Z') // From ISO format
const date3 = casters.castValueAsDate(1703505000) // From Unix timestamp
const date4 = casters.castValueAsDate(new Date()) // From JS Date
const date5 = casters.castValueAsDate(DateTime.now()) // From Luxon DateTime
// castValueAsDateTime is an alias for castValueAsDate with enhanced error messages
const dateTime = casters.castValueAsDateTime('2023-12-25T10:30:00Z')Boolean Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
// Cast to boolean with flexible string parsing
const bool1 = casters.castValueAsBoolean(true) // true
const bool2 = casters.castValueAsBoolean('true') // true
const bool3 = casters.castValueAsBoolean('1') // true
const bool4 = casters.castValueAsBoolean('false') // false
const bool5 = casters.castValueAsBoolean('0') // false
const bool6 = casters.castValueAsBoolean(1) // true
const bool7 = casters.castValueAsBoolean(0) // false
// Case insensitive string parsing
const bool8 = casters.castValueAsBoolean('TRUE') // true
const bool9 = casters.castValueAsBoolean('False') // falseBinary Data Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
// Cast to binary data (Uint8Array or Buffer)
const buffer = Buffer.from('hello')
const uint8Array = new Uint8Array([72, 101, 108, 108, 111])
const binary1 = casters.castValueAsBinary(buffer) // Buffer
const binary2 = casters.castValueAsBinary(uint8Array) // Uint8Array
// Throws E_UNCASTABLE for non-binary data
try {
casters.castValueAsBinary('not binary')
} catch (error) {
// E_UNCASTABLE: Cannot cast value to Binary
}Object and Array Casting
import { casters } from '@nhtio/lucid-resourceful/utils'
// Cast to plain object
const obj = casters.castValueAsObject({ name: 'John', age: 30 })
// Result: { name: 'John', age: 30 }
// Cast to array
const arr = casters.castValueAsArray([1, 2, 3, 'hello'])
// Result: [1, 2, 3, 'hello']
// Throws E_UNCASTABLE for incompatible types
try {
casters.castValueAsObject('not an object')
} catch (error) {
// E_UNCASTABLE: Cannot cast value to Object
}Complete Caster Reference
| Function | Input Types | Output Type | Description |
|---|---|---|---|
castValueAsString | string, number | string | Converts values to string representation |
castValueAsDate | string, number, Date, DateTime | DateTime | Converts values to Luxon DateTime with enhanced parsing |
castValueAsDateTime | string, number, Date, DateTime | DateTime | Alias for castValueAsDate with enhanced error handling |
castValueAsBinary | Uint8Array, Buffer | Uint8Array | Converts binary data to Uint8Array |
castValueAsNumber | number, string | number | Converts values to numeric type |
castValueAsInteger | number, string | number | Converts values to integer (truncated) |
castValueAsBigint | bigint, number, string | bigint | Converts values to bigint type |
castValueAsUnsignedInt | number, bigint, string | number | Converts values to 32-bit unsigned integer |
castValueAsBoolean | boolean, string, number | boolean | Converts values to boolean with flexible parsing |
castValueAsObject | object | LucidPlainObject | Converts values to plain object |
castValueAsArray | Array<unknown> | Array<unknown> | Converts values to array type |
Preparers
The preparers namespace provides utilities for preparing values before they are stored in the database. These functions include nullable support and comprehensive error handling for data validation.
Nullable Support
All preparer functions support nullable fields through overloaded signatures:
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Non-nullable field - returns string, throws on invalid input
const required: string = preparers.prepareString('name', 'John', false)
// Nullable field - returns string | null, returns null for null input
const optional: string | null = preparers.prepareString('nickname', null, true)Preparation Error Handling
Preparer functions throw E_INVALID_PREPARED_VALUE errors when values cannot be prepared for database storage, providing the field name and expected type for debugging.
String Preparation
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Prepare string values with nullable support
const name = preparers.prepareString('name', 'John Doe', false) // 'John Doe'
const nickname = preparers.prepareString('nickname', null, true) // null
const title = preparers.prepareString('title', 123, false) // '123' (converted)
// Error handling for invalid values
try {
preparers.prepareString('name', { invalid: 'object' }, false)
} catch (error) {
// E_INVALID_PREPARED_VALUE: Cannot prepare field 'name' as String
}Numeric Preparation
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Prepare numeric values
const age = preparers.prepareNumber('age', '25', false) // 25
const score = preparers.prepareNumber('score', null, true) // null
const count = preparers.prepareInteger('count', 25.7, false) // 25 (truncated)
const id = preparers.prepareBigint('id', '12345', false) // 12345n
const flags = preparers.prepareUnsignedint('flags', -1, false) // 4294967295 (wrapped)Date and Time Preparation
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Prepare date/time values with enhanced parsing
const created = preparers.prepareDate('createdAt', '2023-12-25', false)
const updated = preparers.prepareDateTime('updatedAt', new Date(), false)
const deleted = preparers.prepareDate('deletedAt', null, true) // null
// Supports multiple input formats
const date1 = preparers.prepareDate('date', '2023-12-25T10:30:00Z', false) // ISO format
const date2 = preparers.prepareDate('date', '2023-12-25 10:30:00', false) // SQL format
const date3 = preparers.prepareDate('date', 1703505000, false) // Unix timestampBoolean and Binary Preparation
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Prepare boolean values with flexible parsing
const active = preparers.prepareBoolean('active', 'true', false) // true
const verified = preparers.prepareBoolean('verified', 1, false) // true
const deleted = preparers.prepareBoolean('deleted', null, true) // null
// Prepare binary data
const avatar = preparers.prepareBinary('avatar', buffer, false)
const signature = preparers.prepareBinary('signature', null, true) // nullObject and Array Preparation
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Prepare complex data types
const metadata = preparers.prepareObject('metadata', { version: 1 }, false)
const tags = preparers.prepareArray('tags', ['tag1', 'tag2'], false)
const config = preparers.prepareObject('config', null, true) // nullComplete Preparer Reference
| Function | Input Types | Nullable Support | Description |
|---|---|---|---|
prepareString | unknown | ✅ | Prepares string values for database storage |
prepareDate | unknown | ✅ | Prepares date values with enhanced parsing |
prepareDateTime | unknown | ✅ | Prepares datetime values with enhanced parsing |
prepareBinary | unknown | ✅ | Prepares binary data for storage |
prepareNumber | unknown | ✅ | Prepares numeric values for storage |
prepareInteger | unknown | ✅ | Prepares integer values (truncated) |
prepareBigint | unknown | ✅ | Prepares bigint values for storage |
prepareUnsignedint | unknown | ✅ | Prepares unsigned integer values |
prepareBoolean | unknown | ✅ | Prepares boolean values with flexible parsing |
prepareObject | unknown | ✅ | Prepares object values for storage |
prepareArray | unknown | ✅ | Prepares array values for storage |
Consumers
The consumers namespace provides utilities for safely consuming values from database results. These functions ensure that data retrieved from the database is properly typed and validated before use in your application.
Database Result Processing
Consumer functions are essential when working with raw database results where type safety is not guaranteed:
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Process database results safely
async function processUserRecord(dbResult: any) {
const id = consumers.consumeNumber('id', dbResult.id, false)
const name = consumers.consumeString('name', dbResult.name, false)
const email = consumers.consumeString('email', dbResult.email, true) // nullable
const createdAt = consumers.consumeDate('created_at', dbResult.created_at, false)
return { id, name, email, createdAt }
}Consumption Error Handling
Consumer functions throw E_INVALID_CONSUMED_VALUE errors when database values cannot be consumed as expected types:
import { consumers } from '@nhtio/lucid-resourceful/utils'
try {
const age = consumers.consumeNumber('age', 'not a number', false)
} catch (error) {
// E_INVALID_CONSUMED_VALUE: Cannot consume field 'age' as Number
console.log(`Failed to process field: ${error.field}`)
console.log(`Expected type: ${error.expectedType}`)
}String Consumption
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Consume string values from database results
const title = consumers.consumeString('title', dbResult.title, false)
const description = consumers.consumeString('description', dbResult.description, true)
// Handles type conversion for compatible types
const id = consumers.consumeString('id', 123, false) // '123'Numeric Consumption
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Consume various numeric types
const price = consumers.consumeNumber('price', dbResult.price, false)
const quantity = consumers.consumeInteger('quantity', dbResult.quantity, false)
const userId = consumers.consumeBigint('user_id', dbResult.user_id, false)
const flags = consumers.consumeUnsignedint('flags', dbResult.flags, true)
// Handles string-to-number conversion
const count = consumers.consumeNumber('count', '42', false) // 42Date and Time Consumption
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Consume date/time values with enhanced parsing
const created = consumers.consumeDate('created_at', dbResult.created_at, false)
const updated = consumers.consumeDateTime('updated_at', dbResult.updated_at, true)
// Supports multiple database date formats
const date1 = consumers.consumeDate('date', '2023-12-25 10:30:00', false) // SQL format
const date2 = consumers.consumeDate('date', '2023-12-25T10:30:00Z', false) // ISO format
const date3 = consumers.consumeDate('date', 1703505000, false) // Unix timestampBoolean and Binary Consumption
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Consume boolean values with flexible parsing
const active = consumers.consumeBoolean('is_active', dbResult.is_active, false)
const verified = consumers.consumeBoolean('verified', '1', false) // true
// Consume binary data
const avatar = consumers.consumeBinary('avatar', dbResult.avatar, true)
const thumbnail = consumers.consumeBinary('thumbnail', buffer, false)Complex Data Consumption
import { consumers } from '@nhtio/lucid-resourceful/utils'
// Consume JSON/object fields
const metadata = consumers.consumeObject('metadata', dbResult.metadata, true)
const settings = consumers.consumeObject('settings', '{"theme": "dark"}', false)
// Consume array fields
const tags = consumers.consumeArray('tags', dbResult.tags, false)
const permissions = consumers.consumeArray('permissions', JSON.parse(dbResult.permissions), true)Complete Consumer Reference
| Function | Return Type | Nullable Support | Description |
|---|---|---|---|
consumeString | string | null | ✅ | Safely consumes string values from database |
consumeDate | DateTime | null | ✅ | Consumes date values with enhanced parsing |
consumeDateTime | DateTime | null | ✅ | Consumes datetime values with enhanced parsing |
consumeBinary | LucidBinaryValue | null | ✅ | Consumes binary data from database |
consumeNumber | number | null | ✅ | Consumes numeric values from database |
consumeInteger | number | null | ✅ | Consumes integer values (truncated) |
consumeBigint | bigint | null | ✅ | Consumes bigint values from database |
consumeUnsignedint | number | null | ✅ | Consumes unsigned integer values |
consumeBoolean | boolean | null | ✅ | Consumes boolean values with flexible parsing |
consumeObject | LucidPlainObject | null | ✅ | Consumes object/JSON values from database |
consumeArray | Array<unknown> | null | ✅ | Consumes array/JSON values from database |
Guards
The guards namespace provides type guard utilities for runtime type checking. These functions help ensure type safety when working with unknown values and are extensively used throughout Lucid Resourceful.
Basic Type Guards
import { guards } from '@nhtio/lucid-resourceful/utils'
// Check for basic types
if (guards.isObject(value)) {
// TypeScript knows value is { [key: string]: unknown }
console.log(value.someProperty)
}
if (guards.isArray(value)) {
// TypeScript knows value is unknown[]
console.log(value.length)
}Luxon DateTime Detection
import { guards } from '@nhtio/lucid-resourceful/utils'
import { DateTime } from 'luxon'
// Safely check for Luxon DateTime instances
if (guards.isLuxonDateTime(value)) {
// TypeScript knows value is DateTime
console.log(value.toISO())
console.log(value.isValid)
}
// Works with actual DateTime instances
const now = DateTime.now()
console.log(guards.isLuxonDateTime(now)) // trueBinary Data Detection
import { guards } from '@nhtio/lucid-resourceful/utils'
// Check for binary data (Uint8Array or Buffer)
if (guards.isLucidBinaryValue(value)) {
// TypeScript knows value is Uint8Array or Buffer
console.log(value.byteLength)
}
// Works with both Uint8Array and Buffer
const uint8Array = new Uint8Array([1, 2, 3])
const buffer = Buffer.from('hello')
console.log(guards.isLucidBinaryValue(uint8Array)) // true
console.log(guards.isLucidBinaryValue(buffer)) // true
console.log(guards.isLucidBinaryValue('string')) // falseInstance Type Checking
import { guards } from '@nhtio/lucid-resourceful/utils'
// Check if value is instance of specific class
class CustomClass {
customMethod() {
return 'custom'
}
}
const instance = new CustomClass()
// Using constructor with type parameter
if (guards.isInstanceOf<CustomClass>(instance, 'CustomClass', CustomClass)) {
// TypeScript knows instance is CustomClass
console.log(instance.customMethod())
}
// Using class name only with generic type
if (guards.isInstanceOf<CustomClass>(instance, 'CustomClass')) {
// More flexible checking without constructor reference
// TypeScript knows instance is CustomClass
console.log(instance.customMethod())
}
// Practical example with unknown value
function processValue(value: unknown) {
if (guards.isInstanceOf<Date>(value, 'Date')) {
// TypeScript knows value is Date
console.log(value.getTime())
console.log(value.toISOString())
}
}ResourcefulModel Detection
import { guards } from '@nhtio/lucid-resourceful/utils'
// Check if value is a ResourcefulModel
if (guards.isResourcefulModel(value)) {
// TypeScript knows value has resourceful properties
console.log(value.$resourcefulName)
console.log(value.$resourcefulColumns)
console.log(value.$resourcefulRelationships)
}Practical Usage Examples
Safe Property Access
import { guards } from '@nhtio/lucid-resourceful/utils'
function processData(data: unknown) {
if (guards.isObject(data)) {
// Safe to access object properties
const name = guards.isString(data.name) ? data.name : 'Unknown'
const age = guards.isNumber(data.age) ? data.age : 0
return { name, age }
}
throw new Error('Expected object data')
}Database Result Validation
import { guards } from '@nhtio/lucid-resourceful/utils'
function validateUserRecord(record: unknown) {
if (!guards.isObject(record)) {
throw new Error('Invalid user record format')
}
const errors: string[] = []
if (!guards.isNumber(record.id)) {
errors.push('Missing or invalid user ID')
}
if (!guards.isString(record.email)) {
errors.push('Missing or invalid email')
}
if (record.created_at && !guards.isLuxonDateTime(record.created_at)) {
errors.push('Invalid creation date format')
}
if (errors.length > 0) {
throw new Error(`Validation failed: ${errors.join(', ')}`)
}
return record
}Type-Safe Data Processing
import { guards } from '@nhtio/lucid-resourceful/utils'
function processApiResponse(response: unknown) {
if (!guards.isObject(response)) {
throw new Error('Invalid API response')
}
const result: any = {}
// Process string fields
if (guards.isString(response.name)) {
result.name = response.name
}
// Process array fields
if (guards.isArray(response.tags)) {
result.tags = response.tags.filter(guards.isString)
}
// Process nested objects
if (guards.isObject(response.metadata)) {
result.metadata = response.metadata
}
return result
}Complete Guards Reference
| Function | Type Guard | Description |
|---|---|---|
isLuxonDateTime | DateTime | Checks if value is a Luxon DateTime instance |
isLucidBinaryValue | LucidBinaryValue | Checks if value is binary data (Uint8Array or Buffer) |
isObject | { [key: string]: unknown } | Checks if value is a plain object (not null, not array) |
isArray | unknown[] | Checks if value is an array |
isInstanceOf | T | Checks if value is instance of specific class |
isResourcefulModel | ResourcefulModel | Checks if value is a ResourcefulModel instance |
Best Practices
Utility Error Handling
Always handle potential casting and preparation errors appropriately:
import { casters, preparers } from '@nhtio/lucid-resourceful/utils'
import { errors } from '@nhtio/lucid-resourceful'
try {
const value = casters.castValueAsNumber(userInput)
const prepared = preparers.prepareNumber('score', value, false)
} catch (error) {
if (errors.isInstanceOf.E_UNCASTABLE(error)) {
console.log(`Cannot cast to ${error.expectedTypes.join(' or ')}`)
} else if (errors.isInstanceOf.E_INVALID_PREPARED_VALUE(error)) {
console.log(`Invalid ${error.expectedType} for field '${error.field}'`)
}
}Type Safety
Use type guards to ensure type safety in dynamic code:
import { guards, consumers } from '@nhtio/lucid-resourceful/utils'
function processApiData(data: unknown) {
if (!guards.isObject(data)) {
throw new Error('Expected object data')
}
// Now safely access properties with proper type checking
const id = guards.isNumber(data.id)
? data.id
: consumers.consumeNumber('id', data.id, false)
}Performance Considerations
- Caching: Consider caching type-checked results for frequently accessed data
- Early Validation: Use guards early in data processing pipelines to fail fast
- Batch Processing: Group similar type operations together for better performance
Integration with Resourceful
These utilities integrate seamlessly with Lucid Resourceful's data type system:
import { ResourcefulStringType } from '@nhtio/lucid-resourceful/definitions'
import { preparers } from '@nhtio/lucid-resourceful/utils'
// Custom data processing using preparers
function customStringHandler(fieldName: string, value: unknown, nullable: boolean) {
const prepared = preparers.prepareString(fieldName, value, nullable)
// Additional custom processing
if (prepared && prepared.length > 255) {
throw new Error(`Field '${fieldName}' exceeds maximum length`)
}
return prepared
}Related Documentation
- Data Type Definitions - Learn about resourceful data types that use these utilities
- Decorators - Understanding how decorators leverage these utilities internally
- Error Handling - Complete reference for utility-related errors
- Validation - How validation integrates with utility functions
API Reference
For complete type definitions and method signatures, see:
@nhtio/lucid-resourceful/utils- Main utilities moduleLucidBinaryValue- Binary data type definitionLucidPlainObject- Plain object type definitionE_UNCASTABLE- Casting error referenceE_INVALID_PREPARED_VALUE- Preparation error referenceE_INVALID_CONSUMED_VALUE- Consumption error reference