Chalk home page
Docs
API
CLI
  1. Features
  2. Has One

In a one-to-one relationship, two feature sets have at most one feature set on both sides of the relation.

Specified below is the simplest way to demonstrate a join for a has-one relationship. Here, users have an associated profile:

from chalk.features import features

@features
class Profile:
    ...
    user_id: str
    email_age_years: float

@features
class User:
    ...
    uid: Profile.user_id
    profile: Profile

This specifies that User.uid is of type str and User.profile is a has-one feature through the join User.uid == Profile.user_id.

Explicit Join

The following snippet, in which the join is explicitly defined, is equivalent to the recommended implementation.

from chalk.features import features, has_one, ...

@features
class Profile:
    ...
    user_id: str
    email_age_years: float

@features
class User:
    ...
    uid: str
    profile: Profile = has_one(lambda: Profile.user_id == User.uid)

The `lambda` solves forward references, letting you reference `User` before it is defined.

You can also reference the join from the foreign feature class, if you prefer. The following is equivalent to the two examples above.

from chalk.features import features

@features
class Profile:
    ...
    user_id: "User.uid"
    email_age_years: float

@features
class User:
    ...
    uid: str
    profile: Profile

Now, you can reference features on Profile through User. For example:

user_email_age = User.profile.email_age_years

Back-references

One-to-one

You can also add the back-reference to User from Profile. You don’t have to explicitly set the join on Profile, however. Instead, the join condition is assumed to be symmetric and copied over. Building on the above example, all you need to do to complete the one-to-one relationship is to add a User to the Profile class:

@features
class Profile:
  ...
  user_id: "User.uid"
  email_age_years: float
  user: "User"

@features
class User:
  ...
  uid: str
  profile: Profile

Here you need to use quotes around `User` to use a forward reference.

Optional relationships

You can define optional relationships simply by using the typing.Optional[...] keyword:

from typing import Optional

@features
class User:
  ...
  uid: Profile.user_id
  profile: Profile
  profile: Optional[Profile]