relationalai.dsl.InstanceProperty
class relationalai.InstanceProperty
InstanceProperty
is a subclass of Producer
that
produces property values within rule and query contexts.
They are created by accessing attributes of an Instance
.
Example
Section titled “Example”As producers, instances of InstanceProperty
serve as variables in
rules or queries that represent property values of objects.
You create them by accessing attributes of an Instance
:
import relationalai as rai
# Create a model named "books" with a Book type.model = rai.Model("books")Book = model.Type("Book")
# Add some books to the model.with model.rule(): # Each call to `Book.add` creates a book with title, author, and year_published properties. Book.add(title="Foundation", author="Isaac Asimov", year_published=1951) Book.add(title="Foundation and Empire", author="Isaac Asimov", year_published=1952) Book.add(title="Dune", author="Frank Herbert") # Note that year_published is not set.
# Get the names of books authored by Isaac Asimov.with model.query() as select: # Get all books. book = Book() # InstanceProperty objects are created by accesing an attribute of an Instance, like book.author. # Here it is used in an expression to filter books by author. book.author == "Isaac Asimov" # Select the book.title property to include in the query result. response = select(book.title)
print(response.results)# Output:# title# 0 Foundation# 1 Foundation and Empire
Envision this rule executing for each book in the model, with each book passing through the rule’s criteria sequentially:
Book()
returns anInstance
that produces aBook
object.book.author
returns anInstanceProperty
for the author’s name. The==
operator filters books by comparingbook.author
to “Isaac Asimov”.book.title
returns anInstanceProperty
for the book’s title, which is selected in the query results.
InstanceProperty
supports various comparison and mathematical operators such as ==
, !=
, <
, +
, -
, *
, /
, and %
.
The following example demonstrates using the %
operator with InstanceProperty
to filter books published in an even-numbered year:
# Get books published in an even numbered year.with model.query() as select: book = Book() book.year_published % 2 == 0 # Filter books by even year. response = select(book.title, book.year_published)
print(response.results)# Output:# title year_published# 0 Foundation and Empire 1952
For the full list of supported operators, see the Producer
class documentation.
By default, InstanceProperty
outputs None
for undefined properties,
which may display as NaN
in the query’s pandas DataFrame
depending on the property’s data type.
# Get the genre and rating of each book.with model.query() as select: book = Book() response = select(book.title, book.year_published)
print(response.results)# Output:# title year_published# 0 Dune NaN# 1 Foundation 1951.0# 2 Foundation and Empire 1952.0
Use .or_()
to assign default values to properties lacking explicit values:
with model.query() as select: book = Book() response = select(book.title, book.year_published.or_(-1))
print(response.results)# Output:# title year_published# 0 Dune -1# 1 Foundation 1951# 2 Foundation and Empire 1952
You can check if a property has a value and is not None
using .has_value()
:
# Get books that have a year published.with model.query() as select: book = Book() book.year_published.has_value() # Filter books that have a year published. response = select(book.title, book.year_published)
print(response.results)# Output:# title year_published# 0 Foundation 1951# 1 Foundation and Empire 1952
By default, properties support only a single value, and setting a new value overwrites the previous one.
You can create and manage multi-valued properties by using .add()
or .extend()
:
# Add genres to the books.# genres is a multi-valued property because it is created with Instance.extend().with model.rule(): Book(title="Foundation").genres.extend(["Science Fiction"]) Book(title="Dune").genres.extend(["Science Fiction", "Adventure"])
# Get the genres of all books.with model.query() as select: book = Book() # Select the title and genres properties of the books. # `.or_()` sets a default value of "Unknown" for books without genres. response = select(book.title, book.genres.or_("Unknown"))
print(response.results)
See the documentation for .add()
and .extend()
for further details on multi-valued properties.
Methods
Section titled “Methods”In addition to the methods inherited from Producer
, InstanceProperty
supports:
Name | Description | Returns |
---|---|---|
.or_() | Set a default property value on objects lacking a value. | InstanceProperty |
.in_() | Check if the property value is in a collection. | Expression |
.add() | Add a value to a property, creating the property if it doesn’t exist. | None |
.extend() | Extend a multi-valued property with multiple values from an iterable, creating the property if it doesn’t exist. | None |
.choose() | Choose n values from a multi-valued property. | tuple of n Instance |
.set() | Set properties or assigns types to the object associated with the current InstanceProperty . | Instance |
.has_value() | Check if the property has a value and is not None . | InstanceProperty |
.add()
Section titled “.add()”InstanceProperty.add(other: Any) -> None
Adds a value to a multi-valued property and creates the property if it doesn’t exist. Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | The value to be added to the property. Acceptable value types include Producer objects, as well as numbers, strings, dates, and datetime objects. |
Returns
Section titled “Returns”None
Example
Section titled “Example”import relationalai as rai
# Create a model named "books" with Author and Book types.model = rai.Model("books")Author = model.Type("Author")Book = model.Type("Book")
# Add authors and books to the model.with model.rule(): vonnegut = Author.add(name="Kurt Vonnegut") vonnegut.books.add(Book.add(title="Cat's Cradle")) asimov = Author.add(name="Isaac Asimov") asimov.books.add(Book.add(title="Foundation")) asimov.books.add(Book.add(title="Foundation and Empire"))
# Retrieve titles of books written by Isaac Asimov.with model.query() as select: book = Author(name="Isaac Asimov").books response = select(book.title)
print(response.results)# Output:# title# 0 Foundation# 1 Foundation and Empire
In the example above, vonnegut.books.add()
creates the multi-valued property books
for the vonnegut
object.
In contrast, the Author.name
property is single-valued as it is defined through Type.add()
.
Single-valued properties can also be established using Instance.set()
.
Calling InstanceProperty.add()
on a single-valued property raises an Exception
:
# Attempt to add a second author name to the book titled "Foundation".# The author property is single-valued because it is created with Instance.add().with model.rule(): Author(name="Isaac Asimov").name.add("Paul French")
# Output:# Exception: Trying to use a property `name` as both singular and multi-valued
You can add values to multi-valued properties across multiple rules.
For instance, the next rule adds another book to Kurt Vonnegut’s books
property:
with model.rule(): author = Author(name="Kurt Vonnegut") author.books.add(Book.add(title="Slaughterhouse-Five"))
with model.query() as select: book = Author(name="Kurt Vonnegut").books response = select(book.title)
print(response.results)# Output:# title# 0 Cat's Cradle# 1 Slaughterhouse-Five
To add multiple values at once, use the InstanceProperty.extend()
method:
with model.rule(): author = Author.add(name="Frank Herbert") author.books.extend([Book.add(title="Dune"), Book.add(title="Dune Messiah")])
.choose()
Section titled “.choose()”InstanceProperty.choose(n: int, unique: bool = True) -> tuple[Producer]
Chooses n
-combinations of values from a multi-valued property and
returns them as a tuple (v1, v2, ..., vn)
of Producer
objects.
By default, combinations are sorted in ascending order with no repeated values.
If unique
is False
, all possible n
-permutations with repeated values are produced.
Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
n | int | The number of values to choose. Must be a positive integer. |
unique | bool | If True , the combination is sorted in ascending order with no repeated values. If False , all possible permutations (including repeated values) are produced. Default is True . |
Returns
Section titled “Returns”A tuple of n
Producer
objects.
Example
Section titled “Example”Use .choose()
the get pairs, triples, or other combinations of values from a multi-valued property:
import relationalai as rai
# Create a model named "books" with Author and Book types.model = rai.Model("books")Author = model.Type("Author")Book = model.Type("Book")
# Add some authors and books to the model.with model.rule(): Author.add(name="Kurt Vonnegut").books.add(Book.add(title="Cat's Cradle")) Author.add(name="Isaac Asimov").books.extend([ Book.add(title="Foundation"), Book.add(title="Foundation and Empire") ])
# Get pairs of books written by the same author.with model.query() as select: author = Author() book1, book2 = author.books.choose(2) response = select(book1.title, book2.title)
print(response.results)# Output:# title title2# 0 Foundation Foundation and Empire
The model only contains one book for Kurt Vonnegut, so it is impossible to choose two unique books, which is why the dataframe returned by the query only contains titles of books by Isaac Asimov.
Set unique=False
to get all possible permutations (including repeated values) of books by the same author:
with model.query() as select: author = Author() book1, book2 = author.books.choose(2, unique=False) response = select(book1.title, book2.title)
print(response.results)# Output:# title title2# 0 Cat's Cradle Cat's Cradle# 1 Foundation Foundation# 2 Foundation Foundation and Empire# 3 Foundation and Empire Foundation# 4 Foundation and Empire Foundation and Empire
.choose()
should only be used with multi-valued properties.
Calling it on a single-valued property, such a book’s title
property, returns producers that produce no values:
with model.query() as select: title1, title2 = Book().title.choose(2) respose = select(title1, title2)
print(response.results)# Output:# Empty DataFrame# Columns: []# Index: []
Passing a 0
or a negative value to .choose()
raises a ValueError
:
with model.query() as select: title = Book().title.choose(0) response = select(title)
# Output:# ValueError: Must choose a positive number of items
.extend()
Section titled “.extend()”InstanceProperty.extend(others: Iterable[Any]) -> None
Extends a multi-valued property of an Instance
with values
from an iterable and creates the property if it doesn’t exist.
Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
others | Iterable[Any] | The values to add to the property. Acceptable value types include Producer objects, as well as numbers, strings, dates, and datetime objects. |
Returns
Section titled “Returns”None
Example
Section titled “Example”import relationalai as rai
# Create a model named "books" with Author and Book types.model = rai.Model("books")Author = model.Type("Author")Book = model.Type("Book")
# Add multiple books to an author using extend.with model.rule(): herbert = Author.add(name="Frank Herbert") herbert.books.extend([ Book.add(title="Dune"), Book.add(title="Dune Messiah"), Book.add(title="Children of Dune") ])
# Get the titles of books written by Frank Herbert.with model.query() as select: # Get all books by Frank Herbert. book = Author(name="Frank Herbert").books # Select the title property of the book. response = select(book.title)
print(response.results)# Output:# title# 0 Children of Dune# 1 Dune# 2 Dune Messiah
In the example above, herbert.books.extend()
creates the multi-valued property books
for the herbert
object.
In contrast, the Author.name
property is single-valued as it is defined through Type.add()
.
Single-valued properties can also be established using Instance.set()
.
Calling InstanceProperty.extend()
on a single-valued property raises an Exception
:
# Attempting to extend the author name property with multiple values fails.# The author property is single-valued because it was created with Type.add().with model.rule(): Author(name="Isaac Asimov").name.extend( ["Franklin Herbert", "Franklin Patrick Herbert, Jr."] )
# Output:# Exception: Trying to use a property `name` as both singular and multi-valued
Single values can be added to a multi-valued property by passing an iterable containing one value,
or directly using the InstanceProperty.add()
method.
You can extend multi-valued properties across multiple rules.
For instance, the next rule adds two more books to Frank Herbert’s books
property:
with model.rule(): author = Author(name="Frank Herbert") author.books.extend([ Book.add(title="God Emperor of Dune"), Book.add(title="Heretics of Dune") ])
.has_value()
Section titled “.has_value()”InstanceProperty.has_value() -> InstanceProperty
Checks if a property has a value and is not None
.
Useful for filtering objects where the property is defined and has a non-null value.
Must be called in a rule or query context.
Returns
Section titled “Returns”An InstanceProperty
object representing the property with a value check applied.
Example
Section titled “Example”Use has_value()
to filter objects with defined property values:
import relationalai as rai
# Create a model named "books" with a Book type.model = rai.Model("books")Book = model.Type("Book")
# Add some books to the model.with model.rule(): # Each call to `Book.add` creates a book with title, author, and year_published properties. Book.add(title="Foundation", author="Isaac Asimov", year_published=1951) Book.add(title="Foundation and Empire", author="Isaac Asimov", year_published=1952) Book.add(title="Dune", author="Frank Herbert") # Note that year_published is not set.
# Get books that have a year published.with model.query() as select: book = Book() book.year_published.has_value() # Filter books that have a year published. response = select(book.title, book.year_published)
print(response.results)# Output:# title year_published# 0 Foundation 1951# 1 Foundation and Empire 1952
If you don’t use has_value()
, the output includes books with None
values for the year_published
property:
# Get books and their year published without filtering.with model.query() as select: book = Book() response = select(book.title, book.year_published)
print(response.results)# Output:# title year_published# 0 Dune NaN# 1 Foundation 1951.0# 2 Foundation and Empire 1952.0
.in_()
Section titled “.in_()”InstanceProperty.in_(others: Iterable[Any]) -> Expression
Checks if any of the values produced by InstanceProperty
are contained in others
.
Returns an Expression
that filters objects and property values
based on their membership in the others
iterable.
Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
others | Iterable[Any] | Collection of values for checking membership. Supports Producer objects, numbers, strings, dates, and datetime objects. |
Returns
Section titled “Returns”An Expression
object that filters objects and property values based on their membership in the others
collection.
Example
Section titled “Example”Use .in_()
to filter objects in a rule or query context,
checking if their property values exist within a specified collection:
import relationalai as rai
# Create a model named "books" with a Book type.model = rai.Model("books")Book = model.Type("Book")
# Add some books to the model.with model.rule(): Book.add(title="Foundation", author="Isaac Asimov") Book.add(title="Cat's Cradle", author="Kurt Vonnegut") Book.add(title="Dune", author="Frank Herbert")
# Get the titles of books written by Kurt Vonnegut or the author of Foundation.with model.query() as select: book = Book() # Get all book objects. book.author.in_(["Kurt Vonnegut", Book(title="Foundation").author]) # Filter books by author in the collection. response = select(book.title, book.author) # Select the title and author properties of the books.
print(response.results)# Output:# title author# 0 Cat's Cradle Kurt Vonnegut# 1 Foundation Isaac Asimov
In the above example, book
is an Instance
that produces Book
objects.
book.author.in_()
returns an Expression
that filters books to include
only those authored by "Kurt Vonnegut"
or the author of "Foundation"
.
If no authors from the collection match, the query yields no results:
with model.query() as select: book = Book() # Get all book objects. book.author.in_(["Ted Chiang", "J.R.R. Tolkien"]) # Filter books by author in the collection. response = select(book.title, book.author) # Select the title and author properties of the books.
print(response.results)# Output:# Empty DataFrame# Columns: []# Index: []
.in_()
also works with multi-valued properties,
such as properties created with .add()
or .extend()
:
# Add genres to the books.# The genre property is multi-valued because it is created with Instance.extend().with model.rule(): Book(title="Foundation").genres.extend(["Science Fiction", "Space Opera"]) Book(title="Cat's Cradle").genres.extend(["Science Fiction", "Satire"]) Book(title="Dune").genres.extend(["Science Fiction", "Space Opera"])
# Get books with the genre "Satire", "Fantasy", or both.with model.query() as select: book = Book() # Get all book objects. book.genres.in_(["Satire", "Fantasy"]) # Filter books by genre in the collection. response = select(book.title, book.author, book.genres) # Select the title and genre properties of the books.
print(response.results)# Output:# title author genres# 0 Cat's Cradle Kurt Vonnegut Satire
Note that only the "Satire"
genre appears in the results.
This is because book.genres
produces multiple values, and .in_()
filters both the book
objects and their genres
.
Consequently, only genres that meet the filter criteria are included in the final results.
.or_()
Section titled “.or_()”InstanceProperty.or_(other: Any) -> InstanceProperty
Produces a default property value for objects for which the property is not set.
Returns an InstanceProperty
that produces the original values, along with the default value other
.
Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | The default property value. Supported types include Producer objects, numbers, strings, dates, and datetime objects. For optimal performance, the type should match the values produced by the InstanceProperty . |
Returns
Section titled “Returns”An InstanceProperty
object.
Example
Section titled “Example”Use .or_()
to assign a default property value to objects where the property is either unset or set to None
:
import relationalai as rai
# Create a model named "books" with a Book type.model = rai.Model("books")Book = model.Type("Book")
# Add some books to the model.with model.rule(): Book.add(title="Foundation", author="Isaac Asimov") Book.add(title="Dune", author="Frank Herbert") Book.add(title="Sir Gowain and the Green Knight") # No author.
# Get the title and publication year of all books.with model.query() as select: # Get all book objects. book = Book() # Select the title and author properties of the books. # `.or_()` sets a default value of "Unknown" for books without an author. response = select(book.title, book.author.or_("Unknown"))
print(response.results)# Output:# title author# 0 Dune Frank Herbert# 1 Foundation Isaac Asimov# 2 Sir Gowain and the Green Knight Unknown
Above, book
is an Instance
that produces Book
objects.
book.author.or_("Unknown")
returns an InstanceProperty
that produces the author’s name
or "Unknown"
if the book lacks an author
property, such as in “Sir Gawain and the Green Knight.”
Without .or_()
, the query outputs None
for books lacking an author.
In the resulting pandas DataFrame
, None
may appear as NaN
, depending on the column type:
# Get the title and publication year of all books.with model.query() as select: book = Book() response = select(book.title, book.author) # .or() is not used.
print(response.results)# Output:# title author# 0 Dune Frank Herbert# 1 Foundation Isaac Asimov# 2 Sir Gowain and the Green Knight NaN
.or_()
also works with multi-valued properties created using .add()
or .extend()
:
# Add genres to the books.# genres is a multi-valued property because it is created with Instance.extend().with model.rule(): Book(title="Foundation").genres.extend(["Science Fiction"]) Book(title="Dune").genres.extend(["Science Fiction", "Adventure"])
# Get the genres of all books.with model.query() as select: book = Book() # Select the title and genres properties of the books. # `.or_()` sets a default value of "Unknown" for books without genres. response = select(book.title, book.genres.or_("Unknown"))
print(response.results)# Output:# title genres# 0 Dune Adventure# 1 Dune Science Fiction# 2 Foundation Science Fiction# 3 Sir Gowain and the Green Knight Unknown
.set()
Section titled “.set()”InstanceProperty.set(*args: Type, **kwargs: Any) -> Instance
Set properties or assigns types to objects produced by an InstanceProperty
object.
Returns the Instance
object on which the property or type is set.
Must be used in a rule or query context.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
*args | Type | Optional types to apply to the object. |
**kwargs | Any | Properties to set on the objects with <property_name>=<value> format. Accepts Producer objects, numbers, strings, dates, and datetime objects. |
Returns
Section titled “Returns”Returns the Instance
object on which the property or type is set.
Example
Section titled “Example”Use .set()
to assign properties and types directly on objects associated with a specific property:
import relationalai as rai
# Create a model named "books" with Author and Book types.model = rai.Model("books")Author = model.Type("Author")Book = model.Type("Book")
# Add some authors and books to the model.with model.rule(): Book.add(title="Foundation", author=Author.add(name="Isaac Asimov"))
# Set a note property on the author of the Foundation book.with model.rule(): Book(title="Foundation").author.set(note="Science fiction author")
with model.query() as select: author = Author() response = select(author.name, author.note)
print(response.results)# Output:# name note# 0 Isaac Asimov Science fiction author
.set()
also works with multi-valued properties created using .add()
or .extend()
:
# Add a books property to the Author type.with model.rule(): # Get all books book = Book() # Get the author of the book. author = book.author # Create multi-values books property for the author and add the book to it. # books multi-valued because it is created with InstanceProperty.add(). author.books.add(book)
# Set the genre property to "Science Fiction" on books by Isaac Asimov.with model.rule(): Author(name="Isaac Asimov").books.set(genre="Science fiction")
# Get the names of authors and the titles and genres of their books.with model.query() as select: # Get all author objects. author = Author() # Select the name of the author and the title and genre of their books. response = select(author.name, author.books.title, author.books.genre)
print(response.results)# Output:# name title genre# 0 Isaac Asimov Foundation Science fiction
InstanceProperty.set()
works exactly the same as Instance.set()
.
See the Instance.set()
documentation for more examples and details.