loadEvents method

  1. @override
Future<List<Nip01Event>> loadEvents({
  1. List<String>? ids,
  2. List<String>? pubKeys,
  3. List<int>? kinds,
  4. Map<String, List<String>>? tags,
  5. int? since,
  6. int? until,
  7. String? search,
  8. int? limit,
})
override

Load visible events from cache with flexible filtering.

Parameters:

  • ids: event ids
  • pubKeys: author pubkeys
  • kinds: event kinds
  • tags: tag filters, e.g. {'p': ['pubkey1'], 'e': ['eventid1']}
  • since/until: created_at bounds
  • search: content search string
  • limit: maximum number of returned events

Visibility rules apply here:

  • only the latest visible replaceable/addressable winner is returned
  • expired events are filtered out
  • author-deleted events are filtered out

Implementation

@override
Future<List<Nip01Event>> loadEvents({
  List<String>? ids,
  List<String>? pubKeys,
  List<int>? kinds,
  Map<String, List<String>>? tags,
  int? since,
  int? until,
  String? search,
  int? limit,
}) async {
  await dbRdy;
  final eventBox = _objectBox.store.box<DbNip01Event>();

  // Build conditions
  Condition<DbNip01Event>? condition;

  // Add search condition if provided (NIP-50)
  if (search != null && search.isNotEmpty) {
    condition = DbNip01Event_.content.contains(search, caseSensitive: false);
  }

  // Add ids filter
  if (ids != null && ids.isNotEmpty) {
    Condition<DbNip01Event> idsCondition = DbNip01Event_.nostrId.oneOf(ids);
    condition =
        (condition == null) ? idsCondition : condition.and(idsCondition);
  }

  // Add pubKeys filter
  if (pubKeys != null && pubKeys.isNotEmpty) {
    Condition<DbNip01Event> pubKeysCondition = DbNip01Event_.pubKey.oneOf(
      pubKeys,
    );
    condition = (condition == null)
        ? pubKeysCondition
        : condition.and(pubKeysCondition);
  }

  // Add kinds filter
  if (kinds != null && kinds.isNotEmpty) {
    Condition<DbNip01Event> kindsCondition = DbNip01Event_.kind.oneOf(kinds);
    condition =
        (condition == null) ? kindsCondition : condition.and(kindsCondition);
  }

  // Add since filter
  if (since != null) {
    Condition<DbNip01Event> sinceCondition =
        DbNip01Event_.createdAt.greaterOrEqual(since);
    condition =
        (condition == null) ? sinceCondition : condition.and(sinceCondition);
  }

  // Add until filter
  if (until != null) {
    Condition<DbNip01Event> untilCondition =
        DbNip01Event_.createdAt.lessOrEqual(until);
    condition =
        (condition == null) ? untilCondition : condition.and(untilCondition);
  }

  if (tags != null && tags.isNotEmpty) {
    final matchingEventIds = _findEventIdsByTags(eventBox, tags);
    if (matchingEventIds.isEmpty) {
      return [];
    }

    final tagCondition = DbNip01Event_.dbId.oneOf(matchingEventIds.toList());
    condition =
        (condition == null) ? tagCondition : condition.and(tagCondition);
  }

  // Create and build the query
  QueryBuilder<DbNip01Event> queryBuilder;
  if (condition != null) {
    queryBuilder = eventBox.query(condition);
  } else {
    queryBuilder = eventBox.query();
  }

  // Apply sorting
  queryBuilder.order(DbNip01Event_.createdAt, flags: Order.descending);

  // Build and execute the query
  final query = queryBuilder.build();
  final results = query.find();

  final deletions = eventBox
      .query(DbNip01Event_.kind.equals(5))
      .build()
      .find()
      .map((dbEvent) => dbEvent.toNdk())
      .toList();

  var events = _applyEventVisibilityRules(
    results.map((dbEvent) => dbEvent.toNdk()).toList(),
    deletions,
  )..sort((a, b) => b.createdAt.compareTo(a.createdAt));

  if (limit != null && limit > 0 && events.length > limit) {
    events = events.take(limit).toList();
  }

  return events;
}