import 'package:dio/dio.dart'; import 'errors/marianumconnect_error.dart'; import 'marianumconnect_api.dart'; import 'marianumconnect_endpoint.dart'; /// Shared base for MarianumConnect API queries. Owns the [dio] client (the /// shared authenticated singleton by default) and routes calls through [guard] /// so every query maps a DioException to the app's typed AppExceptions the same /// way instead of repeating the try/catch. Subclasses with bespoke error or /// lifecycle handling (own dio, silent failure, custom status mapping) may skip /// [guard] and still reuse [dio]/[endpoint]. abstract class MarianumConnectQuery { final Dio dio; MarianumConnectQuery({Dio? dio}) : dio = dio ?? MarianumConnectApi.dio(); /// Resolves [path] against the active mobile-API base URL. String endpoint(String path) => MarianumConnectEndpoint.resolve(path); /// Runs [body], converting any DioException into the matching AppException. Future guard(Future Function() body) async { try { return await body(); } on DioException catch (e) { throw mapMarianumConnectError(e); } } /// GETs [path] and parses the JSON object body with [fromJson]. Future getObject( String path, T Function(Map json) fromJson, { Map? queryParameters, }) => guard(() async { final response = await dio.get>( endpoint(path), queryParameters: queryParameters, ); return fromJson(response.data!); }); /// GETs [path] and maps each element of the JSON array body with [fromJson]. Future> getList( String path, T Function(Map json) fromJson, { Map? queryParameters, }) => guard(() async { final response = await dio.get>( endpoint(path), queryParameters: queryParameters, ); return response.data! .map((e) => fromJson(e as Map)) .toList(); }); /// Formats [d] as an ISO `yyyy-MM-dd` day for MarianumConnect query params. String isoDate(DateTime d) => '${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}'; }