Database / ORM Overview

Relationships

Database tables are frequently related to one another. For example, a User may have many Posts, or a Post may belong to a specific Category.

Archery makes managing these relationships incredibly intuitive by leveraging standard naming conventions for foreign keys. Depending on your active database driver, Archery will automatically assume the foreign key is either <model_name>_id or <model_name>_uuid.

Retrieving Relations

You can easily query relational siblings directly off an active model instance using the provided async relationship builders:

One to One

A one-to-one relationship is the most basic form of database association. For example, a User model might be associated with a single Phone model.

final phone = await user.hasOne<Phone>();

Similarly, the inverse relationship works flawlessly. The Phone can quickly find its owning User:

final owner = await phone.belongsToOne<User>();

One to Many

A one-to-many relationship defines a single model owning any amount of other models. A blog Post may have an infinite number of Comment models.

final comments = await post.hasMany<Comment>();

Mutating Relations

Instead of manually querying and updating foreign keys, you can leverage Archery's elegant relationship mutators to quickly link and unlink disparate records.

Use the attach and detach functions to assign records to one another dynamically:

final user = await Model.find<User>(id: 1);
final profile = Profile(bio: "I love archery!");
await profile.save();

// Automatically sets user_id = user.id on the profile record
await user.attach(profile, relationship: ModelRelationshipType.hasOne);

// Removes the relation
await user.detach(profile, relationship: ModelRelationshipType.hasOne);

Eager Loading Relationships

If you are returning a model's JSON directly into an HTTP Response (as an API usually does), you probably want to embed relationship data into the JSON map.

You can rapidly generate saturated models using the load method. This method executes the database lookup, serializes both the parent and children models, and merges them into a single comprehensive dictionary that's ready to fly across the wire:

router.get('/user/:id', (request) async {
  final user = await Model.findOrFail<User>(
    request: request, 
    id: request.params.get('id')
  );

  // Return User JSON with nested 'comments' array
  final payload = await user.load<Comment>(ModelRelationshipType.hasMany);
  return request.json(payload);
});