Schema objects
In this guide, you’ll see how to use driver API methods and stateful objects to programmatically manipulate types and rules in a database schema using one of the TypeDB drivers. This page assumes you’ve already followed instructions from the Define query page.
Type objects
A type object has many useful methods to traverse the type hierarchy, find related types, and manipulate types definitions/properties. To manipulate a type with driver API methods, you need to get a stateful object that represents the type in the database.
Get type objects
To get a type object from a TypeDB database, you can use a TypeQL Get query or one of the driver API methods.
Get a type object by its label
Use type’s label to retrieve the type object.
For example, to get a stateful object of the user
entity type, use:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let user_type = tx.concept().get_entity_type("user".to_owned()).resolve()?.unwrap();
For more information, see the ConceptManager class methods.
user_type = tx.concepts.get_entity_type("user").resolve()
For more information, see the ConceptManager class methods.
let userType = await tx.concepts.getEntityType("user");
For more information, see the ConceptManager class methods.
EntityType userType = tx.concepts().getEntityType("user").resolve();
For more information, see the ConceptManager class methods.
IEntityType userType = tx.Concepts.GetEntityType("user").Resolve()!;
For more information, see the IConceptManager class methods.
std::unique_ptr<TypeDB::EntityType> userType = tx.concepts.getEntityType("user").get();
For more information, see the ConceptManager class methods.
Concept* userType = concept_promise_resolve(concepts_get_entity_type(tx, "user"));
For more information, see the Concept struct functions.
Query for types
Send a Get query with a pattern to retrieve types and process the response to get type objects. For example, to get all entity types, send the following Get query:
match
$x sub entity;
get $x;
Create type objects
To add a new type into the schema of a database,
use a TypeQL Define query or one of the put type methods.
For example, to add an entity type with the label admin
by using put type method, use the following code:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
admin_type = tx.concepts.put_entity_type("admin").resolve()
For more information, see the ConceptManager class methods.
admin_type = tx.concepts.put_entity_type("admin").resolve()
For more information, see the ConceptManager class methods.
let adminType = await tx.concepts.putEntityType("admin");
For more information, see the ConceptManager class methods.
EntityType adminType = tx.concepts().putEntityType("admin").resolve();
For more information, see the ConceptManager class methods.
IEntityType adminType = tx.Concepts.PutEntityType("admin").Resolve()!;
For more information, see the IConceptManager class methods.
std::unique_ptr<TypeDB::EntityType> adminType = tx.concepts.putEntityType("admin").get();
For more information, see the ConceptManager class methods.
Concept* adminType = concept_promise_resolve(concepts_put_entity_type(tx, "admin"));
For more information, see the Concept struct functions.
Type manipulation
A stateful type object has many useful methods to manipulate the type or traverse the type hierarchy of a schema:
-
get/set label,
-
get/set supertype,
-
get subtypes,
-
get ownerships,
-
get roles played,
-
etc.
For example, see how to change a supertype for the admin
type we added previously:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
drop(admin_type.set_supertype(&tx, user_type.clone()).resolve());
For more information on methods, available for manipulating Type objects, see the Schema class methods.
admin_type.set_supertype(tx, user_type)
For more information on methods, available for manipulating Type objects, see the Schema class methods.
await adminType.setSupertype(tx, userType);
For more information on methods, available for manipulating Type objects, see the Schema class methods.
adminType.setSupertype(tx, userType).resolve();
For more information on methods, available for manipulating Type objects, see the Schema class methods.
adminType.SetSupertype(tx, userType);
For more information on methods, available for manipulating Type objects, see the Schema class methods.
adminType.get()->setSupertype(tx, userType.get()).wait();
For more information on methods, available for manipulating Type objects, see the Schema class methods.
entity_type_set_supertype(tx, adminType, userType);
For more information on methods, available for manipulating Type objects, see the Schema section functions.
Full example
See below a more comprehensive example of type objects manipulation.
In this example we retrieve the user
type object, create the admin
type and set user
as a supertype for admin
.
Then we retrieve all subtypes of the entity
root types (effectively all entity types) and print their labels.
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let databases = DatabaseManager::new(driver);
let db = databases.get(DB_NAME)?;
{
let session = Session::new(db, SessionType::Schema)?;
{
let tx = session.transaction(TransactionType::Write)?;
let user_type = tx.concept().get_entity_type("user".to_owned()).resolve()?.ok_or("No root entity")?;
let mut admin_type = tx.concept().put_entity_type("admin".to_owned()).resolve()?;
drop(admin_type.set_supertype(&tx, user_type).resolve());
let entities = tx
.concept()
.get_entity_type("entity".to_owned())
.resolve()?
.ok_or("No root entity")?
.get_subtypes(&tx, Transitivity::Transitive)?;
for subtype in entities {
println!("{}", subtype?.label);
}
let _ = tx.commit().resolve();
}
}
with driver.session(DB_NAME, SessionType.SCHEMA) as session:
with session.transaction(TransactionType.WRITE) as tx:
user_type = tx.concepts.get_entity_type("user").resolve()
admin_type = tx.concepts.put_entity_type("admin").resolve()
admin_type.set_supertype(tx, user_type)
root_entity = tx.concepts.get_root_entity_type()
subtypes = list(root_entity.get_subtypes(tx, Transitivity.TRANSITIVE))
for subtype in subtypes:
print(subtype.get_label().name)
tx.commit()
try {
session = await driver.session(DB_NAME, SessionType.SCHEMA);
try {
tx = await session.transaction(TransactionType.WRITE);
let user = await tx.concepts.getEntityType("user");
let admin = await tx.concepts.putEntityType("admin");
await admin.setSupertype(tx, user);
let rootEntity = await tx.concepts.getRootEntityType();
let subtypes = await rootEntity.getSubtypes(tx, Concept.Transitivity.TRANSITIVE);
await subtypes.forEach(subtype => console.log(subtype.label.toString()));
await tx.commit();
}
finally {if (tx.isOpen()) {await tx.close()};}
}
finally {await session?.close();}
try (TypeDBSession session = driver.session(DB_NAME, TypeDBSession.Type.SCHEMA)) {
try (TypeDBTransaction tx = session.transaction(TypeDBTransaction.Type.WRITE)) {
EntityType userType = tx.concepts().getEntityType("user").resolve();
EntityType adminType = tx.concepts().putEntityType("admin").resolve();
adminType.setSupertype(tx, userType).resolve();
EntityType root_entity = tx.concepts().getRootEntityType();
root_entity.getSubtypes(tx, Concept.Transitivity.TRANSITIVE).forEach(result -> System.out.println(result.getLabel().name()));
tx.commit();
}
}
using (ITypeDBSession session = driver.Session(DB_NAME, SessionType.Schema)) {
using (ITypeDBTransaction tx = session.Transaction(TransactionType.Write)) {
IEntityType userType = tx.Concepts.GetEntityType("user").Resolve()!;
IEntityType adminType = tx.Concepts.PutEntityType("admin").Resolve()!;
adminType.SetSupertype(tx, userType);
IEnumerable<IType> entities = tx.Concepts.RootEntityType.GetSubtypes(tx, IConcept.Transitivity.Transitive);
foreach (IType entity in entities) {
Console.WriteLine(entity.Label);
}
tx.Commit();
}
}
TypeDB::Options options;
TypeDB::Session session = driver.session(DB_NAME, TypeDB::SessionType::SCHEMA, options);
{
TypeDB::Transaction tx = session.transaction(TypeDB::TransactionType::WRITE, options);
std::unique_ptr<TypeDB::EntityType> userType = tx.concepts.getEntityType("user").get();
std::unique_ptr<TypeDB::EntityType> adminType = tx.concepts.putEntityType("admin").get();
adminType.get()->setSupertype(tx, userType.get()).wait();
TypeDB::ConceptIterable<TypeDB::EntityType> entities = tx.concepts.getRootEntityType().get()->getSubtypes(tx, TypeDB::Transitivity::TRANSITIVE);
for (std::unique_ptr<TypeDB::EntityType>& entity : entities) {
std::cout << entity.get()->getLabel() << std::endl;
}
tx.commit();
}
Options* opts = options_new();
session = session_new(databaseManager, DB_NAME, Schema, opts);
tx = transaction_new(session, Write, opts);
if ((tx == NULL) || FAILED()) {
handle_error("Transaction failed to start.");
goto cleanup;
}
Concept* userType = concept_promise_resolve(concepts_get_entity_type(tx, "user"));
Concept* adminType = concept_promise_resolve(concepts_put_entity_type(tx, "admin"));
entity_type_set_supertype(tx, adminType, userType);
ConceptIterator* entities = entity_type_get_subtypes(tx, concepts_get_root_entity_type(), Transitive);
Concept* entity;
while ((entity = concept_iterator_next(entities)) != NULL) {
printf("%s\n", thing_type_get_label(entity));
}
void_promise_resolve(transaction_commit(tx));
if (FAILED()) {
handle_error("Transaction commit failed.");
goto cleanup;
}
session_close(session);
For an additional example of programmatic type manipulations, see the Schema editing page.
Rule objects
A rule object has label
, when
, and then
properties and just a few methods.
To manipulate a rule with driver API methods, you need to get a stateful object that represents the rule in the database.
Get a rule
Rules can be defined with a TypeQL query (see Define query), but they can’t be retrieved with one. To get a rule object from a TypeDB database, you need to use the Logic class methods of a driver API.
Get a rule object by its label
Use rule’s label to retrieve the rule object.
For example, to get a stateful object of the rule with the label Employee
, use:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let old_rule = tx.logic().get_rule("users".to_owned()).resolve()?.ok_or("Rule not found.")?;
old_rule = tx.logic.get_rule("users").resolve()
let oldRule = (await tx.logic.getRule("users")).label;
Rule oldRule = tx.logic().getRule("users").resolve();
IRule oldRule = tx.Logic.GetRule("users").Resolve()!;
TypeDB::Rule oldRule = tx.logic.getRule("users").get().value();
Rule* oldRule = rule_promise_resolve(logic_manager_get_rule(tx, "users"));
Get all rules
Use get rules method to retrieve all rules in a schema:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let rules = tx.logic().get_rules()?;
for rule in rules {
println!("{}", rule.clone()?.label);
println!("{}", rule.clone()?.when.to_string());
println!("{}", rule.clone()?.then.to_string());
}
rules = tx.logic.get_rules()
for rule in rules:
print(rule.label)
print(rule.when)
print(rule.then)
let rules = await tx.logic.getRules();
for await (const rule of rules) {
console.log(rule.label);
console.log(rule.when);
console.log(rule.then);
}
tx.logic().getRules().forEach(result -> {
System.out.println(result.getLabel());
System.out.println(result.getWhen().toString());
System.out.println(result.getThen().toString());
});
IEnumerable<IRule> rules = tx.Logic.GetRules();
foreach (IRule rule in rules) {
Console.WriteLine(rule.Label);
Console.WriteLine(rule.When);
Console.WriteLine(rule.Then);
}
TypeDB::RuleIterable rules = tx.logic.getRules();
for (TypeDB::Rule& rule : rules) {
std::cout << rule.label() << std::endl;
std::cout << rule.when() << std::endl;
std::cout << rule.then() << std::endl;
}
RuleIterator* rules = logic_manager_get_rules(tx);
Rule* rule;
while ((rule = rule_iterator_next(rules)) != NULL) {
printf("%s\n%s\n%s\n", rule_get_label(rule), rule_get_when(rule), rule_get_then(rule));
}
Add a rule
Use the following methods to add a rule to the schema of a database:
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let condition = typeql::parse_pattern("{$u isa user, has email $e; $e contains '@typedb.com';}")?
.into_conjunction();
let conclusion = typeql::parse_pattern("$u has name 'Employee'")?.into_statement();
let mut new_rule = tx.logic().put_rule("Employee".to_string(), condition, conclusion).resolve()?;
new_rule = tx.logic.put_rule("Employee",
"{$u isa user, has email $e; $e contains '@typedb.com';}",
"$u has name 'Employee'").resolve()
let newRule = await tx.logic.putRule("Employee","{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'");
Pattern condition = TypeQL.parsePattern("{$u isa user, has email $e; $e contains '@typedb.com';}");
Pattern conclusion = TypeQL.parsePattern("$u has name 'Employee'");
Rule newRule = tx.logic().putRule("Employee", condition, conclusion).resolve();
IRule newRule = tx.Logic.PutRule("Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'").Resolve()!;
TypeDB::Rule newRule = tx.logic.putRule("Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'").get();
Rule* newRule = rule_promise_resolve(logic_manager_put_rule(tx, "Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}", "$u has name 'Employee'"));
Rule manipulation
A stateful rule object has just a few methods: get/set label, delete, and is_deleted.
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let _ = new_rule.delete(&tx).resolve();
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
new_rule.delete(tx).resolve()
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
await newRule.delete(tx);
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
newRule.delete(tx).resolve();
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
newRule.Delete(tx).Resolve();
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
newRule.deleteRule(tx).get();
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
rule_delete(tx, newRule);
The above example deletes the type, which type object is stored in the variable, from the schema of a database. You need to commit transaction to persist the changes.
Full example
See below a comprehensive example of rules manipulation: retrieving all rules, printing label, condition (when) and conclusion(then), adding a new rule, retrieving a rule by its label, and deleting a rule.
See below a more comprehensive example of rule objects manipulation.
In this example we retrieve the users
rule object and print its label, condition, and conclusion.
Then we add a new rule Employee
and retrieve all rules to print their labels.
-
Rust
-
Python
-
Node.js
-
Java
-
C#
-
C++
-
C
let db = databases.get(DB_NAME)?;
{
let session = Session::new(db, SessionType::Schema)?;
{
let tx = session.transaction(TransactionType::Write)?;
let rules = tx.logic().get_rules()?;
for rule in rules {
println!("{}", rule.clone()?.label);
println!("{}", rule.clone()?.when.to_string());
println!("{}", rule.clone()?.then.to_string());
}
let condition = typeql::parse_pattern("{$u isa user, has email $e; $e contains '@typedb.com';}")?
.into_conjunction();
let conclusion = typeql::parse_pattern("$u has name 'Employee'")?.into_statement();
let mut new_rule = tx.logic().put_rule("Employee".to_string(), condition, conclusion).resolve()?;
let _ = new_rule.delete(&tx).resolve();
let old_rule = tx.logic().get_rule("users".to_owned()).resolve()?.ok_or("Rule not found.")?;
let _ = tx.commit().resolve();
}
}
with driver.session(DB_NAME, SessionType.SCHEMA) as session:
with session.transaction(TransactionType.WRITE) as tx:
rules = tx.logic.get_rules()
for rule in rules:
print(rule.label)
print(rule.when)
print(rule.then)
new_rule = tx.logic.put_rule("Employee",
"{$u isa user, has email $e; $e contains '@typedb.com';}",
"$u has name 'Employee'").resolve()
new_rule.delete(tx).resolve()
old_rule = tx.logic.get_rule("users").resolve()
print(old_rule.label)
tx.commit()
try {
session = await driver.session(DB_NAME, SessionType.SCHEMA);
try {
tx = await session.transaction(TransactionType.WRITE);
for await (const rule of tx.logic.getRules()) {
console.log(rule.label);
console.log(rule.when);
console.log(rule.then);
}
let newRule = await tx.logic.putRule("Employee","{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'");
console.log((await tx.logic.getRule("users")).label);
await newRule.delete(tx);
await tx.commit();
}
finally {if (tx.isOpen()) {await tx.close()};}
}
finally {await session?.close();}
try (TypeDBSession session = driver.session(DB_NAME, TypeDBSession.Type.SCHEMA)) {
try (TypeDBTransaction tx = session.transaction(TypeDBTransaction.Type.WRITE)) {
tx.logic().getRules().forEach(result -> {
System.out.println(result.getLabel());
System.out.println(result.getWhen().toString());
System.out.println(result.getThen().toString());
});
Pattern condition = TypeQL.parsePattern("{$u isa user, has email $e; $e contains '@typedb.com';}");
Pattern conclusion = TypeQL.parsePattern("$u has name 'Employee'");
Rule newRule = tx.logic().putRule("Employee", condition, conclusion).resolve();
Rule oldRule = tx.logic().getRule("users").resolve();
System.out.println(oldRule.getLabel());
newRule.delete(tx).resolve();
tx.commit();
}
}
using (ITypeDBSession session = driver.Session(DB_NAME, SessionType.Schema)) {
using (ITypeDBTransaction tx = session.Transaction(TransactionType.Write)) {
IEnumerable<IRule> rules = tx.Logic.GetRules();
foreach (IRule rule in rules) {
Console.WriteLine(rule.Label);
Console.WriteLine(rule.When);
Console.WriteLine(rule.Then);
}
IRule newRule = tx.Logic.PutRule("Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'").Resolve()!;
IRule oldRule = tx.Logic.GetRule("users").Resolve()!;
Console.WriteLine(oldRule.Label);
newRule.Delete(tx).Resolve();
tx.Commit();
}
}
TypeDB::Options options;
TypeDB::Session session = driver.session(DB_NAME, TypeDB::SessionType::SCHEMA, options);
{
TypeDB::Transaction tx = session.transaction(TypeDB::TransactionType::WRITE, options);
TypeDB::RuleIterable rules = tx.logic.getRules();
for (TypeDB::Rule& rule : rules) {
std::cout << rule.label() << std::endl;
std::cout << rule.when() << std::endl;
std::cout << rule.then() << std::endl;
}
TypeDB::Rule newRule = tx.logic.putRule("Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}","$u has name 'Employee'").get();
TypeDB::Rule oldRule = tx.logic.getRule("users").get().value();
std::cout << oldRule.label() << std::endl;
newRule.deleteRule(tx).get();
tx.commit();
}
Options* opts = options_new();
session = session_new(databaseManager, DB_NAME, Schema, opts);
tx = transaction_new(session, Write, opts);
if ((tx == NULL) || FAILED()) {
handle_error("Transaction failed to start.");
goto cleanup;
}
RuleIterator* rules = logic_manager_get_rules(tx);
Rule* rule;
while ((rule = rule_iterator_next(rules)) != NULL) {
printf("%s\n%s\n%s\n", rule_get_label(rule), rule_get_when(rule), rule_get_then(rule));
}
Rule* newRule = rule_promise_resolve(logic_manager_put_rule(tx, "Employee", "{$u isa user, has email $e; $e contains '@typedb.com';}", "$u has name 'Employee'"));
Rule* oldRule = rule_promise_resolve(logic_manager_get_rule(tx, "users"));
printf("%s\n", rule_get_label(oldRule));
rule_delete(tx, newRule);
void_promise_resolve(transaction_commit(tx));
if (FAILED()) {
handle_error("Transaction commit failed.");
goto cleanup;
}
session_close(session);