LogoZonai

Side Effects: get

Reading rows from any table inside an extension or cron job.

get is a side-effect API for reading rows from any table inside an extension hook or cron job. Reads use the same JWT from the original request.

get.one#

Fetches a single row matching a condition. Returns null if no row matches:

@override
Future<void> afterCreateSuccess(Comment comment, Jwt? jwt) async {
  final post = await get.one(
    tableName: 'posts',
    where: Eq('id', comment.postId.value),
  );

  if (post != null) {
    logger.info('Comment added to post: ${post['title']}');
  }
}

get.many#

Fetches multiple rows. Returns an empty list if none match:

@override
Future<void> beforeDelete(User user, Jwt? jwt) async {
  final orders = await get.many(
    tableName: 'orders',
    where: Eq('user_id', user.id.value),
    limit: 1,
  ) ?? [];

  if (orders.isNotEmpty) {
    throw Exception('Cannot delete user with orders');
  }
}

Optional limit and offset parameters support pagination.

Return Type#

get.one returns Future<Map<String, Object?>?> and get.many returns Future<List<Map<String, Object?>>?>. The results are untyped maps — access fields with ['fieldName'] notation, not dot-property access:

final row = await get.one(tableName: 'users', where: Eq('id', userId));
final email = row?['email'] as String?;

The Where Clause#

Eq('column', value) is the simplest condition. More complex queries can be composed using And, Or, Gt, Lt, and other Where constructors.

Rules Apply#

get calls enforce the same table and row rules as the main request, using the same JWT. On the default path those rules run in-process; with ZONAI_FORCE_WORKERS=1 they go through the rules worker. If the requesting user cannot view a table, a get call for that table inside an extension will be denied.

Common Uses#

  • Fetch the user row to personalize an email after a sign-up
  • Check for related rows before allowing a deletion
  • Load additional context before sending a notification
  • Fetch rows that need processing in a cron job