parseSqliteSelector function

SqliteSelector parseSqliteSelector(
  1. String subPath,
  2. String queryString
)

Parses the table/query selector tail of a SQLite path (omp's parseSqliteSelector). Throws StateError with omp's messages on unsupported combinations.

Implementation

SqliteSelector parseSqliteSelector(String subPath, String queryString) {
  final normalizedSubPath = subPath.replaceFirst(RegExp('^:+'), '').trim();
  final params = Uri.splitQueryString(queryString);
  final rawQuery = params['q'];

  if (rawQuery != null) {
    final otherKeys = params.keys.where((key) => key != 'q');
    if (normalizedSubPath.isNotEmpty || otherKeys.isNotEmpty) {
      throw StateError(
        'SQLite raw queries cannot be combined with table selectors or '
        'pagination',
      );
    }
    if (rawQuery.trim().isEmpty) {
      throw StateError("SQLite query parameter 'q' cannot be empty");
    }
    return SqliteRawSelector(rawQuery);
  }

  if (normalizedSubPath.isEmpty) {
    if (params.isNotEmpty) {
      throw StateError(
        'SQLite query parameters require a table selector or q=SELECT...',
      );
    }
    return const SqliteListSelector();
  }

  final separatorIndex = normalizedSubPath.indexOf(':');
  final table = separatorIndex == -1
      ? normalizedSubPath
      : normalizedSubPath.substring(0, separatorIndex);
  final key = separatorIndex == -1
      ? null
      : normalizedSubPath.substring(separatorIndex + 1);
  if (table.isEmpty) {
    throw StateError('SQLite selectors must include a table name');
  }

  if (key != null && key.isNotEmpty) {
    if (params.isNotEmpty) {
      throw StateError(
        'SQLite row lookups cannot be combined with query parameters',
      );
    }
    return SqliteRowSelector(table, key);
  }

  final where = _validateWhereClause(params['where']);
  final orderParam = params['order']?.trim();
  final order = orderParam == null || orderParam.isEmpty ? null : orderParam;
  final hasQueryParams =
      params.containsKey('limit') ||
      params.containsKey('offset') ||
      order != null ||
      where != null;
  if (hasQueryParams) {
    const knownKeys = {'limit', 'offset', 'order', 'where'};
    for (final keyName in params.keys) {
      if (!knownKeys.contains(keyName)) {
        throw StateError("Unsupported SQLite query parameter '$keyName'");
      }
    }
    return SqliteQuerySelector(
      table: table,
      limit: _parseLimit(params['limit'], defaultSqliteQueryLimit),
      offset: _parseOffset(params['offset']),
      order: order,
      where: where,
    );
  }

  if (params.isNotEmpty) {
    throw StateError(
      "Unsupported SQLite query parameter '${params.keys.first}'",
    );
  }

  return SqliteSchemaSelector(table);
}