TypeDB Philosophy
Programming languages have evolved rapidly, but database models have failed to keep up - and modern applications must use complex layered architectures to manage data as a result. In order to resolve this, we built TypeDB on a completely new, highly expressive database paradigm. This page introduces its origins and core ideas.
Why do we need a new kind of database?
“The limits of my language mean the limits of my world” — Ludwig Wittgenstein, philosopher and logician
Application code uses complex data structures
TypeDB was conceived to solve the lack of expressivity in current database paradigms. Programming languages are becoming increasingly more declarative, empowering engineers to quickly write safe and expressive code backed by static type checking and abstract data constructs. Object-oriented programming involves complex modeling constructs such as abstraction, inheritance, and polymorphism, requiring the expression of multidimensional data structures. However, current databases are unable to natively handle these data structures that we so easily take for granted.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
// Class inheritance in Java
class User {
String email;
String name;
User(String email, String name) {
this.name = name;
this.email = email;
}
}
class Employee extends User {
int employeeId;
Employee(String email, String name, int employeeId) {
super(email, name);
this.employeeId = employeeId;
}
}
class PartTimeEmployee extends Employee {
int weeklyHours;
PartTimeEmployee(String email, String name, int employeeId, int weeklyHours) {
super(email, name, employeeId);
this.weeklyHours = weeklyHours;
}
}
// Class instantiation in Java
PartTimeEmployee john = new PartTimeEmployee(
"john.doe@typedb.com",
"John Doe",
346523,
35
);
Relational databases lack the same expressivity
Relational databases were designed at a time when procedural programming languages were the norm. They are built on Codd’s relational algebra and implemented using tables and one-dimensional tuples. As a result, relational databases are unable to natively model complex data structures due to their lack of expressivity. This fundamental incompatibility between object and relational models has become one of the biggest challenges in database engineering and left databases unable to evolve alongside programming languages.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
-- Table inheritance in SQL
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
);
CREATE TABLE employees (
id INTEGER PRIMARY KEY REFERENCES users(id),
employee_id INTEGER NOT NULL UNIQUE
);
CREATE TABLE part_time_employees (
id INTEGER PRIMARY KEY REFERENCES employees(id),
weekly_hours INTEGER NOT NULL
);
-- Data insertion in SQL
DO $$
DECLARE
inserted_user_id INTEGER;
BEGIN
INSERT INTO users (id, email, name)
VALUES (DEFAULT, 'john.doe@typedb.com', 'John Doe')
RETURNING id INTO inserted_user_id;
INSERT INTO employees (id, employee_id)
VALUES (inserted_user_id, 346523);
INSERT INTO part_time_employees (id, weekly_hours)
VALUES (inserted_user_id, 35);
COMMIT;
END $$;
Schemaless databases come at a high cost
The limitations of relational databases led to the emergence of NoSQL databases, particularly document and graph databases. These databases eliminated the predefined schema, making data insertion trivial, but this comes with the cost of complicating retrieval. Without a schema, structural metadata must be stored as data, hardcoded into queries, or modeled in a secondary data store. This forces engineers to access their data imperatively, as the database does not have the context to correctly interpret declarative polymorphic queries.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
// Retrieval of polymorphic data in MongoDB
db.resource_ownerships.aggregate([
{
$lookup:
{
from: "resources",
localField: "resource",
foreignField: "_id",
as: "resource"
}
},
{
$unwind:
{
path: "$resource"
}
},
{
$lookup:
{
from: "users",
localField: "owner",
foreignField: "_id",
as: "owner"
}
},
{
$unwind:
{
path: "$owner"
}
},
{
$unwind:
{
path: "$owner.emails"
}
},
{
$addFields:
{
resource_id: {
$switch: {
branches: [
{
case: {
$eq: ["$resource.resource_type", "file"]
},
then: "$resource.path"
},
{
case: {
$eq: ["$resource.resource_type", "directory"]
},
then: "$resource.path"
},
{
case: {
$eq: ["$resource.resource_type", "commit"]
},
then: "$resource.hash"
},
{
case: {
$eq: ["$resource.resource_type", "repository"]
},
then: "$resource.name"
},
{
case: {
$eq: ["$resource.resource_type", "table"]
},
then: "$resource.name"
},
{
case: {
$eq: ["$resource.resource_type", "database"]
},
then: "$resource.name"
}
]
}
}
}
},
{
$project: {
_id: false,
email: "$owner.emails",
resource_type: "$resource.resource_type",
id: "$resource_id"
}
}
])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
// Retrieval of polymorphic data in Neo4j's Cypher
MATCH
(user:User)-[:OWNS]->(rsrc:Resource)
WITH
rsrc,
[user.primary_email] + user.alias_emails AS emails,
labels(rsrc) AS resource_types,
keys(rsrc) AS properties
UNWIND emails AS email
UNWIND resource_types AS rsc_type
WITH
rsrc, email, rsc_type, properties,
{
File: "path",
Directory: "path",
Commit: "hash",
Repository: "name",
Table: "name",
Database: "name"
} AS id_type_map
WHERE rsc_type IN keys(id_type_map)
AND id_type_map[rsc_type] IN properties
RETURN email, rsc_type, rsrc[id_type_map[rsc_type]] AS id
What makes TypeDB unique among databases?
TypeDB has a strongly-typed schema for defining inheritance hierarchies and interfaces, a variablizable query language for composing truly declarative queries, and a type inference engine for resolving queries against the schema.
Types are defined in a hierarchy
TypeDB models are described by types, defined in a schema as templates for data instances, analogous to classes. Each user-defined type extends one of three root types: entity
, relation
, and attribute
, or a previously user-defined type. Entities represent independent concepts. Relations represent concepts dependent on roles played by entities and other relations. Attributes represent properties of entities and relations. Any type can be made concrete or abstract, and roles in relations can be overridden by their subtypes.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
define
user sub entity;
admin sub user;
user-group sub entity;
resource sub entity, abstract;
file sub resource;
ownership sub relation, abstract,
relates owned,
relates owner;
group-ownership sub ownership,
relates group as owned;
resource-ownership sub ownership,
relates resource as owned;
id sub attribute, abstract, value string;
email sub id;
name sub id;
path sub id;
Behaviors are shared and inherited
Once the entity, relation, and attribute type hierarchies have been defined, the attributes that entities and relations own
and the roles they play
in relations are implemented like interfaces. Declarations of owned attributes and played roles are independent of each other, and multiple entity and relation types can own the same attribute or play the same role. The attributes a type owns and the roles it plays are inherited by its subtypes, and can be overridden to specialize them.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
define
user owns email,
plays resource-ownership:owner;
admin plays group-ownership:owner;
user-group owns name,
plays group-ownership:group,
plays resouce-ownership:owner;
resource owns id,
plays resource-ownership:resource;
file owns path as id;
Data is semantically validated
With the type hierarchies and interfaces defined in the schema, data can be instantiated with an insert
query. Data instances and types are defined by variables using a $variable-name
that exists in the scope of the query and can be reused to describe complex data patterns. Relations are defined with a tuple of roleplayers and the roles they play. Write queries undergo semantic validation against the schema, ensuring that the inserted or modified data patterns are valid. Queries that would insert data not allowed by the schema are rejected.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
insert
$naomi isa admin, has email "naomi@typedb.com";
$amos isa user, has email "amos@typedb.com";
$engineers isa user-group, has name "engineers";
$benchmark isa file, has path "/amos/benchmark-results.xlsx";
$roadmap isa file, has path "/typedb/feature-roadmap.pdf";
(group: $engineers, owner: $naomi) isa group-ownership;
(resource: $benchmark, owner: $amos) isa resource-ownership;
(resource: $roadmap, owner: $engineers) isa resource-ownership;
Data is queried declaratively
Data is queried with high-level patterns, in which any element can be variablized. Queries are analyzed by the type inference engine before going to the query planner. It resolves polymorphism by identifying possible types that could fit patterns as defined by the schema, and queries return instances of all those types. Querying a supertype returns instances of subtypes that inherit from it. Querying an interface returns instances of types that implement it. Querying a variablized type parametrically returns instances of all types that match the pattern.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
match
(owned: $object, owner: $owner) isa! $ownership-type;
fetch
$ownership-type;
$object: id;
$owner: id;
# Results:
[{
"ownership-type": { "root": "relation", "label": "group-ownership" },
"object": {
"type": { "root": "entity", "label": "user-group" },
"id": [
{ "value": "engineers", "value_type": "string", "type": { "root": "attribute", "label": "name" } }
]
},
"owner": {
"type": { "root": "entity", "label": "admin" },
"id": [
{ "value": "naomi@typedb.com", "value_type": "string", "type": { "root": "attribute", "label": "email" } }
]
}
},
{
"ownership-type": { "root": "relation", "label": "resource-ownership" },
"object": {
"type": { "root": "entity", "label": "file" },
"id": [
{ "value": "/amos/benchmark-results.xlsx", "value_type": "string", "type": { "root": "attribute", "label": "path" } }
]
},
"owner": {
"type": { "root": "entity", "label": "user" },
"id": [
{ "value": "amos@typedb.com", "value_type": "string", "type": { "root": "attribute", "label": "email" } }
]
}
},
{
"ownership-type": { "root": "relation", "label": "resource-ownership" },
"object": {
"type": { "root": "entity", "label": "file" },
"id": [
{ "value": "/typedb/feature-roadmap.pdf", "value_type": "string", "type": { "root": "attribute", "label": "path" } }
]
},
"owner": {
"type": { "root": "entity", "label": "user-group" },
"id": [
{ "value": "engineers", "value_type": "string", "type": { "root": "attribute", "label": "name" } }
]
}
}]
How does TypeDB impact database engineering?
TypeDB natively implements high-level model features like abstraction, inheritance, and polymorphism. This enables engineers to work with flexible and adaptable data models, making it easier to manage, query, and reason over complex data structures.
A unified way of working with data
TypeDB enables engineers to use the same conceptual data models in their application and database, by directly implementing high-level abstractions. Unlike with other databases, additional backend layers are not necessary, and all of these features are built-in, robust, and performant. This empowers engineers to quickly write queries that are as safe and expressive as code. TypeDB redefines database architecture by providing the tools required for modern application development, leading to a number of unique benefits.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
# Type inheritance in TypeQL
define
user sub entity;
email sub attribute, value string;
name sub attribute, value string;
user owns name, owns email;
employee sub user;
emloyee-id sub attribute, value long;
employee owns employee-id;
part-time-employee sub employee;
weekly-hours sub attribute, value long;
part-time-employee owns weekly-hours;
# Data insertion in TypeDB
insert
$john isa part-time-employee,
has email "john.doe@typedb.com",
has name "John Doe",
has employee-id 346523,
has weekly-hours 35;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
// Class inheritance in Java
class User {
String email;
String name;
User(String email, String name) {
this.name = name;
this.email = email;
}
}
class Employee extends User {
int employeeId;
Employee(String email, String name, int employeeId) {
super(email, name);
this.employeeId = employeeId;
}
}
class PartTimeEmployee extends Employee {
int weeklyHours;
PartTimeEmployee(String email, String name, int employeeId, int weeklyHours) {
super(email, name, employeeId);
this.weeklyHours = weeklyHours;
}
}
// Class instantiation in Java
PartTimeEmployee john = new PartTimeEmployee(
"john.doe@typedb.com",
"John Doe",
346523,
35
);
Data integrity
The conceptual schema and advanced constraint language provide integrity guarantees even when working with polymorphic data structures. Unlike with other databases, where integrity is managed in the application, TypeDB validates data directly at the source.
Continuous extensibility
Queries are truly declarative, so the results of queries automatically extend to include new valid types that are added to the schema after the query is written. This minimizes the need to maintain and update queries when the schema is extended.
Consolidated models
The high-level data model means that schemas in relational, document, and graph databases can be translated to TypeDB with no loss of information. This allows for easy transfer of data from other databases, during migrations or when building an analytics layer.
Integrated application logic
Integrate application logic by defining functions in the schema that can be called directly from queries. Functions use the same syntax as queries, allowing functions to provide high-level abstractions for complex constraints, contained within their logic.
Object model parity
The conceptual schema allows for perfect parity with object models. Data structures that are challenging to model in other databases are simple and intuitive in TypeDB, with type hierarchies, abstract types, multivalued attributes, n-ary relations, and more.
Near-natural language
Schemas and queries read close to natural language, without having to use imperative language to describe low-level data structures. As a result, Engineers and domain experts can understand the intent of queries, even with no experience of writing them.
Get started today
Deploy locally or in the cloud and start building now, or explore more about TypeDB and how its unique capabilities as a polymorphic database can refine and empower your applications.
Start building with TypeDB
Cloud or container, a polymorphic database with a conceptual data model, a strong subtyping system, a symbolic reasoning engine, and a type-theoretic language is minutes away.