Skip to content

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.

task.yaml
1
entities:
2
- name: task
3
fields:
4
- name: id # Primary key field
5
type: int
6
validations:
7
- type: required
8
- type: unique
9
message: should me unique for all entries
10
- type: final
11
message: field cannot be updated
12
- name: name
13
type: string
14
validations:
15
- type: required # validation marking the field as mandatory
16
message: name is a required field # error message to send when validation fails
17
- name: description
18
type: string
19
- name: duedate
20
type: date
21
- name: priority
22
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.

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

1
traits:
2
- name: common
3
applytoall: true
4
fields:
5
- name: createdby
6
type: string
7
defaultvalue: contextget("user")
8
validations:
9
- type: final
10
- type: length
11
min: 5
12
max: 255
13
- name: createdon
14
type: timestamp
15
defaultvalue: currentTimestamp()
16
validations:
17
- type: final
18
- name: updatedby
19
type: string
20
computed: contextget("user")
21
validations:
22
- type: length
23
min: 5
24
max: 255
25
- name: updatedon
26
type: timestamp
27
computed: currentTimestamp()
28
- name: softdelete
29
applytoall: true
30
fields:
31
- name: deletedby
32
type: string
33
validations:
34
- type: writeonce
35
- type: length
36
min: 5
37
max: 255
38
- name: deletedon
39
type: timestamp
40
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.

1
entities:
2
inherits: kisai.id
3
default-order: name asc
4
fields:
5
- name: outlets
6
- name: address
7
- 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

person.yaml
1
entities:
2
- name: person
3
fields:
4
- name: id
5
type: ulid
6
defaultvalue: ulid()
7
validations:
8
- type: required
9
- type: unique
10
message: id field needs to be unique
11
- type: final
12
message: id field cannot be updated
13
- name: city
14
type: string
15
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

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.

salary.yaml
1
enttties:
2
- name: salary
3
fields:
4
- name: empid
5
type: ulid
6
- name: basic
7
type: int
8
- name: bonus
9
type: int
10
- name: professionaltax
11
type: int
12
- name: incometax
13
type: int
14
- name: takehome
15
type: int
16
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 DatatypePayload DatatypeTransformExamples
stringAnytostring - convert any type to string
fields:
- name: firstname
type: string
transform:
- type: tostring
stringstring

trim - 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 value

fields:
- name: firstname
type: string
transform:
- type: trim
- name: middlename
type: string
transform:
- type: emptyasnull
- name: lastname
type: string
transform:
- type: ltrim
fields:
- name: uid
type: string
transform:
- type: prefix
value: UID-
- type: uppercase
- name: slug
type: string
transform:
- type: replace
find: " "
replace: "-"
int
bigint
string
float
double

tointeger - convert string, float or double to integer

fields:
- name: age
type: int
transform:
- type: tointeger
doublestring
int
float

todouble - convert string, integer or float to double

fields:
- name: amount
type: double
transform:
- type: todouble
date
datetime
timestamp
string

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

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

ValidationDescriptionExamples
requiredmarks that the field value should be provided
fields:
- name: lastname
type: string
validations:
- type: required
message: lastname is a required field
uniquemarks that the field values should be unique
fields:
- 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 readonly
fields:
- 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 fields
fields:
- 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 bound
fields:
- 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 upperbound
fields:
- 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

Compliance

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 Card
fields:
- name: creditcard
type: string
compliances:
- type: nolog
hashThe value provided will not be stored directly. A destructive hash is stored. Typically used for passwords
fields:
- 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 field
fields:
- 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 value
fields:
- 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 value
fields:
- 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 data
fields:
- 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.

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.

1
entities:
2
- name: employee
3
inherits: kisai.uid
4
fields:
5
- name: firstname
6
- name: lastname
7
- name: salarybreakup
8
inherits: kisai.id
9
fields:
10
- name: employeeid
11
type: ulid
12
validations:
13
- type: required
14
- name: base
15
type: int
16
- name: bonus
17
type: int
18
- name: equity
19
type: int
20
references:
21
- name: employee_salarybreakup
22
parent: employee.id
23
child: salarybreakup.employeeid
24
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.

1
entities:
2
- name: customer
3
inherits: kisai.uid
4
fields:
5
- name: firstname
6
- name: lastname
7
- name: address
8
- name: orders
9
inherits: kisai.id
10
fields:
11
- name: customerid
12
type: ulid
13
validations:
14
- type: required
15
- name: itemcount
16
type: int
17
- name: totalmrp
18
type: int
19
- name: totaltax
20
type: int
21
- name: totaldiscount
22
type: int
23
- name: totalpaid
24
type: int
25
references:
26
- name: customer_orders
27
parent: customer.id
28
child: orders.customerid
29
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.

1
entities:
2
- name: student
3
inherits: kisai.uid
4
fields:
5
- name: firstname
6
- name: lastname
7
- name: grade
8
- name: course
9
inherits: kisai.id
10
fields:
11
- name: name
12
type: string
13
- name: credits
14
type: int
15
- name: start
16
type: date
17
- name: end
18
type: date
19
references:
20
- name: student_courses
21
parent: student.id
22
child: course.id
23
type: manytomany

Customizing the hidden entity

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

1
entities:
2
- name: customer
3
inherits: kisai.uid
4
fields:
5
- name: firstname
6
- name: lastname
7
- name: infrastructure:
8
inherits: kisai.id
9
fields:
10
- name: machinename
11
- name: ip
12
- name: total_memory
13
type: bigint
14
validations:
15
- type: required
16
- name: total_storage
17
type: bigint
18
validations:
19
- type: required
20
- name: total_cores
21
type: bigint
22
validations:
23
- type: required
24
- name: customerinfrastructureallocation
25
inherits: kisai.id
26
default-order: id desc
27
primary-key: id
28
fields:
29
- name: id
30
type: ulid
31
defaultvalue: ulid()
32
validations:
33
- type: required
34
- type: unique
35
message: id field needs to be unique
36
- type: final
37
message: id field cannot be updated
38
- name: customerid
39
type: ulid
40
validations:
41
- type: required
42
- name: infrastructureid
43
type: ulid
44
validations:
45
- type: required
46
- name: meta
47
type: object
48
- name: allocated_memory
49
type: bigint
50
validations:
51
- type: required
52
- name: allocated_storage
53
type: bigint
54
validations:
55
- type: required
56
- name: allocated_cores
57
type: bigint
58
validations:
59
- type: required
60
references:
61
- name: employee_courses
62
parent: employee.id
63
child: course.id
64
type: manytomany
65
customentity:
66
name: customerinfrastructureallocation
67
parentfield: customerid
68
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.

1
entities:
2
- name: employee
3
inherits: kisai.uid
4
fields:
5
- name: firstname
6
- name: lastname
7
- name: managerid
8
type: ulid
9
references:
10
- name: employee_manager
11
parent: employee.id
12
child: employee.managerid
13
type: onetomany