# Lesson 4.2: Inserting polymorphic data

## [](#_inferring_types)Inferring types

In the previous lesson, we saw how we could use `match` clauses in Insert queries in order to have new data reference existing data. In this lesson, we’ll see how we can use that strategy to perform **polymorphic inserts**. We have already created a new `promotion` entity for the Spring Sale with this query from a previous exercise.

```typeql
insert
$spring-sale isa promotion,
    has code "SPR24",
    has name "Spring Sale 2024",
    has start-timestamp 2024-03-15T00:00:00,
    has end-timestamp 2024-03-31T23:59:59;
```

**→ Run, but don’t commit - we don’t want these changes!**

However, we have not yet assigned any books to this sale. This sale is a pretty big one, so we’re going to assign every book in the store to it with a 10% discount.

```typeql
match
$spring-sale isa promotion, has code "SPR24";
$book isa book;
insert
$rel isa promotion-inclusion,
  links (promotion: $spring-sale, item: $book),
  has discount 0.10;
```

_→ Commit this one!_

By matching books using the supertype `book`, this query will add all books to the promotion, regardless of whether they are paperbacks, hardbacks, or ebooks. In this case, TypeDB is using **type inference** to resolve the inheritance polymorphism in the write query. We can just as easily use interface or parametric polymorphism in data writes!

Exercise

Write three new Insert queries. The first should create a new promotion with the following details:

*   The code "SFF24".
    
*   The name "Sci-Fi & Fantasy Festival 2024".
    
*   The start date (inclusive) 19th April 2024.
    
*   The end date (exclusive) 27th April 2024.
    

The second should match any book with a `genre` attribute with the value `"science fiction"` and add it to the promotion with a 15% discount. The third should match any book with the genre `"fantasy"` and add it with a 20% discount.

Sample solution

```typeql
insert
$sff-festival isa promotion,
    has code "SFF24",
    has name "Sci-Fi & Fantasy Festival 2024",
    has start-timestamp 2024-04-19T00:00:00,
    has end-timestamp 2024-04-26T23:59:59;
```

```typeql
match
$sff-festival isa promotion, has code "SFF24";
$book isa book, has genre "science fiction";
insert
promotion-inclusion (promotion: $sff-festival, item: $book),
  has discount 0.15;
```

```typeql
match
$sff-festival isa promotion, has code "SFF24";
$book isa book, has genre "fantasy";
insert
promotion-inclusion (promotion: $sff-festival, item: $book),
  has discount 0.20;
```

_→ Commit!_

## [](#_inferring_roles)Inferring roles

In addition to inferring types of referenced data, TypeDB is able to infer the roles of role players when inserting new relations. This allows us to write significantly more concise Insert queries. For example, in the following query, we insert `rating` and `action-execution` relations without specifying roles!

```typeql
match
$user-11 isa user, has id "u0011";
$frankenstein isa book, has isbn-13 "9780486282114";
insert
$review isa review, has id "r0034",
    has score 8;
rating ($review, $frankenstein);
action-execution ($review, $user-11),
  has timestamp 2024-03-19T03:32:00.073;
```

_→ Commit!_

For this query, TypeDB is able to infer that `$review` plays the `review` role and `$frankenstein` plays the `rated` role in rating. This is because:

*   `rating` has roles `rating:review` and `rating:rated`.
    
*   `$review` is of type `review`.
    
*   `review` plays `rating:review` but not `rating:rated`.
    
*   `$frankenstein` is of type `book`.
    
*   `book` plays `rating:rated` but not `rating:review`.
    

These constraints mean that TypeDB can infer the roles of `$review` and `$frankenstein` unambiguously, as they could not play any other roles. The same applies to the `action-execution` relation. Conversely, if one or more of the role players _can_ play multiple roles, then TypeDB is unable to infer them and throws an exception. Consider the following query, for instance.

```typeql
match
$us isa country, has name "United States";
$ma isa state, has name "Massachusetts";
insert
locating ($us, $ma);
```

The types `country` and `state` can play both `location:location` and `location:located`, so any of the following four combinations of roles would be valid:

*   `(location: $us, located: $ga) isa locating;`
    
*   `(located: $us, location: $ga) isa locating;`
    
*   `(location: $us, location: $ga) isa locating;`
    
*   `(located: $us, located: $ga) isa locating;`
    

It is obvious to us that the first statement is the correct one, but TypeDB cannot determine this unambiguously, so we would have to specify the roles when inserting this particular `locating` relation.

Exercise

_Frankenstein_ is often considered to be one of the earliest works of science fiction, but is instead listed under the "horror" genre in the bookstore database. As a result, it wasn’t added to the Sci-Fi & Fantasy Festival promotion by our previous query. Insert a new relation to explicitly add it to the promotion with a 15% discount, and use **role inference** to avoid specifying any necessary roles.

Sample solution

```typeql
match
$sff-festival isa promotion, has code "SFF24";
$frankenstein isa book, has isbn-13 "9780486282114";
insert
promotion-inclusion ($sff-festival, $frankenstein),
  has discount 0.15;
```

_→ Commit_

[Inserting simple data](../4.1-inserting-simple-data/index.md) [Deleting data](../4.3-deleting-data/index.md)

[Edit on GitHub](https://github.com/typedb/typedb-docs/edit/3.x-development/academy/modules/ROOT/pages/4-writing-data/4.2-inserting-polymorphic-data.adoc) Edit this page on GitHub.