@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
| Import | Description |
|---|---|
@elqnt/entity | All exports (hooks, models, store, constants) |
@elqnt/entity/hooks | React hooks (useEntityDefinitions, useEntityRecords, useEntities) |
@elqnt/entity/models | TypeScript types |
@elqnt/entity/api | Internal 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:
| Method | Parameters | Returns | Description |
|---|---|---|---|
listDefinitions | - | EntityDefinition[] | List all entity definitions |
getDefinition | entityName: string | EntityDefinition | null | Get definition by name |
createDefinition | definition: Partial<EntityDefinition> | EntityDefinition | null | Create new definition |
updateDefinition | entityName: string, updates: Partial<EntityDefinition> | EntityDefinition | null | Update definition |
deleteDefinition | entityName: string | boolean | Delete 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:
| Method | Parameters | Returns | Description |
|---|---|---|---|
queryRecords | QueryRecordsParams | QueryRecordsResult | Query records with pagination/filters |
getRecord | recordId: string | EntityRecord | null | Get record by ID |
createRecord | record: Partial<EntityRecord> | EntityRecord | null | Create a record |
updateRecord | recordId: string, record: Partial<EntityRecord> | EntityRecord | null | Update a record |
deleteRecord | recordId: string | boolean | Delete a record |
countRecords | filters?: Record<string, unknown> | number | Count records matching filters |
bulkCreate | records: Partial<EntityRecord>[] | BulkOperationResult | Create multiple records |
bulkUpdate | records: Partial<EntityRecord>[] | BulkOperationResult | Update multiple records |
bulkDelete | recordIds: string[] | boolean | Delete 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:
| Action | Payload | Description |
|---|---|---|
setDefinitions | EntityDefinition[] | Set all definitions |
addDefinition | EntityDefinition | Add a definition |
updateDefinition | EntityDefinition | Update a definition |
removeDefinition | string (name) | Remove a definition |
setSelectedDefinition | EntityDefinition | undefined | Set 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 |
setSelectedView | EntityView | undefined | Set 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:
| Action | Payload | Description |
|---|---|---|
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 |
setActiveView | EntityView | undefined | Set 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
| Function | Method | Gateway Route |
|---|---|---|
| Definitions | ||
| List | GET | /api/v1/entities/definitions |
| Get | GET | /api/v1/entities/definitions/{entityName} |
| Create | POST | /api/v1/entities/definitions |
| Update | PUT | /api/v1/entities/definitions/{entityName} |
| Delete | DELETE | /api/v1/entities/definitions/{entityName} |
| Records | ||
| Query | GET | /api/v1/entities/{entityName}/records |
| Get | GET | /api/v1/entities/{entityName}/records/{recordId} |
| Create | POST | /api/v1/entities/{entityName}/records |
| Update | PUT | /api/v1/entities/{entityName}/records/{recordId} |
| Delete | DELETE | /api/v1/entities/{entityName}/records/{recordId} |
| Count | GET | /api/v1/entities/{entityName}/records/count |
| Bulk Operations | ||
| Bulk Create | POST | /api/v1/entities/{entityName}/records/bulk |
| Bulk Update | PUT | /api/v1/entities/{entityName}/records/bulk |
| Bulk Delete | DELETE | /api/v1/entities/{entityName}/records/bulk |
| Admin | ||
| Provision | POST | /api/v1/admin/entities/update |
Type Generation
Entity types are generated from Go using tygo:
cd backend && tygo generate
| Go Package | TypeScript Output |
|---|---|
blazi/services/entities/models | @elqnt/entity/models/entity.ts |
See Also
- Entities Management - Architecture guide
- @elqnt/workflow - Entity triggers in workflows
- @elqnt/kg - Knowledge graph for entity search