Scalar Constant Implementation Guide

Scalar constants serve as foundational building blocks for complex data modeling in Akan.js applications. They define reusable value objects that can be embedded in other models without creating separate database collections.
File Structure and Location
Scalar constants follow strict naming conventions and directory structure:
# File location convention
{app,lib}/
└── */lib/__scalar/
    └── <scalarName>/               # camelCase directory
        └── <scalarName>.constant.ts  # scalar definition file
        
ElementConventionExample
Directory
camelCase
geoLocation
File
<scalarName>.constant.ts
geoLocation.constant.ts
Class
PascalCase
GeoLocation
Enum Values
camelCase
active, pendingApproval
Model Definition
Scalar models follow a strict single-responsibility pattern with essential decorators:
import { Field, Model } from "@akanjs/constant";
@Model.Scalar("ScalarName") // Must match class name exactly
export class ScalarName {
  @Field.Prop(() => FieldType, { ...options })
  fieldName: FieldType;
}
        
Critical: The string passed to @Model.Scalar() must match the class name exactly
Field Definitions
Field definitions support various types with configurable validation options:
// Basic field types
@Field.Prop(() => String)
name: string;
@Field.Prop(() => Int)
quantity: number;
@Field.Prop(() => Float)
percentage: number;
@Field.Prop(() => Boolean)
isActive: boolean;
@Field.Prop(() => Date)
timestamp: Dayjs;  // Always use Dayjs for dates
// Special field types
@Field.Hidden(() => String)
internalCode: string;
@Field.Secret(() => String)
apiKey: string;
@Field.Resolve(() => Int)
get total(): number {
  return this.items.length;
}
        
Field Options
default:Any:undefined

Default field value

{ default: 0 }
nullable:Boolean:false

Allows null values

{ nullable: true }
enum:Enum:-

Restricts to enum values

{ enum: Status }
min:Number:-

Minimum numeric value

{ min: 0 }
max:Number:-

Maximum numeric value

{ max: 100 }
minlength:Number:-

Minimum string length

{ minlength: 3 }
maxlength:Number:-

Maximum string length

{ maxlength: 255 }
example:Any:-

Example value for documentation

{ example: [0,0] }
validate:Function:-

Custom validation function

{ validate: (v) => v > 0 }
immutable:Boolean:false

Prevents modification after creation

{ immutable: true }
select:Boolean:true

Includes in query results by default

{ select: false }
text:String:-

Enables text search capabilities

{ text: 'search' }
Complex Field Types
Scalar constants support advanced field types for complex data structures:
// Array fields
@Field.Prop(() => [String])
tags: string[];
@Field.Prop(() => [[Int]])
matrix: number[][];
@Field.Prop(() => [OtherScalar])
items: OtherScalar[];
// Map fields
@Field.Prop(() => Map, {
  of: String,  // Must specify value type
  default: new Map()
})
metadata: Map<string, string>;
// Enum implementation (camelCase values)
export const Status = enumOf(["active", "inactive"] as const);
export type Status = enumOf<typeof Status>;
@Field.Prop(() => String, {
  enum: Status,
  default: "active"
})
status: Status;
        
Static Methods
Add utility methods directly to scalar classes for domain-specific operations:
@Model.Scalar("Coordinate")
export class Coordinate {
  @Field.Prop(() => [Float], { default: [0, 0] })
  coordinates: number[];
  // Calculate distance between coordinates
  static getDistanceKm(loc1: Coordinate, loc2: Coordinate) {
    const [lon1, lat1] = loc1.coordinates;
    const [lon2, lat2] = loc2.coordinates;
    // Distance calculation logic
    return distance;
  }
}
        
Common Mistakes
IssueWrongCorrect
Incorrect Enum Case
enumOf(['ACTIVE', 'INACTIVE'])
enumOf(['active', 'inactive'])
Incorrect Array Syntax
() => Array<Int>
() => [Int]
Missing Nullable Type
description: string;
description: string | null;
Improper Enum Implementation
const Status = enumOf(['active'])
export const Status = enumOf(['active'])
Multiple Models
Multiple @Model.Scalar per file
Single scalar per file
Incorrect Date Handling
createdAt: Date;
createdAt: Dayjs;
Full Examples
Practical implementations demonstrating various scalar patterns:
// Basic scalar example
@Model.Scalar("Amount")
export class Amount {
  @Field.Prop(() => Float, { min: 0, default: 0 })
  value: number;
  @Field.Prop(() => String, { default: "USD" })
  currency: string;
}
// Complex scalar with enums
@Model.Scalar("GeoLocation")
export class GeoLocation {
  @Field.Prop(() => Float, { min: -90, max: 90 })
  latitude: number;
  
  @Field.Prop(() => Float, { min: -180, max: 180 })
  longitude: number;
  
  @Field.Prop(() => String, { 
    enum: AccuracyLevel,
    default: "medium" 
  })
  accuracy: AccuracyLevel;
}
// Scalar with nested objects
@Model.Scalar("ProductSpec")
export class ProductSpec {
  @Field.Prop(() => String)
  sku: string;
  
  @Field.Prop(() => [String], { default: [] })
  colors: string[];
  
  @Field.Prop(() => Dimension)
  size: Dimension;
}
        
Implementation Checklist
  • Location: __scalar/<camelCase>/<camelCase>.constant.ts
  • Structure: Single @Model.Scalar class per file
  • Naming: Class name = PascalCase directory name
  • Decorator: @Model.Scalar('ClassName') with exact match
  • Enum Values: Always camelCase (active, not ACTIVE)
  • Fields: Use @Field.Prop with arrow function types
  • Arrays: Wrap in [] (e.g., [Int])
  • Enums: Export with enumOf and derived type
  • Dates: Always use Dayjs type with Date decorator
  • Nullability: Use | null with { nullable: true }
  • Validation: Implement field-level constraints
Tip: Scalar constants are value objects - they should not contain ID or timestamp fields
Released under the MIT License
Official Akan.js Consulting onAkansoft
Copyright © 2025 Akan.js. All rights reserved.
System managed bybassman