Skip to content

relationalai.dsl.ContextSelect

class ContextSelect

ContextSelect objects are returned by the Context.__enter__() method. They are used to select results in query contexts. ContextSelect objects are also used in Model.match() contexts as a variable to which values are conditionally assigned.

Both Model.query() and Model.match() return Context objects. A Context is a context manager and must be used in a with statement.

ContextSelect objects are returned by the Context.__enter__() method, which is called automatically when the with statement executes. The ContextSelect object it returns can be named in the with statement’s as clause.

In queries, the ContextSelect object is used to select the data to be returned. By convention, we name the ContextSelect object select. You call select() at the end of the query and pass to it the objects, properties, and variables you want returned in the results:

import relationalai as rai
# =====
# SETUP
# =====
model = rai.Model("MyModel")
Item = model.Type("Item")
with model.rule():
Item.add(id=1).set(name="A", price=10.00)
Item.add(id=2).set(name="B", price=10.00)
Item.add(id=3).set(name="C", price=20.00)
# =======
# EXAMPLE
# =======
with model.query() as select: # select is a ContextSelect object
item = Item()
# Calling select returns the Context object created by model.query().
response = select(item.id, item.name, item.price)
# The query results are assigned to the response.results attribute.
print(response.results)
# id name price
# 0 1 A 10.0
# 1 2 B 10.0
# 2 3 C 20.0
# Rows for each item filtered by the query are returned in the results. This
# means duplicate rows may be returned:
with model.query() as select:
item = Item()
response = select(item.price)
# There are two rows with 10.00 in the results because there are two two items
# with a price of 10.00.
print(response.results)
# price
# 0 10.0
# 1 10.0
# 2 20.0
# Use select.distinct() to return only unique rows in the results:
with model.query() as select:
item = Item()
response = select.distinct(item.price)
print(response.results)
# price
# 0 10.0
# 1 20.0

In a Model.match() context, the ContextSelect object represents a variable to which values are conditionally assigned. Give the ContextSelect object a descriptive name and use the ContextSelect.add() method to assign values to it:

from relationalai.std import alias
# Compute an item's discount based on its price.
with model.query() as select:
item = Item()
with model.match() as discount: # discount is a ContextSelect object
# Items with a price greater than 15 get a 25% discount.
with item.price > 15:
discount.add(0.25) # Assign 0.25 to discount.
# All other items get a 10% discount.
with model.case():
discount.add(0.1)
# Compute the discounted price.
discounted_price = item.price * (1 - discount)
response = select(
item.id,
item.name,
item.price,
alias(discount, "discount"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# id name price discount discounted_price
# 0 1 A 10.0 0.10 9.0
# 1 2 B 10.0 0.10 9.0
# 2 3 C 20.0 0.25 15.0

See Model.match() for more information on .match() contexts.

NameDescriptionReturns
.__call__()Selects query results. Must be called in a query context.Context
.distinct()Selects only distinct rows in the query results. Must be called in a query context.Context
.__getattr__()Accesses properties of values assigned to the ContestSelect. Only used in .match() contexts.Instance or InstanceProperty
.add()Assigns values to the ContextSelect. Only used in .match() contexts.None
ContextSelect.add(item: Any, **kwargs: Any) -> None

Assigns a value to a ContextSelect object. May only be called from ContextSelect objects created in a Model.match() block.

NameTypeDescription
itemAnyThe value to assign to the ContextSelect.
**kwargsAny(Optional) Keyword arguments that set context-specific properties on assigned values.

None

Use .add() to assign values to a ContextSelect object in a Model.match() block:

import relationalai as rai
from relationalai.std import alias
# =====
# SETUP
# =====
model = rai.Model("MyModel")
Item = model.Type("Item")
with model.rule():
Item.add(id=1).set(name="A", price=10.00)
Item.add(id=2).set(name="B", price=10.00)
Item.add(id=3).set(name="C", price=20.00)
# =======
# EXAMPLE
# =======
# Compute an item's discount based on its price.
with model.query() as select:
item = Item()
with model.match() as discount: # discount is a ContextSelect object
# Items with a price greater than 15 get a 25% discount.
with item.price > 15:
discount.add(0.25) # Assign 0.25 to discount.
# All other items get a 10% discount.
with model.case():
discount.add(0.1)
# Compute the discounted price.
discounted_price = item.price * (1 - discount)
response = select(
item.id,
item.name,
item.price,
alias(discount, "discount"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# id name price discount discounted_price
# 0 1 A 10.0 0.10 9.0
# 1 2 B 10.0 0.10 9.0
# 2 3 C 20.0 0.25 15.0

Besides Python strings, numbers, dates, datetimes, and Booleans, expressions involving objects and their properties may also be assigned to a ContextSelect object:

# Declare a Discount type and define some Discount objects.
Discount = model.Type("Discount")
with model.rule():
Discount.add(rate=0.25).set(code="25OFF")
Discount.add(rate=0.10).set(code="10OFF")
# Compute an item's discount based on its price.
with model.query() as select:
item = Item()
with model.match() as discount:
# Items with a price greater than 15 get a 25% discount.
with item.price > 15:
discount.add(Discount(rate=0.25))
# All other items get a 10% discount.
with model.case():
discount.add(Discount(rate=0.10))
# Compute the discounted price. Properties of the Discount object can be
# accessed directly from the discount variable.
discounted_price = item.price * (1 - discount.rate)
response = select(
item.name,
item.price,
alias(discount.code, "discount_code"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# name price discount_code discounted_price
# 0 A 10.0 10OFF 9.0
# 1 B 10.0 10OFF 9.0
# 2 C 20.0 25OFF 15.0

Optional keyword arguments may be passed to .add() to set properties on assigned values. These properties can only be accessed from the ContextSelect object:

with model.query() as select:
item = Item()
with model.match() as discount:
with item.price > 15:
# Assign the Discount object with rate 0.25 to discount and set
# the reason to property to provide context for the discount.
discount.add(Discount(rate=0.25), reason="Over $15")
with model.case():
discount.add(Discount(rate=0.25), reason="$15 or less")
discounted_price = item.price * (1 - discount.rate)
response = select(
item.name,
item.price,
alias(discount.code, "discount_code"),
alias(discounted_price, "discounted_price"),
alias(discount.reason, "reason"), # Access the reason property set by discount.add().
)
print(response.results)
# name price discount_code discounted_price reason
# 0 A 10.0 10OFF 9.0 $15 or less
# 1 B 10.0 10OFF 9.0 $15 or less
# 2 C 20.0 25OFF 15.0 Over $15

The same keyword argument keys must be provided each time you call .add() in one of the .match() block’s branches. Otherwise, an error will be raised.

Properties set in .add() take precedence over properties set elsewhere with the same name:

with model.query() as select:
item = Item()
with model.match() as discount:
with item.price > 15:
# The code property set here takes precedence over the code property
# set on the Discount object.
discount.add(Discount(rate=0.25), code="SUMMER25")
with model.case():
discount.add(Discount(rate=0.10), code="SUMMER10")
discounted_price = item.price * (1 - discount.rate)
response = select(
item.name,
item.price,
alias(discount.code, "discount_code"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# name price discount_code discounted_price
# 0 A 10.0 SUMMER10 9.0
# 1 B 10.0 SUMMER10 9.0
# 2 C 20.0 SUMMER25 15.0

See Model.match() for more information on .match() contexts.

ContextSelect.distinct(*args: Producer) -> Context

Selects the data to be returned by a query and returns the Context object whose .__enter__() method returned the ContextSelect object. Only distinct rows are returned. The query results are assigned to the Context object’s .results attribute. .distinct() may only be called in a query context.

NameTypeDescription
*argsProducer or Python string, number, date, datetime, or Boolean objects.The objects, properties, and other values to return in query results.

A Context object.

Use .distinct() in a query context to select only distinct rows of data:

import relationalai as rai
# =====
# SETUP
# =====
model = rai.Model("Books")
Book = model.Type("Book")
with model.rule():
Book.add(title="The Illiad", author="Homer")
Book.add(title="The Odyssey", author="Homer")
Book.add(title="The Aeneid", author="Virgil")
# =======
# EXAMPLE
# =======
with model.query() as select:
book = Book()
response = select.distinct(book.author)
# Author names in the results are unique.
print(response.results)
# author
# 0 Homer
# 1 Virgil
# Without .distinct, select() returns a row for each book, even if multiple books
# have the same author. For instance, the following query returns two rows for
# Homer because there are two books authored by him.
with model.query() as select:
book = Book()
response = select(book.author)
print(response.results)
# author
# 0 Homer
# 1 Homer
# 2 Virgil
ContextSelect.__call__(*args: Producer) -> Context

Selects the data to be returned in a model.query() block and returns the Context object created by model.query(). The query results are assigned to the Context object’s .results attribute. ContextSelect objects may only be called in a query context.

NameTypeDescription
*argsProducer or Python string, number, date, datetime, or Boolean objects.The objects, properties, and other values to return in query results.

A Context object.

Call a ContextSelect object in a query context to select the data returned by the query:

import relationalai as rai
# =====
# SETUP
# =====
model = rai.Model("Books")
Book = model.Type("Book")
NonFiction = model.Type("NonFiction")
Fiction = model.Type("Fiction")
Horror = model.Type("Horror")
Fantasy = model.Type("Fantasy")
with model.rule():
Book.add(Fiction, Horror, title="It", author="Stephen King", year=1986)
Book.add(Fiction, Fantasy, title="The Dark Tower", author="Stephen King", year=1982)
Book.add(NonFiction, title="On Writing", author="Stephen King", year=2000)
# =======
# EXAMPLE
# =======
with model.query() as select: # select is a ContextSelect object.
book = Book()
# response is the Context object returned by model.query().
response = select(book.title, book.author, book.year)
# Query results are assigned to the response.results attribute.
print(response.results)
# title author year
# 0 It Stephen King 1986
# 1 On Writing Stephen King 2000
# 2 The Dark Tower Stephen King 1982
# Rows for each book filtered by the query are returned in the results. This
# means duplicate rows may be returned:
with model.query() as select:
book = Book()
response = select(book.author)
# There are two rows for Stephen King in the results because there are three
# books authored by him.
print(response.results)
# author
# 0 Stephen King
# 1 Stephen King
# 2 Stephen King
# Use select.distinct() to return only unique rows in the results:
with model.query() as select:
book = Book()
response = select.distinct(book.author)
print(response.results)
# author
# 0 Stephen King

You may call a ContextSelect object multiple times, but it must have the same number of arguments each time it is called:

with model.query() as select:
select("B", 1)
# The return value only needs to be assigned on the last call.
response = select("A", 2)
print(response.results)
# v v2
# 0 A 2
# 1 B 1

Each call adds rows to the query results. Calling a ContextSelect object multiple times lets you select data from different logical branches of a query:

with model.query() as select:
book = Book()
with NonFiction(book):
response = select(book.title, "NonFiction")
with Fiction(book):
select(book.title, "Fiction")
with Horror(book):
select(book.title, "Horror")
with Fantasy(book):
response = select(book.title, "Fantasy")
print(response.results)
# title v
# 0 It Fiction
# 1 It Horror
# 2 On Writing NonFiction
# 3 The Dark Tower Fantasy
# 4 The Dark Tower Fiction
ContextSelect.__getattr__(name: str) -> Instance | InstanceProperty

Gets properties of values assigned to a ContextSelect object. May only be called from ContextSelect objects created in a Model.match() block.

NameTypeDescription
namestrThe name of the property to get.

An Instance or an InstanceProperty.

.__getattr__() is called when you access an attribute of a ContextSelect object using the dot (.) operator. It returns properties of values assigned to the ContextSelect object:

import relationalai as rai
from relationalai.std import alias
# =====
# SETUP
# =====
model = rai.Model("MyModel")
Item = model.Type("Item")
with model.rule():
Item.add(id=1).set(name="A", price=10.00)
Item.add(id=2).set(name="B", price=10.00)
Item.add(id=3).set(name="C", price=20.00)
# =======
# EXAMPLE
# =======
# Compute an item's discount based on its price.
with model.query() as select:
item = Item()
with model.match() as discount: # discount is a ContextSelect object
# Items with a price greater than 15 get a 25% discount.
with item.price > 15:
discount.add(0.25, reason="Over $15")
# All other items get a 10% discount.
with model.case():
discount.add(0.1, reason="$15 or less")
# Compute the discounted price.
discounted_price = item.price * (1 - discount)
response = select(
item.id,
item.name,
item.price,
alias(discount, "discount"),
alias(discounted_price, "discounted_price"),
# discount.reason accesses the reason property set in discount.add().
alias(discount.reason, "reason"),
)
print(response.results)
# id name price discount discounted_price reason
# 0 1 A 10.0 0.10 9.0 $15 or less
# 1 2 B 10.0 0.10 9.0 $15 or less
# 2 3 C 20.0 0.25 15.0 Over $15

If the value assigned to the ContextSelect is a Producer, such as an Instance or an InstanceProperty, then .__getattr__() may also return properties of the Producer set elsewhere in the model:

# Declare a Discount type and define some Discount objects.
Discount = model.Type("Discount")
with model.rule():
Discount.add(rate=0.25).set(code="25OFF")
Discount.add(rate=0.10).set(code="10OFF")
# Compute an item's discount based on its price.
with model.query() as select:
item = Item()
with model.match() as discount:
# Items with a price greater than 15 get a 25% discount.
with item.price > 15:
discount.add(Discount(rate=0.25))
# All other items get a 10% discount.
with model.case():
discount.add(Discount(rate=0.10))
# Compute the discounted price. Properties of the Discount object can be
# accessed directly from the discount variable.
discounted_price = item.price * (1 - discount.rate)
response = select(
item.name,
item.price,
alias(discount.code, "discount_code"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# name price discount_code discounted_price
# 0 A 10.0 10OFF 9.0
# 1 B 10.0 10OFF 9.0
# 2 C 20.0 25OFF 15.0

Properties set in ContextSelect.add() take precedence over properties set elsewhere with the same name:

with model.query() as select:
item = Item()
with model.match() as discount:
with item.price > 15:
# The code property set here takes precedence over the code property
# set on the Discount object.
discount.add(Discount(rate=0.25), code="SUMMER25")
with model.case():
discount.add(Discount(rate=0.10), code="SUMMER10")
discounted_price = item.price * (1 - discount.rate)
response = select(
item.name,
item.price,
alias(discount.code, "discount_code"),
alias(discounted_price, "discounted_price"),
)
print(response.results)
# name price discount_code discounted_price
# 0 A 10.0 SUMMER10 9.0
# 1 B 10.0 SUMMER10 9.0
# 2 C 20.0 SUMMER25 15.0

See Model.match() for more information on .match() contexts.