Entities
Entities are foundational blocks of building datastores and APIs. Each entity is mapped to a table in a relation database and to a collection in a Document database. Entities are defined in yaml, and are exposed by Data API block will expose them for CRUD (Create, Update, Retrieve, Delete) operations on REST, GraphQL protocols.
Defining Simple Entity
The simplest entity will have a name and few fields.
1entities:2- name: task3 fields:4 - name: id # Primary key field5 type: int6 validations:7 - type: required8 - type: unique9 message: should me unique for all entries10 - type: final11 message: field cannot be updated12 - name: name13 type: string14 validations:15 - type: required # validation marking the field as mandatory16 message: name is a required field # error message to send when validation fails17 - name: description18 type: string19 - name: duedate20 type: date21 - name: priority22 type: priority
Default traits
All entities created on the kis.ai platform have the below fields, injected. into them through the traits kisai.common
and kisai.softdelete
, as they have the attribute applytoall
set to true
.
Trait | Field | Description |
---|---|---|
kisai.common | createdby | this will have the id of the user creating the current row of the entity |
kisai.common | createdon | this will have the timestamp when the user created the current row of the entity |
kisai.common | updatedby | this will have the id of the user updating the current row of the entity |
kisai.common | updatedon | this will have the timestamp when the user updated the current row of the entity |
kisai.softdelete | deletedby | this will have the id of the user soft deleted the current row of the entity |
kisai.softdelete | deletedon | this will have the timestamp when the user soft deleted the current row of the entity |
YAML Definition of common traits
1traits:2- name: common3 applytoall: true4 fields:5 - name: createdby6 type: string7 defaultvalue: contextget("user")8 validations:9 - type: final10 - type: length11 min: 512 max: 25513 - name: createdon14 type: timestamp15 defaultvalue: currentTimestamp()16 validations:17 - type: final18 - name: updatedby19 type: string20 computed: contextget("user")21 validations:22 - type: length23 min: 524 max: 25525 - name: updatedon26 type: timestamp27 computed: currentTimestamp()28- name: softdelete29 applytoall: true30 fields:31 - name: deletedby32 type: string33 validations:34 - type: writeonce35 - type: length36 min: 537 max: 25538 - name: deletedon39 type: timestamp40 validations:41 - type: writeonce
Default Ordering
When querying the data for an entity, it by default ordered by id. However, default ordering by another fields might be needed when fetching multiple rows of an entity. Here default-order
ensures that data retrieved always follows the default order.
1entities:2inherits: kisai.id3default-order: name asc4fields:5- name: outlets6- name: address7- name: gps
Evaluation Lifecycle
Entity has its own internal lifecycle and has an evaluation sequence. Every time a row is created or updated, this lifecycle of evaluation occurs
Default Values
Fields can have either static or dynamic default values. In the below example, ulid() function gives a new ulid every time its called, or a static value New York
1entities:2- name: person3 fields:4 - name: id5 type: ulid6 defaultvalue: ulid()7 validations:8 - type: required9 - type: unique10 message: id field needs to be unique11 - type: final12 message: id field cannot be updated13 - name: city14 type: string15 defaultvalue: > 'New York'
Common Default Functions
Function | Description |
---|---|
ulid() | gives new ULIDs |
currentTimestamp() | gives the current timestamp |
contextget(“user”) | returns the current user id from the request context |
Idempotent
Entities can be marked as idempotent by adding idempotent
is true, then the id field is not generated on the server side and it is expected from the client side.
Computed fields
Computed fields allow developers to create dynamic fields, whose values are not provided by the user but are computed from other fields or functions. In the example below takehome
is a computed field.
1enttties:2- name: salary3 fields:4 - name: empid5 type: ulid6 - name: basic7 type: int8 - name: bonus9 type: int10 - name: professionaltax11 type: int12 - name: incometax13 type: int14 - name: takehome15 type: int16 computed: basic + bonus - (professionaltax + incometax)
Transforms
Most times the input values need some transformations before inserting into the datastore, like trimming, capitalizing or replace symbols etc. Listed below are all the supported transforms.
Field Datatype | Payload Datatype | Transform | Examples |
---|---|---|---|
string | Any | tostring - convert any type to string |
|
string | string |
|
|
int bigint | string float double |
|
|
double | string int float |
|
|
date datetime timestamp | string |
|
|
Validations
Validations are a critical part of all API. Validations in kis.ai are isomorphic
Validation | Description | Examples |
---|---|---|
required | marks that the field value should be provided |
|
unique | marks that the field values should be unique |
|
final | marks that the field value can be set only once and then it becomes readonly |
|
readonly | marks that the field value can only be read and cannot be updated. Usually such values also have computed to allow them to be computed from other fields. |
|
writeonly | field can be updated but the value stored cannot be read. Usually used to store tokens or PII data or answers to private questions used to authenticate users. This fields still can be used for checking value, but cannot be used to read, and cannot be used as input for computed fields |
|
writeonce | field can be updated only once but the value stored cannot be read. |
|
length | length of the value is validated against the lower bound or upper bound |
|
minmax | Validate that the numerical value is between a lowerbound and upperbound |
|
Compliance
Compliances are additional constraints that you can add to the field to make it compliant with specific values.
Compliance | Description | Examples |
---|---|---|
nolog | Ensures that field is not logged in log files including audit logs. Eg: Social Security Number, Credit Card |
|
hash | The value provided will not be stored directly. A destructive hash is stored. Typically used for passwords |
|
mask | when querying this field data is masked and to see the real value, the user should have unmask privilege on this field |
|
tokenize | stores the tokenized data in the field. User should have untokenize privilege to see the actual value |
|
encrypt | stores the encrypted data in the field. User should have decrypt privilege to see the decrypted value |
|
pii | marks the field as Personally Identifiable Information and will be stored encrypted and nolog compliance is applied automatically. The user should have showpii privilege on this field to see the data |
|
Defining Related Entities
Entities in real world are some times nested, most times related and complex. When modeling the real world in entities, relations are must have. Data API block has the concept of references
to define relations between entities. These relationships dictate how data is connected and ensures data integrity.
1. One-to-One (1:1)
A one-to-one relationship occurs when a single record in one entity is associated with a single record in another entity. This type of relationship is less common but useful for splitting a large entity into smaller ones or for security purposes.
Employee and Salary Breakup
Each employee has one salary breakup, and one salary breakup is linked to one user.
1entities:2- name: employee3 inherits: kisai.uid4 fields:5 - name: firstname6 - name: lastname7- name: salarybreakup8 inherits: kisai.id9 fields:10 - name: employeeid11 type: ulid12 validations:13 - type: required14 - name: base15 type: int16 - name: bonus17 type: int18 - name: equity19 type: int20references:21- name: employee_salarybreakup22 parent: employee.id23 child: salarybreakup.employeeid24 type: onetoone
2. One-to-Many (1:M )
A one-to-many relationship is the most common type of relationship between entities. It occurs when a single record of one entity is related to multiple records in another entity.
Customer and Orders:
One customer can place multiple orders, but each order is linked to only one customer.
1entities:2- name: customer3 inherits: kisai.uid4 fields:5 - name: firstname6 - name: lastname7 - name: address8- name: orders9 inherits: kisai.id10 fields:11 - name: customerid12 type: ulid13 validations:14 - type: required15 - name: itemcount16 type: int17 - name: totalmrp18 type: int19 - name: totaltax20 type: int21 - name: totaldiscount22 type: int23 - name: totalpaid24 type: int25references:26- name: customer_orders27 parent: customer.id28 child: orders.customerid29 type: onetomany
3. Many-to-Many (M:N )
A many-to-many relationship occurs when multiple records in one table are related to multiple records in another table. This relationship is typically implemented using a junction (or associative) table that breaks down the many-to-many relationship into two one-to-many relationships.
Students and Courses: Students can enroll in multiple courses, and each course can have multiple students.
1entities:2- name: student3 inherits: kisai.uid4 fields:5 - name: firstname6 - name: lastname7 - name: grade8- name: course9 inherits: kisai.id10 fields:11 - name: name12 type: string13 - name: credits14 type: int15 - name: start16 type: date17 - name: end18 type: date19references:20- name: student_courses21 parent: student.id22 child: course.id23 type: manytomany
Customizing the hidden entity
Sometimes you need to store additional details in the hidden entity, then you use the use customentity
1entities:2- name: customer3 inherits: kisai.uid4 fields:5 - name: firstname6 - name: lastname7- name: infrastructure:8 inherits: kisai.id9 fields:10 - name: machinename11 - name: ip12 - name: total_memory13 type: bigint14 validations:15 - type: required16 - name: total_storage17 type: bigint18 validations:19 - type: required20 - name: total_cores21 type: bigint22 validations:23 - type: required24- name: customerinfrastructureallocation25 inherits: kisai.id26 default-order: id desc27 primary-key: id28 fields:29 - name: id30 type: ulid31 defaultvalue: ulid()32 validations:33 - type: required34 - type: unique35 message: id field needs to be unique36 - type: final37 message: id field cannot be updated38 - name: customerid39 type: ulid40 validations:41 - type: required42 - name: infrastructureid43 type: ulid44 validations:45 - type: required46 - name: meta47 type: object48 - name: allocated_memory49 type: bigint50 validations:51 - type: required52 - name: allocated_storage53 type: bigint54 validations:55 - type: required56 - name: allocated_cores57 type: bigint58 validations:59 - type: required60references:61- name: employee_courses62 parent: employee.id63 child: course.id64 type: manytomany65 customentity:66 name: customerinfrastructureallocation67 parentfield: customerid68 childfield: infrastructureid
4. Self-Referencing (Recursive)
A self-referencing relationship occurs when a entity is related to itself. This is useful for hierarchical data structures such as organizational charts or family trees.
Employees: An employee can be a manager of other employees, creating a recursive relationship within the same table.
1entities:2- name: employee3 inherits: kisai.uid4 fields:5 - name: firstname6 - name: lastname7 - name: managerid8 type: ulid9references:10- name: employee_manager11 parent: employee.id12 child: employee.managerid13 type: onetomany