Skip to content
Talk to our solutions team

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.

The simplest entity will have a name and few fields.

task.yaml

entities:
- name: task
fields:
- name: id # Primary key field
type: int
validations:
- type: required
- type: unique
message: should me unique for all entries
- type: final
message: field cannot be updated
- name: name
type: string
validations:
- type: required # validation marking the field as mandatory
message: name is a required field # error message to send when validation fails
- name: description
type: string
- name: duedate
type: date
- name: priority
type: priority

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.

TraitFieldDescription
kisai.commoncreatedbythis will have the id of the user creating the current row of the entity
kisai.commoncreatedonthis will have the timestamp when the user created the current row of the entity
kisai.commonupdatedbythis will have the id of the user updating the current row of the entity
kisai.commonupdatedonthis will have the timestamp when the user updated the current row of the entity
kisai.softdeletedeletedbythis will have the id of the user soft deleted the current row of the entity
kisai.softdeletedeletedonthis will have the timestamp when the user soft deleted the current row of the entity

YAML Definition of common traits

traits:
- name: common
applytoall: true
fields:
- name: createdby
type: string
defaultvalue: contextget("user")
validations:
- type: final
- type: length
min: 5
max: 255
- name: createdon
type: timestamp
defaultvalue: currentTimestamp()
validations:
- type: final
- name: updatedby
type: string
computed: contextget("user")
validations:
- type: length
min: 5
max: 255
- name: updatedon
type: timestamp
computed: currentTimestamp()
- name: softdelete
applytoall: true
fields:
- name: deletedby
type: string
validations:
- type: writeonce
- type: length
min: 5
max: 255
- name: deletedon
type: timestamp
validations:
- type: writeonce

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.

Order by clauses in queries will override default-order definition.

entities:
inherits: kisai.id
default-order: name asc
fields:
- name: outlets
- name: address
- name: gps

Entity has its own internal lifecycle and has an evaluation sequence. Every time a row is created or updated, this lifecycle of evaluation occurs

[Flowchart showing: defaultvalue → transforms → computed → validations]

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

person.yaml

entities:
- name: person
fields:
- name: id
type: ulid
defaultvalue: ulid()
validations:
- type: required
- type: unique
message: id field needs to be unique
- type: final
message: id field cannot be updated
- name: city
type: string
defaultvalue: > 'New York'

Common Default Functions

FunctionDescription
ulid()gives new ULIDs
currentTimestamp()gives the current timestamp
contextget(“user”)returns the current user id from the request context

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 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.

salary.yaml

entities:
- name: salary
fields:
- name: empid
type: ulid
- name: basic
type: int
- name: bonus
type: int
- name: professionaltax
type: int
- name: incometax
type: int
- name: takehome
type: int
computed: basic + bonus - (professionaltax + incometax)

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 DatatypePayload DatatypeTransformExamples
stringAnytostring - convert any type to stringfields: - name: firstname type: string transform: - type: tostring
stringstringtrim - trim spaces from beginning and end ltrim - trim spaces from beginning rtrim - trim spaces from end lowercase - convert value to lowercase uppercase - make the entire string uppercase titlecase - make the entire string titlecase sentencecase - make the entire string sentence case prefix - add a prefix to the string suffix - add a suffix to the string replace - replace a char or substring in the string with a character or substring emptyasnull - replace an empty string with null valuefields: - name: firstname type: string transform: - type: trim - name: middlename type: string transform: - type: emptyasnull - name: lastname type: string transform: - type: ltrim
stringstringprefix - add a prefix to the string suffix - add a suffix to the string replace - replace a char or substring in the string with a character or substringfields: - name: uid type: string transform: - type: prefix value: UID- - type: uppercase - name: slug type: string transform: - type: replace find: " " replace: "-"
int bigintstring float doubletointeger - convert string, float or double to integerfields: - name: age type: int transform: - type: tointeger
doublestring int floattodouble - convert string, integer or float to doublefields: - name: amount type: double transform: - type: todouble
date datetime timestampstringtodate - convert string to date todatetime - convert string to datetime totimestamp - convert string to datetime with tz- name: orderdate type: date transform: - type: todate format: yyyy-mm-dd - name: birthtime type: datetime transform: - type: todatetime format: yyyy-mm-ddTHH:mm:ss - name: transactionclosurets type: timestamp transform: - type: totimestamp format: yyyy-mm-ddTHH:mm:ss+5:30

Validations are a critical part of all API. Validations in kis.ai are isomorphic

ValidationDescriptionExamples
requiredmarks that the field value should be providedfields: - name: lastname type: string validations: - type: required message: lastname is a required field
uniquemarks that the field values should be uniquefields: - name: employeeid type: string validations: - type: required message: employeeid is a required field - type: unique message: employeeid should be unique
finalmarks that the field value can be set only once and then it becomes readonlyfields: - name: uid type: string validations: - type: final message: uid field cannot be changed
readonlymarks 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.fields: - name: amount type: double defaultvalue: 0 - name: discount type: double computed: amount * 0.1 # 10% discount validations: - type: readonly message: you cannot update discount directly
writeonlyfield 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 fieldsfields: - name: secretanswer01 type: string validations: - type: writeonly message: you cannot read from this field
writeoncefield can be updated only once but the value stored cannot be read.fields: - name: secretanswer01 type: string validations: - type: writeonly message: you can write only once to this field
lengthlength of the value is validated against the lower bound or upper boundfields: - name: firstname type: string validations: - type: length min: 3 max: 50 message: firstname should be between 3 and 50 characters - name: interestedtopics type: array(string) validations: - type: length min: 3 max: 10 message: you should select 3 to 10 interested topics
minmaxValidate that the numerical value is between a lowerbound and upperboundfields: - name: age type: int validations: - type: minmax min: 18 max: 150 message: age should be between 18 and 150 years - name: rating type: int validations: - type: minmax min: 1 message: rating should be at minimum of 1

Compliances are additional constraints that you can add to the field to make it compliant with specific values.

ComplianceDescriptionExamples
nologEnsures that field is not logged in log files including audit logs. Eg: Social Security Number, Credit Cardfields: - name: creditcard type: string compliances: - type: nolog
hashThe value provided will not be stored directly. A destructive hash is stored. Typically used for passwordsfields: - name: secondpassword type: string compliances: - type: hash algorithm: SHA-512/256
maskwhen querying this field data is masked and to see the real value, the user should have unmask privilege on this fieldfields: - name: creditcard type: string compliances: - type: mask value: "XXX___"
tokenizestores the tokenized data in the field. User should have untokenize privilege to see the actual valuefields: - name: creditcard type: string compliances: - type: tokenize value: creditcard-unique
encryptstores the encrypted data in the field. User should have decrypt privilege to see the decrypted valuefields: - name: securenote type: string compliances: - type: encrypt algorithm: aes-256 vault-key: securenotekey
piimarks 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 datafields: - name: socialsecuritynumber type: string compliances: - type: pii algorithm: aes-256 vault-key: securenotekey

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.

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.

entities:
- name: employee
inherits: kisai.uid
fields:
- name: firstname
- name: lastname
- name: salarybreakup
inherits: kisai.id
fields:
- name: employeeid
type: ulid
validations:
- type: required
- name: base
type: int
- name: bonus
type: int
- name: equity
type: int
references:
- name: employee_salarybreakup
parent: employee.id
child: salarybreakup.employeeid
type: onetoone

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.

entities:
- name: customer
inherits: kisai.uid
fields:
- name: firstname
- name: lastname
- name: address
- name: orders
inherits: kisai.id
fields:
- name: customerid
type: ulid
validations:
- type: required
- name: itemcount
type: int
- name: totalmrp
type: int
- name: totaltax
type: int
- name: totaldiscount
type: int
- name: totalpaid
type: int
references:
- name: customer_orders
parent: customer.id
child: orders.customerid
type: onetomany

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.

entities:
- name: student
inherits: kisai.uid
fields:
- name: firstname
- name: lastname
- name: grade
- name: course
inherits: kisai.id
fields:
- name: name
type: string
- name: credits
type: int
- name: start
type: date
- name: end
type: date
references:
- name: student_courses
parent: student.id
child: course.id
type: manytomany

Customizing the hidden entity

Sometimes you need to store additional details in the hidden entity, then you use the use customentity

entities:
- name: customer
inherits: kisai.uid
fields:
- name: firstname
- name: lastname
- name: infrastructure:
inherits: kisai.id
fields:
- name: machinename
- name: ip
- name: total_memory
type: bigint
validations:
- type: required
- name: total_storage
type: bigint
validations:
- type: required
- name: total_cores
type: bigint
validations:
- type: required
- name: customerinfrastructureallocation
inherits: kisai.id
default-order: id desc
primary-key: id
fields:
- name: id
type: ulid
defaultvalue: ulid()
validations:
- type: required
- type: unique
message: id field needs to be unique
- type: final
message: id field cannot be updated
- name: customerid
type: ulid
validations:
- type: required
- name: infrastructureid
type: ulid
validations:
- type: required
- name: meta
type: object
- name: allocated_memory
type: bigint
validations:
- type: required
- name: allocated_storage
type: bigint
validations:
- type: required
- name: allocated_cores
type: bigint
validations:
- type: required
references:
- name: employee_courses
parent: employee.id
child: course.id
type: manytomany
customentity:
name: customerinfrastructureallocation
parentfield: customerid
childfield: infrastructureid

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.

entities:
- name: employee
inherits: kisai.uid
fields:
- name: firstname
- name: lastname
- name: managerid
type: ulid
references:
- name: employee_manager
parent: employee.id
child: employee.managerid
type: onetomany