Eloquent

Documentation

@elqnt/entity

Complete entity management for the Eloquent platform. Build dynamic, schema-driven data models with full CRUD operations, bulk actions, filtering, views, and React integration with Redux state management.

Installation

npm install @elqnt/entity

Entry Points

ImportDescription
@elqnt/entityAll exports (hooks, models, store, constants)
@elqnt/entity/hooksReact hooks (useEntityDefinitions, useEntityRecords, useEntities)
@elqnt/entity/modelsTypeScript types
@elqnt/entity/apiInternal API functions (use hooks instead)

React Hooks

useEntityDefinitions

Hook for entity definition CRUD operations with loading/error states.

import { useEntityDefinitions } from "@elqnt/entity/hooks";

const {
  loading,
  error,
  listDefinitions,
  getDefinition,
  createDefinition,
  updateDefinition,
  deleteDefinition,
} = useEntityDefinitions({
  baseUrl: apiGatewayUrl,
  orgId: selectedOrgId,
});

// List all entity definitions
const definitions = await listDefinitions();

// Get definition by entity name
const contactsDef = await getDefinition("contacts");

// Create new entity definition
const newDef = await createDefinition({
  name: "leads",
  displayName: "Leads",
  description: "Sales leads",
  schema: {
    type: "object",
    properties: {
      name: { type: "string", title: "Name" },
      email: { type: "string", format: "email", title: "Email" },
      status: { type: "string", enum: ["new", "contacted", "qualified"] },
    },
    required: ["name"],
  },
});

// Update definition
const updated = await updateDefinition("leads", {
  displayName: "Sales Leads",
});

// Delete definition
const success = await deleteDefinition("leads");

Methods:

MethodParametersReturnsDescription
listDefinitions-EntityDefinition[]List all entity definitions
getDefinitionentityName: stringEntityDefinition | nullGet definition by name
createDefinitiondefinition: Partial<EntityDefinition>EntityDefinition | nullCreate new definition
updateDefinitionentityName: string, updates: Partial<EntityDefinition>EntityDefinition | nullUpdate definition
deleteDefinitionentityName: stringbooleanDelete definition

useEntityRecords

Hook for entity record CRUD operations with bulk actions and filtering.

import { useEntityRecords } from "@elqnt/entity/hooks";

const {
  loading,
  error,
  queryRecords,
  getRecord,
  createRecord,
  updateRecord,
  deleteRecord,
  countRecords,
  bulkCreate,
  bulkUpdate,
  bulkDelete,
} = useEntityRecords({
  baseUrl: apiGatewayUrl,
  orgId: selectedOrgId,
  entityName: "contacts",
});

// Query records with pagination and filters
const { records, total, page, pageSize } = await queryRecords({
  page: 1,
  pageSize: 20,
  filters: { status: "active" },
  sortBy: "name",
  sortOrder: "asc",
});

// Get single record
const record = await getRecord("record-uuid");

// Create record
const newRecord = await createRecord({
  name: "John Doe",
  fields: {
    email: "john@example.com",
    phone: "+1234567890",
    status: "active",
  },
});

// Update record
const updated = await updateRecord("record-uuid", {
  fields: { status: "inactive" },
});

// Delete record
const success = await deleteRecord("record-uuid");

// Count records with filters
const count = await countRecords({ status: "active" });

// Bulk operations
const { records: created } = await bulkCreate([
  { name: "Contact 1", fields: { email: "c1@example.com" } },
  { name: "Contact 2", fields: { email: "c2@example.com" } },
]);

const { records: updated } = await bulkUpdate([
  { id: "id-1", fields: { status: "verified" } },
  { id: "id-2", fields: { status: "verified" } },
]);

const deleted = await bulkDelete(["id-1", "id-2", "id-3"]);

Methods:

MethodParametersReturnsDescription
queryRecordsQueryRecordsParamsQueryRecordsResultQuery records with pagination/filters
getRecordrecordId: stringEntityRecord | nullGet record by ID
createRecordrecord: Partial<EntityRecord>EntityRecord | nullCreate a record
updateRecordrecordId: string, record: Partial<EntityRecord>EntityRecord | nullUpdate a record
deleteRecordrecordId: stringbooleanDelete a record
countRecordsfilters?: Record<string, unknown>numberCount records matching filters
bulkCreaterecords: Partial<EntityRecord>[]BulkOperationResultCreate multiple records
bulkUpdaterecords: Partial<EntityRecord>[]BulkOperationResultUpdate multiple records
bulkDeleterecordIds: string[]booleanDelete multiple records

QueryRecordsParams:

interface QueryRecordsParams {
  page?: number;
  pageSize?: number;
  filters?: Record<string, unknown>;
  sortBy?: string;
  sortOrder?: "asc" | "desc";
}

QueryRecordsResult:

interface QueryRecordsResult {
  records: EntityRecord[];
  total: number;
  page: number;
  pageSize: number;
}

useEntities (Legacy)

Combined hook for both definitions and records. Prefer the specialized hooks above.

import { useEntities } from "@elqnt/entity/hooks";

const {
  loading,
  error,
  listDefinitions,
  getDefinition,
  queryRecords,
  getRecord,
  createRecord,
  updateRecord,
  deleteRecord,
} = useEntities({
  baseUrl: apiGatewayUrl,
  orgId: selectedOrgId,
});

// Query records for any entity
const contacts = await queryRecords("contacts", { page: 1, pageSize: 20 });
const leads = await queryRecords("leads", { filters: { status: "new" } });

Provisioning API

For bulk provisioning entity definitions (admin use).

import { provisionEntitiesApi } from "@elqnt/entity/api";

const result = await provisionEntitiesApi(
  [
    {
      name: "contacts",
      displayName: "Contacts",
      module: "crm",
      schema: { /* JSON Schema */ },
    },
    {
      name: "companies",
      displayName: "Companies",
      module: "crm",
      schema: { /* JSON Schema */ },
    },
  ],
  { baseUrl: apiGatewayUrl, orgId }
);

console.log(`Created: ${result.data?.created}, Updated: ${result.data?.updated}`);

Models

EntityDefinition

import type { EntityDefinition } from "@elqnt/entity/models";

interface EntityDefinition {
  id: string;
  name: string;              // e.g., "contacts"
  displayName: string;       // e.g., "Contacts"
  module: string;            // e.g., "crm", "sales"
  description: string;
  schema: JSONSchema;        // JSON Schema defining fields
  defaultViewId: string;
  metadata?: Record<string, any>;
  createdAt: string;
  updatedAt: string;
  isActive: boolean;
  version: number;
}

EntityRecord

import type { EntityRecord } from "@elqnt/entity/models";

interface EntityRecord {
  id: string;
  entityId: string;          // References EntityDefinition.id
  name: string;              // Display name
  fields: Record<string, any>; // Must match entity definition schema
  tags?: string[];
  metadata?: Record<string, any>;
  createdAt: string;
  updatedAt: string;
  isActive: boolean;
  version: number;
}

EntityView

import type { EntityView, ViewColumn, ViewFilter } from "@elqnt/entity/models";

interface EntityView {
  id: string;
  name: string;
  displayName: string;
  entityName: string;
  columns: ViewColumn[];
  filters: ViewFilter[];
  lookups: LookupInclude[];
  sortBy?: string;
  sortOrder?: number;        // 1 = asc, -1 = desc
  isDefault: boolean;
  createdAt: string;
  updatedAt: string;
  isActive: boolean;
  version: number;
}

interface ViewColumn {
  fieldName: string;
  displayName: string;
  width: number;
  sortable: boolean;
  visible: boolean;
  order: number;
}

interface ViewFilter {
  fieldName: string;
  operator: string;
  value: any;
}

Query & Filtering

import type { EntityQuery, Filter, Sort } from "@elqnt/entity/models";

interface EntityQuery {
  filters: Record<string, any>;
  page: number;
  pageSize: number;
  sortBy: string;
  sortOrder: number;         // 1 = asc, -1 = desc
  includeLookups?: LookupInclude[];
  include?: string[];        // Fields to include
  exclude?: string[];        // Fields to exclude
}

interface Filter {
  field: string;
  operator: EntityFilterOperator;
  value: any;
}

interface Sort {
  field: string;
  direction: number;         // 1 = asc, -1 = desc
}

Filter Operators

import {
  OperatorEq,        // "eq" - Equal to
  OperatorNe,        // "ne" - Not equal to
  OperatorGt,        // "gt" - Greater than
  OperatorGte,       // "gte" - Greater than or equal
  OperatorLt,        // "lt" - Less than
  OperatorLte,       // "lte" - Less than or equal
  OperatorIn,        // "in" - In array
  OperatorNin,       // "nin" - Not in array
  OperatorContains,  // "contains" - Contains string
  OperatorStartsWith,// "startsWith" - Starts with
  OperatorEndsWith,  // "endsWith" - Ends with
  OperatorExists,    // "exists" - Field exists
  OperatorEmpty,     // "empty" - Field is empty
  OperatorBetween,   // "between" - Between range
  EntityFilterOperators, // Object with all operators
} from "@elqnt/entity/models";

Field Types

import {
  EntityFieldTypeString,        // "string" - Short text
  EntityFieldTypeStringMultiline,// "stringMultiline" - Long text
  EntityFieldTypeText,          // "text" - Rich text editor
  EntityFieldTypeInt,           // "int" - Integer
  EntityFieldTypeFloat,         // "float" - Decimal
  EntityFieldTypeBool,          // "bool" - Boolean
  EntityFieldTypeDate,          // "date" - Date
  EntityFieldTypeDateTime,      // "datetime" - Date & time
  EntityFieldTypeEmail,         // "email" - Email
  EntityFieldTypePhone,         // "phone" - Phone
  EntityFieldTypeURL,           // "url" - URL
  EntityFieldTypeDropdown,      // "dropdown" - Single select
  EntityFieldTypeMultiSelect,   // "multiselect" - Multi select
  EntityFieldTypeLookup,        // "lookup" - Reference to another entity
  EntityFieldTypeMultiLookup,   // "multilookup" - Multiple references
  EntityFieldTypeCurrency,      // "currency" - Currency
  EntityFieldTypeFile,          // "file" - File attachment
  EntityFieldTypeImage,         // "image" - Image
  EntityFieldTypeJSON,          // "json" - JSON data
  EntityFieldTypes,             // Object with all field types
} from "@elqnt/entity/models";

Pagination Result

import type { ListResult } from "@elqnt/entity/models";

interface ListResult<T> {
  items: T[];
  totalCount: number;
  currentPage: number;
  pageSize: number;
  totalPages: number;
}

Change Events

import type {
  EntityRecordChangeEvent,
  EntityDefinitionChangeEvent,
  EntityViewChangeEvent,
  RecordChangeAction,
} from "@elqnt/entity/models";

import {
  RecordChangeActionCreated,  // "created"
  RecordChangeActionUpdated,  // "updated"
  RecordChangeActionDeleted,  // "deleted"
} from "@elqnt/entity/models";

interface EntityRecordChangeEvent {
  orgId: string;
  entityName: string;
  recordId: string;
  record?: EntityRecord;
  changes?: RecordChange;
  action: RecordChangeAction;
  timestamp: string;
}

Redux Store

Redux Toolkit slices for entity state management.

Entity Definition Slice

import { entityDefinitionReducer } from "@elqnt/entity";
import type { EntityDefinitionState, EntityDefinitionSelector } from "@elqnt/entity";

// Add to your store
const store = configureStore({
  reducer: {
    entityDefinition: entityDefinitionReducer,
    // ...other reducers
  },
});

// State shape
interface EntityDefinitionState {
  definitions: Record<string, EntityDefinition>;
  selectedDefinition?: EntityDefinition;
  views: Record<string, EntityView[]>;
  selectedView?: EntityView;
  isLoading: boolean;
  error?: string;
  loadingStates: Record<string, boolean>;
}

Actions:

ActionPayloadDescription
setDefinitionsEntityDefinition[]Set all definitions
addDefinitionEntityDefinitionAdd a definition
updateDefinitionEntityDefinitionUpdate a definition
removeDefinitionstring (name)Remove a definition
setSelectedDefinitionEntityDefinition | undefinedSet selected
setViews{ entityName, views }Set views for entity
addView{ entityName, view }Add a view
updateView{ entityName, view }Update a view
removeView{ entityName, viewId }Remove a view
setSelectedViewEntityView | undefinedSet selected view

Entity Record Slice

import { entityRecordReducer } from "@elqnt/entity";
import type { EntityRecordState, EntityRecordSelector } from "@elqnt/entity";

// State shape
interface EntityRecordState {
  records: {
    [entityName: string]: {
      items: Record<string, EntityRecord>;
      params: EntityQuery;
      meta: ListResult<EntityRecord>;
      selected: string[];
    };
  };
  selectedRecord?: EntityRecord;
  activeView?: EntityView;
  isLoading: boolean;
  error?: string;
  loadingStates: Record<string, boolean>;
}

Actions:

ActionPayloadDescription
setRecords{ entityName, records, params }Set records for entity
addRecord{ entityName, record }Add a record
updateRecord{ entityName, record }Update a record
removeRecord{ entityName, recordId }Remove a record
setSelected{ entityName, ids }Set selected record IDs
setSelectedRecord{ record }Set currently selected record
setActiveViewEntityView | undefinedSet active view
updateQueryParams{ entityName, params }Update query params

Constants

Predefined Colors

import { PREDEFINED_COLORS } from "@elqnt/entity";

// For entity/field color pickers
PREDEFINED_COLORS = [
  { value: "#EF4444", name: "Red" },
  { value: "#F97316", name: "Orange" },
  { value: "#EAB308", name: "Yellow" },
  { value: "#22C55E", name: "Green" },
  { value: "#06B6D4", name: "Cyan" },
  { value: "#3B82F6", name: "Blue" },
  { value: "#6366F1", name: "Indigo" },
  { value: "#A855F7", name: "Purple" },
];

NATS Subjects

For backend service communication:

import {
  // Schema management
  EntityOrgSchemaCreate,       // "entity.org.schema.create"
  EntityOrgSchemaDrop,         // "entity.org.schema.drop"

  // Definition CRUD
  EntityDefinitionCreate,      // "entity.definition.create"
  EntityDefinitionCreated,     // "entity.definition.created"
  EntityDefinitionUpdate,      // "entity.definition.update"
  EntityDefinitionUpdated,     // "entity.definition.updated"
  EntityDefinitionGet,         // "entity.definition.get"
  EntityDefinitionGetServer,   // "entity.definition.get.server"
  EntityDefinitionList,        // "entity.definition.list"
  EntityDefinitionDelete,      // "entity.definition.delete"
  EntityDefinitionDeleted,     // "entity.definition.deleted"

  // Record CRUD
  EntityRecordCreate,          // "entity.record.create"
  EntityRecordCreated,         // "entity.record.created"
  EntityRecordGet,             // "entity.record.get"
  EntityRecordQuery,           // "entity.record.query"
  EntityRecordCount,           // "entity.record.count"
  EntityRecordUpdate,          // "entity.record.update"
  EntityRecordUpdated,         // "entity.record.updated"
  EntityRecordDelete,          // "entity.record.delete"
  EntityRecordDeleted,         // "entity.record.deleted"

  // Bulk operations
  EntityRecordsBulkCreate,     // "entity.records.bulk.create"
  EntityRecordsBulkCreated,    // "entity.records.bulk.created"
  EntityRecordsBulkUpdate,     // "entity.records.bulk.update"
  EntityRecordsBulkUpdated,    // "entity.records.bulk.updated"
  EntityRecordsBulkDelete,     // "entity.records.bulk.delete"
  EntityRecordsBulkDeleted,    // "entity.records.bulk.deleted"

  // View CRUD
  EntityViewCreate,            // "entity.view.create"
  EntityViewCreated,           // "entity.view.created"
  EntityViewUpdate,            // "entity.view.update"
  EntityViewUpdated,           // "entity.view.updated"
  EntityViewDelete,            // "entity.view.delete"
  EntityViewDeleted,           // "entity.view.deleted"
  EntityViewList,              // "entity.view.list"
} from "@elqnt/entity/models";

API Gateway Routes

FunctionMethodGateway Route
Definitions
ListGET/api/v1/entities/definitions
GetGET/api/v1/entities/definitions/{entityName}
CreatePOST/api/v1/entities/definitions
UpdatePUT/api/v1/entities/definitions/{entityName}
DeleteDELETE/api/v1/entities/definitions/{entityName}
Records
QueryGET/api/v1/entities/{entityName}/records
GetGET/api/v1/entities/{entityName}/records/{recordId}
CreatePOST/api/v1/entities/{entityName}/records
UpdatePUT/api/v1/entities/{entityName}/records/{recordId}
DeleteDELETE/api/v1/entities/{entityName}/records/{recordId}
CountGET/api/v1/entities/{entityName}/records/count
Bulk Operations
Bulk CreatePOST/api/v1/entities/{entityName}/records/bulk
Bulk UpdatePUT/api/v1/entities/{entityName}/records/bulk
Bulk DeleteDELETE/api/v1/entities/{entityName}/records/bulk
Admin
ProvisionPOST/api/v1/admin/entities/update

Type Generation

Entity types are generated from Go using tygo:

cd backend && tygo generate
Go PackageTypeScript Output
blazi/services/entities/models@elqnt/entity/models/entity.ts

See Also