Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

feat: favorites api #31

Merged
merged 22 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@
"--target",
"lib/main_production.dart"
]
},
{
"name": "API: attach to process",
"type": "dart",
"request": "attach",
"vmServiceUri": "${command:dart.promptForVmService}",
"program": "${workspaceFolder}/api/main.dart"
}
]
}
13 changes: 13 additions & 0 deletions api/amplify/data/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const schema = a.schema({
endTime: a.datetime(),
isFavorite: a.boolean(),
speakers: a.hasMany('SpeakerTalk', 'talkId'),
favorites: a.hasMany('FavoritesTalk', 'talkId'),
}),
Speaker: a
.model({
Expand All @@ -34,6 +35,18 @@ const schema = a.schema({
speakerId: a.id(),
speaker: a.belongsTo('Speaker', 'speakerId'),
}),
FavoritesTalk: a
.model({
favoritesId: a.id().required(),
talkId: a.id().required(),
favorites: a.belongsTo('Favorites', 'favoritesId'),
talk: a.belongsTo('Talk', 'talkId'),
}),
Favorites: a
.model({
userId: a.string(),
talks: a.hasMany('FavoritesTalk', 'favoritesId'),
}),
}).authorization((allow) => [allow.guest()]);

export type Schema = ClientSchema<typeof schema>;
Expand Down
3 changes: 3 additions & 0 deletions api/devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
10 changes: 10 additions & 0 deletions api/lib/helpers/request_body_decoder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'dart:convert';

import 'package:dart_frog/dart_frog.dart';

/// Helper to decode dart frog request bodies
extension RequestBodyDecoder on Request {
/// Returns the request body as a `Map<String, dynamic>`
Future<Map<String, dynamic>> decodeRequestBody() async =>
Map<String, dynamic>.from(jsonDecode(await body()) as Map);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ class AmplifyAPIClient {
final APICategory _api;
final GraphQLRequestWrapper _requestWrapper;

/// Create a GraphQL [get] request.
GraphQLRequest<T> get<T extends Model>(
ModelType<T> modelType,
ModelIdentifier<T> modelIdentifier, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) {
return _requestWrapper.get<T>(
modelType,
modelIdentifier,
apiName: apiName,
authorizationMode: authorizationMode,
headers: headers,
);
}

/// Create a GraphQL [list] request.
GraphQLRequest<PaginatedResult<T>> list<T extends Model>(
ModelType<T> modelType, {
Expand All @@ -34,7 +51,43 @@ class AmplifyAPIClient {
);
}

/// Create a GraphQL [create] request.
GraphQLRequest<T> create<T extends Model>(
T model, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) {
return _requestWrapper.create<T>(
model,
apiName: apiName,
authorizationMode: authorizationMode,
headers: headers,
);
}

/// Create a GraphQL [deleteById] request.
GraphQLRequest<T> deleteById<T extends Model>(
ModelType<T> modelType,
ModelIdentifier<T> modelIdentifier, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) {
return _requestWrapper.deleteById<T>(
modelType,
modelIdentifier,
apiName: apiName,
authorizationMode: authorizationMode,
headers: headers,
);
}

/// Send a GraphQL [query] with a given [request].
GraphQLOperation<T> query<T>({required GraphQLRequest<T> request}) =>
_api.query(request: request);

/// Send a GraphQL [mutate] with a given [request].
GraphQLOperation<T> mutate<T>({required GraphQLRequest<T> request}) =>
_api.mutate(request: request);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:amplify_api_dart/amplify_api_dart.dart';
import 'package:amplify_core/amplify_core.dart';
import 'package:fluttercon_data_source/src/data_source/amplify_api_client.dart';
import 'package:fluttercon_data_source/src/exceptions/exceptions.dart';

Expand All @@ -19,6 +19,92 @@ class FlutterconDataSource {

final AmplifyAPIClient _apiClient;

/// Creates a new [Favorites] entity.
Future<Favorites> createFavorites({required String userId}) async {
try {
final request = _apiClient.create(Favorites(userId: userId));
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.mutate(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Creates a new [FavoritesTalk] entity.
Future<FavoritesTalk> createFavoritesTalk({
required String favoritesId,
required String talkId,
}) async {
try {
final request = _apiClient.create(
FavoritesTalk(
favorites: Favorites(id: favoritesId),
talk: Talk(id: talkId),
),
);
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.mutate(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Deletes a [FavoritesTalk] entity.
Future<FavoritesTalk> deleteFavoritesTalk({required String id}) async {
try {
final request = _apiClient.deleteById(
FavoritesTalk.classType,
FavoritesTalkModelIdentifier(id: id),
);
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.mutate(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Gets a [Favorites] entity by [id].
Future<FavoritesTalk> getFavoritesTalk({required String id}) async {
try {
final request = _apiClient.get(
FavoritesTalk.classType,
FavoritesTalkModelIdentifier(
id: id,
),
);
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.query(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Fetches a paginated list of [Favorites] entities.
/// Can optionally provide a [userId] to filter.
Future<PaginatedResult<Favorites>> getFavorites({String? userId}) async {
try {
final request = _apiClient.list(
Favorites.classType,
where: userId != null ? Favorites.USERID.eq(userId) : null,
);

return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.query(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Fetches a paginated list of speakers.
Future<PaginatedResult<Speaker>> getSpeakers() async {
try {
Expand All @@ -33,11 +119,49 @@ class FlutterconDataSource {
}

/// Fetches a paginated list of talks.
Future<PaginatedResult<Talk>> getTalks({bool favorites = false}) async {
Future<PaginatedResult<Talk>> getTalks() async {
try {
final request = _apiClient.list(
Talk.classType,
where: favorites ? Talk.ISFAVORITE.eq(true) : null,
);
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.query(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Fetches a [Talk] entity by [id].
Future<Talk> getTalk({required String id}) async {
try {
final request =
_apiClient.get(Talk.classType, TalkModelIdentifier(id: id));
return await _sendGraphQLRequest(
request: request,
operation: (request) => _apiClient.query(request: request),
);
} on Exception catch (e) {
throw AmplifyApiException(exception: e);
}
}

/// Fetches a paginated list of [FavoritesTalk] entities
/// for a [favoritesId].
/// A [FavoritesTalk] contains an ID for a favorites entity and
/// an ID for a corresponding talk.
Future<PaginatedResult<FavoritesTalk>> getFavoritesTalks({
required String favoritesId,
String? talkId,
}) async {
try {
final request = _apiClient.list(
FavoritesTalk.classType,
where: QueryPredicateGroup(QueryPredicateGroupType.and, [
FavoritesTalk.FAVORITES.eq(favoritesId),
if (talkId != null) FavoritesTalk.TALK.eq(talkId),
]),
);
return await _sendGraphQLRequest(
request: request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,30 @@ class GraphQLRequestWrapper {
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) list = ModelQueries.list;

/// Wrapper around the static [ModelQueries.get] helper.
GraphQLRequest<T> Function<T extends Model>(
ModelType<T> modelType,
ModelIdentifier<T> modelIdentifier, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) get = ModelQueries.get;

/// Wrapper around the static [ModelMutations.create] helper.
GraphQLRequest<T> Function<T extends Model>(
T model, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) create = ModelMutations.create;

/// Wrapper around the static [ModelMutations.deleteById] helper.
GraphQLRequest<T> Function<T extends Model>(
ModelType<T> modelType,
ModelIdentifier<T> modelIdentifier, {
String? apiName,
APIAuthorizationType? authorizationMode,
Map<String, String>? headers,
}) deleteById = ModelMutations.deleteById;
}
Loading
Loading