Models API

The Models API (dcupl.models) provides methods for managing data model definitions in dcupl. Models define the structure, types, and relationships of your data.

Methods

set()

Sets or replaces a model definition. If a model with the same key exists, it will be replaced.

Signature:

set(model: ModelDefinition): void

Parameters:

Parameter Type Required Description
model ModelDefinition Yes The model definition to set

Examples:

Basic model
dcupl.models.set({
  key: 'Product',
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
  ],
});
Model with references
dcupl.models.set({
  key: 'Product',
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
  ],
  references: [{ key: 'category', type: 'singleValued', model: 'Category' }],
});
Complete model with all options
dcupl.models.set({
  key: 'Product',
  keyProperty: 'id',
  autoGenerateKey: false,
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
    { key: 'tags', type: 'Array<string>', separator: ',' },
  ],
  references: [{ key: 'category', type: 'singleValued', model: 'Category' }],
  quality: {
    enabled: true,
    attributes: {
      required: true,
    },
  },
});

update()

Updates an existing model definition, merging with existing properties.

Signature:

update(model: ModelDefinition): void

Parameters:

Parameter Type Required Description
model ModelDefinition Yes The model definition to merge

Examples:

Update existing model
dcupl.models.update({
  key: 'Product',
  properties: [{ key: 'description', type: 'string' }],
});
Add reference to existing model
dcupl.models.update({
  key: 'Product',
  references: [{ key: 'manufacturer', type: 'singleValued', model: 'Manufacturer' }],
});

get()

Retrieves a model definition by key.

Signature:

get(modelKey: string): ModelDefinition | undefined

Parameters:

Parameter Type Required Description
modelKey string Yes The key of the model to retrieve

Returns: ModelDefinition | undefined - The model definition or undefined if not found

Examples:

Get a model
const model = dcupl.models.get('Product');
if (model) {
  console.log(model.properties);
  console.log(model.references);
}
Check if model exists
const exists = dcupl.models.get('Product') !== undefined;
Access model properties
const model = dcupl.models.get('Product');
if (model) {
  const properties = model.properties || [];
  const references = model.references || [];
}

remove()

Removes a model definition by key.

Signature:

remove(modelKey: string): void

Parameters:

Parameter Type Required Description
modelKey string Yes The key of the model to remove

Examples:

Remove a model
dcupl.models.remove('Product');
Remove multiple models
['Product', 'Category', 'Tag'].forEach((key) => {
  dcupl.models.remove(key);
});

keys()

Returns an array of all model keys.

Signature:

keys(): string[]

Returns: string[] - Array of model keys

Examples:

Get all model keys
const modelKeys = dcupl.models.keys();
console.log(modelKeys); // ['Product', 'Category', 'Tag']
Check if a model exists
const hasProduct = dcupl.models.keys().includes('Product');
Count models
const modelCount = dcupl.models.keys().length;

Type Definitions

ModelDefinition

Defines the structure of a data model.

Type Definition:

type ModelDefinition<ModelNames extends string = string> = {
  key: ModelNames;
  properties?: Property[];
  references?: Reference[];
  data?: RawItem[];
  keyProperty?: string;
  autoGenerateKey?: boolean;
  autoGenerateProperties?: boolean;
  supportsAutoCreation?: boolean;
  valueMappings?: ValueMappingConfig[];
  meta?: ModelMetadata;
  quality?: ModelQualityConfig;
};

Properties:

Property Type Description
key string Unique model identifier
properties Property[] Array of property definitions
references Reference[] Array of reference definitions
data RawItem[] Optional inline data for the model
keyProperty string Property to use as item key (default: 'key')
autoGenerateKey boolean Auto-generate unique keys for items without one (default: false)
autoGenerateProperties boolean Infer property definitions from data structure (default: false)
supportsAutoCreation boolean Allow automatic item creation when referenced by other models (default: false)
valueMappings ValueMappingConfig[] Transform values during data loading
meta ModelMetadata Arbitrary metadata attached to the model
quality ModelQualityConfig Quality validation configuration

Examples:

Minimal model
const model: ModelDefinition = {
  key: 'Product',
  properties: [{ key: 'name', type: 'string' }],
};
Complete model
const model: ModelDefinition = {
  key: 'Product',
  keyProperty: 'productId',
  autoGenerateKey: false,
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
    { key: 'createdAt', type: 'date', inputFormat: 'yyyy-MM-dd' },
  ],
  references: [
    { key: 'category', type: 'singleValued', model: 'Category' },
    { key: 'tags', type: 'multiValued', model: 'Tag' },
  ],
  quality: {
    enabled: true,
    attributes: {
      required: true,
    },
  },
};

Model Options

keyProperty

Specifies which property in your data should be used as the unique item identifier. By default, dcupl looks for a property named key.

Using a custom key property
const model: ModelDefinition = {
  key: 'Product',
  keyProperty: 'productId', // Use 'productId' instead of 'key'
  properties: [
    { key: 'productId', type: 'string' },
    { key: 'name', type: 'string' },
  ],
};

// Data can now use 'productId' as the identifier
dcupl.data.set(
  [
    { productId: 'SKU-001', name: 'Widget' },
    { productId: 'SKU-002', name: 'Gadget' },
  ],
  { model: 'Product' }
);

autoGenerateKey

When true, dcupl generates a unique 10-character key for items that don't have one. Useful when your data doesn't have natural identifiers.

Auto-generating keys
const model: ModelDefinition = {
  key: 'LogEntry',
  autoGenerateKey: true,
  properties: [
    { key: 'message', type: 'string' },
    { key: 'timestamp', type: 'date' },
  ],
};

// Data without keys - dcupl generates them automatically
dcupl.data.set(
  [
    { message: 'User logged in', timestamp: '2025-01-15' },
    { message: 'User logged out', timestamp: '2025-01-15' },
  ],
  { model: 'LogEntry' }
);

// Items will have auto-generated keys like 'a8f3k2m9x1'

autoGenerateProperties

When true, dcupl infers property definitions from the data structure. Useful for quick prototyping or when working with dynamic data.

Auto-generating properties
const model: ModelDefinition = {
  key: 'DynamicData',
  autoGenerateProperties: true,
  // No properties defined - they will be inferred from data
};

dcupl.data.set([{ key: 'item1', name: 'Test', count: 42, active: true }], { model: 'DynamicData' });

// Properties 'name', 'count', 'active' are automatically created

supportsAutoCreation

When true, items are automatically created in this model when referenced by other models. This is useful for lookup tables or reference data that might be incomplete.

Auto-creation of referenced items
const productModel: ModelDefinition = {
  key: 'Product',
  references: [{ key: 'category', type: 'singleValued', model: 'Category' }],
  data: [
    { key: 'p1', category: 'electronics' },
    { key: 'p2', category: 'books' },
  ],
};

const categoryModel: ModelDefinition = {
  key: 'Category',
  supportsAutoCreation: true, // Categories created automatically
  properties: [{ key: 'name', type: 'string' }],
};

// After init, 'electronics' and 'books' exist in Category model
// even though no Category data was explicitly provided

valueMappings

Transform values during data loading. Useful for normalizing data, handling special values, or converting between formats.

Type Definition:

type ValueMappingConfig = {
  attributes: string[]; // Properties/references to apply mapping to
  values: {
    from: (string | '$dcupl_falsy')[]; // Values to match
    to: any; // Replacement value
  }[];
};
Mapping falsy values to a default
const model: ModelDefinition = {
  key: 'Product',
  valueMappings: [
    {
      attributes: ['category', 'brand'],
      values: [
        {
          from: ['$dcupl_falsy'], // Matches undefined, null, empty string
          to: 'uncategorized',
        },
      ],
    },
  ],
  references: [
    { key: 'category', type: 'singleValued', model: 'Category' },
    { key: 'brand', type: 'singleValued', model: 'Brand' },
  ],
};
Converting string values to boolean
const model: ModelDefinition = {
  key: 'Product',
  valueMappings: [
    {
      attributes: ['inStock'],
      values: [
        { from: ['Yes', 'yes', 'Y', '1'], to: true },
        { from: ['No', 'no', 'N', '0'], to: false },
      ],
    },
  ],
  properties: [{ key: 'inStock', type: 'boolean' }],
};

meta

Attach arbitrary metadata to the model for documentation or application-specific purposes.

Model with metadata
const model: ModelDefinition = {
  key: 'Product',
  meta: {
    name: 'Product Catalog',
    description: 'All products available for sale',
    version: '2.0',
    maintainer: 'catalog-team@example.com',
  },
  properties: [{ key: 'name', type: 'string' }],
};

// Access metadata
const productModel = dcupl.models.get('Product');
console.log(productModel?.meta?.description);

Property

Defines a property (field) in a model.

Type Definition:

type Property =
  | PropertyString
  | PropertyStringArray
  | PropertyInt
  | PropertyIntArray
  | PropertyFloat
  | PropertyFloatArray
  | PropertyDate
  | PropertyDateArray
  | PropertyJson
  | PropertyBoolean
  | PropertyAny;

Common Properties:

Property Type Description
key string Unique property identifier
type PropertyType Data type of the property
index boolean Create index for this property
expression string Computed property expression
derive DeriveConfig Derive value from reference
quality AttributeQualityConfig Validation rules

Property Types:

Type Description
'string' Text values
'Array' Array of text values
'int' Integer numbers
'Array' Array of integers
'float' Floating point numbers
'Array' Array of floats
'date' Date/time values
'Array' Array of dates
'boolean' Boolean values
'json' JSON objects
'any' Any type

Examples:

String property
{
  key: 'name',
  type: 'string'
}
Number with fractionDigits
{
  key: 'price',
  type: 'float',
  fractionDigits: 2
}
Array property
{
  key: 'tags',
  type: 'Array<string>',
  separator: ','
}
Date property
{
  key: 'createdAt',
  type: 'date',
  inputFormat: 'yyyy-MM-dd',
  UTC: true
}
Derived property
{
  key: 'categoryName',
  type: 'string',
  derive: {
    localReference: 'category',
    remoteProperty: 'name'
  }
}
Expression property
{
  key: 'discountedPrice',
  type: 'float',
  expression: 'price * (1 - discount)'
}
Property with quality checks
{
  key: 'email',
  type: 'string',
  quality: {
    required: true,
    validators: {
      email: { value: true }
    }
  }
}

Reference

Defines a relationship to another model.

Type Definition:

type Reference =
  | ReferenceBase
  | ResolvedReference
  | DerivedReference
  | GroupedReference
  | QueryReference;

Common Properties:

Property Type Description
key string Unique reference identifier
type 'singleValued' | 'multiValued' Single or multiple items
model string Target model key
separator string Separator for multi-valued references
validity 'loose' | 'strict' Validation strictness

Reference Types:

1. Basic Reference

{
  key: 'category',
  type: 'singleValued',
  model: 'Category'
}

{
  key: 'tags',
  type: 'multiValued',
  model: 'Tag',
  separator: ','
}

2. Resolved Reference

{
  key: 'relatedProducts',
  type: 'multiValued',
  model: 'Product',
  resolve: {
    reference: 'productId',
    model: 'ProductRelation'
  }
}

3. Derived Reference

{
  key: 'similarProducts',
  type: 'multiValued',
  model: 'Product',
  derive: {
    localReference: 'category',
    remoteReference: 'products'
  }
}

4. Grouped Reference

{
  key: 'categoryGroup',
  type: 'multiValued',
  model: 'Product',
  groupBy: {
    reference: 'category',
    includeSelfInGroup: false
  }
}

5. Query Reference

{
  key: 'activeProducts',
  type: 'multiValued',
  model: 'Product',
  query: {
    modelKey: 'Product',
    queries: [
      { operator: 'eq', attribute: 'status', value: 'active' }
    ]
  }
}

Property Options

derive

Derives a property value from a referenced model.

Type: { localReference: string; remoteProperty: string; separator?: string }

Examples:

Derive single value
{
  key: 'categoryName',
  type: 'string',
  derive: {
    localReference: 'category',
    remoteProperty: 'name'
  }
}
Derive multiple values
{
  key: 'tagNames',
  type: 'Array<string>',
  derive: {
    localReference: 'tags',
    remoteProperty: 'name',
    separator: ', '
  }
}

expression

Defines a computed property using an expression.

Type: string

Examples:

Simple calculation
{
  key: 'total',
  type: 'float',
  expression: 'price * quantity'
}
Complex expression
{
  key: 'discountedPrice',
  type: 'float',
  expression: 'price * (1 - discount) * (taxRate + 1)'
}
Conditional expression
{
  key: 'status',
  type: 'string',
  expression: 'quantity > 0 ? "available" : "out of stock"'
}

quality

Defines validation rules for a property.

Type: AttributeQualityConfig

Examples:

Required field
{
  key: 'name',
  type: 'string',
  quality: {
    required: true
  }
}
Email validation
{
  key: 'email',
  type: 'string',
  quality: {
    required: true,
    validators: {
      email: { value: true }
    }
  }
}
Number range
{
  key: 'age',
  type: 'int',
  quality: {
    required: true,
    validators: {
      min: { value: 0 },
      max: { value: 120 }
    }
  }
}
String pattern
{
  key: 'zipCode',
  type: 'string',
  quality: {
    validators: {
      pattern: { value: '^[0-9]{5} }
    }
  }
}
Unique constraint
{
  key: 'username',
  type: 'string',
  quality: {
    required: true,
    validators: {
      unique: { value: true }
    }
  }
}

ModelQualityConfig

Quality validation configuration for a model.

Type Definition:

type ModelQualityConfig = {
  enabled?: boolean;
  attributes?: AttributeQualityConfig;
};

Example:

{
  key: 'Product',
  properties: [...],
  quality: {
    enabled: true,
    attributes: {
      required: true,
      nullable: false
    }
  }
}

AttributeQualityConfig

Quality validation configuration for properties.

Type Definition:

type AttributeQualityConfig = {
  required?: boolean;
  nullable?: boolean;
  forceStrictDataType?: boolean;
  validators?: AttributeValidatorConfig;
  validatorHandling?: 'loose' | 'strict';
};

Properties:

Property Type Description
required boolean Property must have a value
nullable boolean Property can be null
forceStrictDataType boolean Enforce strict type checking
validators AttributeValidatorConfig Validation rules
validatorHandling 'loose' | 'strict' Error handling mode

AttributeValidatorConfig

Validator configuration for properties.

Type Definition:

type AttributeValidatorConfig = {
  email?: ValidatorConfig;
  endsWith?: ValidatorConfig;
  enum?: ValidatorConfig;
  includes?: ValidatorConfig;
  max?: ValidatorConfig;
  maxLength?: ValidatorConfig;
  min?: ValidatorConfig;
  minLength?: ValidatorConfig;
  pattern?: ValidatorConfig;
  unique?: ValidatorConfig;
  startsWith?: ValidatorConfig;
};

Available Validators:

Validator Description Value Type
email Email format validation boolean
endsWith String ends with value string
enum Value must be in list any[]
includes String contains value string
max Maximum value number
maxLength Maximum string length number
min Minimum value number
minLength Minimum string length number
pattern Regex pattern match string
unique Unique across all items boolean
startsWith String starts with value string

Examples:

validators: {
  email: { value: true },
  minLength: { value: 5 },
  maxLength: { value: 100 },
  pattern: { value: '^[a-zA-Z0-9]+ }
}

validators: {
  min: { value: 0 },
  max: { value: 1000 },
  unique: { value: true }
}

validators: {
  enum: { value: ['active', 'inactive', 'pending'] },
  startsWith: { value: 'PRD-' }
}

Complete Examples

Product Model

dcupl.models.set({
  key: 'Product',
  keyProperty: 'productId',
  properties: [
    {
      key: 'name',
      type: 'string',
      quality: {
        required: true,
        validators: {
          minLength: { value: 3 },
          maxLength: { value: 100 },
        },
      },
    },
    {
      key: 'price',
      type: 'float',
      fractionDigits: 2,
      quality: {
        required: true,
        validators: {
          min: { value: 0 },
        },
      },
    },
    {
      key: 'description',
      type: 'string',
    },
    {
      key: 'tags',
      type: 'Array<string>',
      separator: ',',
    },
    {
      key: 'createdAt',
      type: 'date',
      inputFormat: 'yyyy-MM-dd',
      UTC: true,
    },
  ],
  references: [
    {
      key: 'category',
      type: 'singleValued',
      model: 'Category',
    },
    {
      key: 'manufacturer',
      type: 'singleValued',
      model: 'Manufacturer',
    },
  ],
  quality: {
    enabled: true,
  },
});

Model with Derived Properties

dcupl.models.set({
  key: 'Product',
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
    { key: 'discount', type: 'float' },
    {
      key: 'finalPrice',
      type: 'float',
      expression: 'price * (1 - discount)',
      fractionDigits: 2,
    },
    {
      key: 'categoryName',
      type: 'string',
      derive: {
        localReference: 'category',
        remoteProperty: 'name',
      },
    },
  ],
  references: [{ key: 'category', type: 'singleValued', model: 'Category' }],
});

Model with Quality Checks

dcupl.models.set({
  key: 'User',
  properties: [
    {
      key: 'username',
      type: 'string',
      quality: {
        required: true,
        validators: {
          minLength: { value: 3 },
          maxLength: { value: 20 },
          pattern: { value: '^[a-zA-Z0-9_]+ },
          unique: { value: true },
        },
      },
    },
    {
      key: 'email',
      type: 'string',
      quality: {
        required: true,
        validators: {
          email: { value: true },
          unique: { value: true },
        },
      },
    },
    {
      key: 'age',
      type: 'int',
      quality: {
        validators: {
          min: { value: 18 },
          max: { value: 120 },
        },
      },
    },
    {
      key: 'status',
      type: 'string',
      quality: {
        required: true,
        validators: {
          enum: { value: ['active', 'inactive', 'pending'] },
        },
      },
    },
  ],
  quality: {
    enabled: true,
    attributes: {
      required: true,
      nullable: false,
      forceStrictDataType: true,
    },
  },
});

Complex References

// Product model with various reference types
dcupl.models.set({
  key: 'Product',
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'float' },
  ],
  references: [
    // Basic reference
    {
      key: 'category',
      type: 'singleValued',
      model: 'Category',
    },
    // Multi-valued reference
    {
      key: 'tags',
      type: 'multiValued',
      model: 'Tag',
      separator: ',',
    },
    // Resolved reference
    {
      key: 'relatedProducts',
      type: 'multiValued',
      model: 'Product',
      resolve: {
        reference: 'productId',
        model: 'ProductRelation',
      },
    },
    // Query reference
    {
      key: 'similarProducts',
      type: 'multiValued',
      model: 'Product',
      query: {
        modelKey: 'Product',
        queries: [{ operator: 'eq', attribute: 'category', value: { key: '$self.category' } }],
      },
    },
  ],
});

See Also