toMap method

  1. @override
Future<List<Map<String?, dynamic>>> toMap()
override

toMap returns a map

Implementation

@override
Future<List<Map<String?, dynamic>>> toMap() async {
  if (_offset != null && _limit == null) {
    return throw UnsupportedError(
      'You need to pass LIMIT when using OFFSET\n'
      'Use: dao.limit(x).offset(x) instead of dao.offset(x)',
    );
  }

  if (_having.isNotEmpty && _group.isEmpty) {
    return throw UnsupportedError(
      'You need to pass GROUP BY when using HAVING\n'
      'Use: dao.having(x).group(x) instead of dao.having(x)',
    );
  }

  if (_or.isNotEmpty && _where.isEmpty) {
    return throw UnsupportedError(
      'You need to pass WHERE when using OR\n'
      'Use: dao.where(x).or(x) instead of dao.or(x)',
    );
  }

  final builder = _copyQueryWith();

  final completer = Completer<List<Map<String, dynamic>>>()
    ..complete(database!.rawQuery(builder.sql, builder.arguments));

  if (isLogger!) Logger.query(type, completer.future, builder);

  /// use mapping to convert `QueryRow` into `Map` so we can edit that list
  final items = await completer.future.then(
    (values) => values.map((value) {
      var item = Map<String?, dynamic>.from(value);

      /// Search for any join to convert join to nested attributes
      for (final relation in relations) {
        final join = _joins.find((join) => join.type == relation.dao!.type);
        final include =
            _includes.find((include) => include!.type == relation.dao!.type);

        if (join != null) item.nest('${join.type}'.toCamelCase());

        /// nest item if no include
        if (include == null) {
          final foreignKey = schema.foreignKeys.find(
            (fk) => fk.reference!.table == relation.dao!.schema.table,
          );

          if (foreignKey != null) {
            item.nest('${relation.dao!.type}'.toCamelCase());
          }
        }
      }

      return item;
    }).toList(),
  );

  /// include associations
  for (final include in _includes) {
    final Relation<DataAccessObject<dynamic>>? relation = relations.find(
        (relation) => relation.dao!.schema.table == include!.schema.table);

    if (kDebugMode) {
      print(relation);
    }

    if (relation is BelongsTo) {
      final foreignKey = schema.foreignKeys.find(
        (fk) => fk.reference!.table == include!.schema.table,
      );

      /// collect ids to avoid duplication
      final foreignKeys =
          items.map((item) => item[foreignKey!.parent]).toSet().toList();

      // if not empty
      if (foreignKeys.isNotEmpty) {
        /// if length is only one record then use a simple where statment
        if (foreignKeys.length == 1) {
          include!.where({include.schema.primaryKey: foreignKeys.first});
        }

        /// else use where in
        else {
          include!.where({
            '${include.schema.primaryKey} IN (${List.filled(foreignKeys.length, '?').join(',')})':
                foreignKeys
          }).limit(foreignKeys.length);
        }

        final associations = await include.toMap();

        /// add all associations to object for
        for (final item in items) {
          final Map<String?, dynamic>? association = associations.find(
            (association) {
              final primaryKey = association[include.schema.primaryKey];

              /// search for `primaryKey` that matches item `foreignKey`
              return primaryKey == item[foreignKey!.parent];
            },
          );

          item['${include.type}'.toCamelCase()] = association;
        }
      }
    } else {
      final foreignKey = relation!.dao!.schema.foreignKeys.find(
        (fk) => fk.reference!.table == schema.table,
      );

      /// collect ids to avoid duplication
      final primaryKeys =
          items.map((item) => item[schema.primaryKey]).toSet().toList();

      // if not empty
      if (primaryKeys.isNotEmpty) {
        /// if length is only one record then use a simple where statment
        if (primaryKeys.length == 1) {
          include!.where({foreignKey!.parent: primaryKeys.first});
        } else {
          include!.where({
            '${foreignKey!.parent} IN (${List.filled(primaryKeys.length, '?').join(',')})':
                primaryKeys
          }).limit(primaryKeys.length);
        }

        final associations = await include.toMap();

        for (final item in items) {
          /// assign association to parent
          if (relation is HasOne) {
            item['${include.type}'.toCamelCase()] = associations.find(
              (association) {
                /// search for `primaryKey` that matches item `foreignKey`
                return association[include.schema.primaryKey] ==
                    item[include.schema.primaryKey];
              },
            );
          }

          // just removed  || relation is ProxyHasMany
          else if (relation is HasMany) {
            item[include.schema.table] = associations;
          }

          if (kDebugMode) {
            print('item: $item');
          }
        }
      }
    }
    break;
  }

  clear();

  return items;
}