mirror of
https://github.com/johrpan/musicus_mobile.git
synced 2025-10-26 02:37:25 +01:00
database, server: Simpler and more efficient API
This commit is contained in:
parent
d2a8363f6f
commit
ad022a6640
11 changed files with 271 additions and 68 deletions
|
|
@ -59,40 +59,38 @@ class MusicusClient {
|
|||
}
|
||||
|
||||
/// Get all works composed by the person with the ID [personId].
|
||||
Future<List<Work>> getWorks(int personId) async {
|
||||
Future<List<WorkInfo>> getWorks(int personId) async {
|
||||
final response = await _client.get('$host/persons/$personId/works');
|
||||
final json = jsonDecode(response.body);
|
||||
return json.map<Work>((j) => Work.fromJson(j)).toList();
|
||||
return json.map<WorkInfo>((j) => WorkInfo.fromJson(j)).toList();
|
||||
}
|
||||
|
||||
/// Get a work by ID.
|
||||
Future<Work> getWork(int id) async {
|
||||
Future<WorkInfo> getWork(int id) async {
|
||||
final response = await _client.get('$host/works/$id');
|
||||
final json = jsonDecode(response.body);
|
||||
return Work.fromJson(json);
|
||||
}
|
||||
|
||||
/// Get all work parts of the work with the ID [workId].
|
||||
Future<List<Work>> getParts(int workId) async {
|
||||
final response = await _client.get('$host/works/$workId/parts');
|
||||
final json = jsonDecode(response.body);
|
||||
return json.map<Work>((j) => Work.fromJson(j)).toList();
|
||||
return WorkInfo.fromJson(json);
|
||||
}
|
||||
|
||||
/// Get all recordings of the work with the ID [workId].
|
||||
Future<List<Recording>> getRecordings(int workId) async {
|
||||
Future<List<RecordingInfo>> getRecordings(int workId) async {
|
||||
final response = await _client.get('$host/works/$workId/recordings');
|
||||
final json = jsonDecode(response.body);
|
||||
return json.map<Recording>((j) => Recording.fromJson(j)).toList();
|
||||
return json.map<RecordingInfo>((j) => RecordingInfo.fromJson(j)).toList();
|
||||
}
|
||||
|
||||
/// Create or update a work.
|
||||
Future<void> putWork(WorkData data) async {
|
||||
await _client.put(
|
||||
///
|
||||
/// The new or updated work is returned.
|
||||
Future<WorkInfo> putWork(WorkData data) async {
|
||||
final response = await _client.put(
|
||||
'$host/works/${data.data.work.id}',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(data.toJson()),
|
||||
);
|
||||
|
||||
final json = jsonDecode(response.body);
|
||||
return WorkInfo.fromJson(json);
|
||||
}
|
||||
|
||||
/// Get a list of all ensembles.
|
||||
|
|
@ -119,27 +117,24 @@ class MusicusClient {
|
|||
}
|
||||
|
||||
/// Get a recording by ID.
|
||||
Future<Recording> getRecording(int id) async {
|
||||
Future<RecordingInfo> getRecording(int id) async {
|
||||
final response = await _client.get('$host/recordings/$id');
|
||||
final json = jsonDecode(response.body);
|
||||
return Recording.fromJson(json);
|
||||
}
|
||||
|
||||
/// Get all performances within the recording with the ID [recordingId].
|
||||
Future<List<Performance>> getPerformances(int recordingId) async {
|
||||
final response =
|
||||
await _client.get('$host/recordings/$recordingId/performances');
|
||||
final json = jsonDecode(response.body);
|
||||
return json.map<Performance>((j) => Performance.fromJson(j)).toList();
|
||||
return RecordingInfo.fromJson(json);
|
||||
}
|
||||
|
||||
/// Create or update a recording.
|
||||
Future<void> putRecording(RecordingData data) async {
|
||||
await _client.put(
|
||||
///
|
||||
/// The new or updated recording is returned.
|
||||
Future<RecordingInfo> putRecording(RecordingData data) async {
|
||||
final response = await _client.put(
|
||||
'$host/recordings/${data.recording.id}',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(data.toJson()),
|
||||
);
|
||||
|
||||
final json = jsonDecode(response.body);
|
||||
return RecordingInfo.fromJson(json);
|
||||
}
|
||||
|
||||
/// Close the internal http client.
|
||||
|
|
|
|||
|
|
@ -1 +1,2 @@
|
|||
export 'src/database.dart';
|
||||
export 'src/database.dart';
|
||||
export 'src/info.dart';
|
||||
|
|
@ -2,6 +2,8 @@ import 'dart:math';
|
|||
|
||||
import 'package:moor/moor.dart';
|
||||
|
||||
import 'info.dart';
|
||||
|
||||
part 'database.g.dart';
|
||||
|
||||
final _random = Random(DateTime.now().millisecondsSinceEpoch);
|
||||
|
|
@ -99,6 +101,50 @@ class Database extends _$Database {
|
|||
await into(instruments).insert(instrument, orReplace: true);
|
||||
}
|
||||
|
||||
/// Retrieve more information on an already queried work.
|
||||
Future<WorkInfo> getWorkInfo(Work work) async {
|
||||
final id = work.id;
|
||||
|
||||
final composers = await composersByWork(id).get();
|
||||
final instruments = await instrumentsByWork(id).get();
|
||||
|
||||
final List<PartInfo> parts = [];
|
||||
for (final part in await workParts(id).get()) {
|
||||
parts.add(PartInfo(
|
||||
work: part,
|
||||
composer: part.composer != null
|
||||
? await personById(part.composer).getSingle()
|
||||
: null,
|
||||
instruments: await instrumentsByWork(id).get(),
|
||||
));
|
||||
}
|
||||
|
||||
return WorkInfo(
|
||||
work: work,
|
||||
instruments: instruments,
|
||||
composers: composers,
|
||||
parts: parts,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get all available information on a work.
|
||||
Future<WorkInfo> getWork(int id) async {
|
||||
final work = await workById(id).getSingle();
|
||||
return await getWorkInfo(work);
|
||||
}
|
||||
|
||||
/// Get information on all works written by the person with ID [personId].
|
||||
Future<List<WorkInfo>> getWorks(int personId) async {
|
||||
final works = await worksByComposer(personId).get();
|
||||
|
||||
final List<WorkInfo> result = [];
|
||||
for (final work in works) {
|
||||
result.add(await getWorkInfo(work));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Future<void> updateWork(WorkData data) async {
|
||||
await transaction(() async {
|
||||
final workId = data.data.work.id;
|
||||
|
|
@ -137,4 +183,47 @@ class Database extends _$Database {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Retreive more information on an already queried recording.
|
||||
Future<RecordingInfo> getRecordingInfo(Recording recording) async {
|
||||
final id = recording.id;
|
||||
|
||||
final List<PerformanceInfo> performances = [];
|
||||
for (final performance in await performancesByRecording(id).get()) {
|
||||
performances.add(PerformanceInfo(
|
||||
person: performance.person != null
|
||||
? await personById(performance.person).getSingle()
|
||||
: null,
|
||||
ensemble: performance.ensemble != null
|
||||
? await ensembleById(performance.ensemble).getSingle()
|
||||
: null,
|
||||
role: performance.role != null
|
||||
? await instrumentById(performance.role).getSingle()
|
||||
: null,
|
||||
));
|
||||
}
|
||||
|
||||
return RecordingInfo(
|
||||
recording: recording,
|
||||
performances: performances,
|
||||
);
|
||||
}
|
||||
|
||||
/// Get all available information on a recording.
|
||||
Future<RecordingInfo> getRecording(int id) async {
|
||||
final recording = await recordingById(id).getSingle();
|
||||
return await getRecordingInfo(recording);
|
||||
}
|
||||
|
||||
/// Get information on all recordings of the work with ID [workId].
|
||||
Future<List<RecordingInfo>> getRecordings(int workId) async {
|
||||
final recordings = await recordingsByWork(workId).get();
|
||||
|
||||
final List<RecordingInfo> result = [];
|
||||
for (final recording in recordings) {
|
||||
result.add(await getRecordingInfo(recording));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
149
database/lib/src/info.dart
Normal file
149
database/lib/src/info.dart
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import 'database.dart';
|
||||
|
||||
/// A bundle of all available information on a work part.
|
||||
class PartInfo {
|
||||
/// The work part itself.
|
||||
final Work work;
|
||||
|
||||
/// A list of instruments.
|
||||
///
|
||||
/// This will include the instruments, that are specific to this part.
|
||||
final List<Instrument> instruments;
|
||||
|
||||
/// The composer of this part.
|
||||
///
|
||||
/// This is null, if this part doesn't have a specific composer.
|
||||
final Person composer;
|
||||
|
||||
PartInfo({
|
||||
this.work,
|
||||
this.instruments,
|
||||
this.composer,
|
||||
});
|
||||
|
||||
factory PartInfo.fromJson(Map<String, dynamic> json) => PartInfo(
|
||||
work: Work.fromJson(json['work']),
|
||||
instruments: json['instruments']
|
||||
.map<Instrument>((j) => Instrument.fromJson(j))
|
||||
.toList(),
|
||||
composer:
|
||||
json['composer'] != null ? Person.fromJson(json['composer']) : null,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'work': work.toJson(),
|
||||
'instruments': instruments.map((i) => i.toJson()).toList(),
|
||||
'composers': composer?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
/// A bundle information on a work.
|
||||
///
|
||||
/// This includes all available information except for recordings of this work.
|
||||
class WorkInfo {
|
||||
/// The work itself.
|
||||
final Work work;
|
||||
|
||||
/// A list of instruments.
|
||||
///
|
||||
/// This will not the include the instruments, that are specific to the work
|
||||
/// parts.
|
||||
final List<Instrument> instruments;
|
||||
|
||||
/// A list of persons, which will include all part composers.
|
||||
final List<Person> composers;
|
||||
|
||||
/// All available information on the work parts.
|
||||
final List<PartInfo> parts;
|
||||
|
||||
WorkInfo({
|
||||
this.work,
|
||||
this.instruments,
|
||||
this.composers,
|
||||
this.parts,
|
||||
});
|
||||
|
||||
factory WorkInfo.fromJson(Map<String, dynamic> json) => WorkInfo(
|
||||
work: Work.fromJson(json['work']),
|
||||
instruments: json['instruments']
|
||||
.map<Instrument>((j) => Instrument.fromJson(j))
|
||||
.toList(),
|
||||
composers:
|
||||
json['composers'].map<Person>((j) => Person.fromJson(j)).toList(),
|
||||
parts:
|
||||
json['parts'].map<WorkInfo>((j) => WorkInfo.fromJson(j)).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'work': work.toJson(),
|
||||
'instruments': instruments.map((i) => i.toJson()).toList(),
|
||||
'composers': composers.map((c) => c.toJson()).toList(),
|
||||
'parts': parts.map((c) => c.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
/// All available information on a performance within a recording.
|
||||
class PerformanceInfo {
|
||||
/// The performing person.
|
||||
///
|
||||
/// This will be null, if this is an ensemble.
|
||||
final Person person;
|
||||
|
||||
/// The performing ensemble.
|
||||
///
|
||||
/// This will be null, if this is a person.
|
||||
final Ensemble ensemble;
|
||||
|
||||
/// The instrument/role or null.
|
||||
final Instrument role;
|
||||
|
||||
PerformanceInfo({
|
||||
this.person,
|
||||
this.ensemble,
|
||||
this.role,
|
||||
});
|
||||
|
||||
factory PerformanceInfo.fromJson(Map<String, dynamic> json) =>
|
||||
PerformanceInfo(
|
||||
person: json['person'] != null ? Person.fromJson(json['person']) : null,
|
||||
ensemble: json['ensemble'] != null
|
||||
? Ensemble.fromJson(json['ensemble'])
|
||||
: null,
|
||||
role: json['role'] != null ? Instrument.fromJson(json['role']) : null,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'person': person?.toJson(),
|
||||
'ensemble': ensemble?.toJson(),
|
||||
'role': role?.toJson(),
|
||||
};
|
||||
}
|
||||
|
||||
/// All available information on a recording.
|
||||
///
|
||||
/// This doesn't include the recorded work, because probably it's already
|
||||
/// available.
|
||||
class RecordingInfo {
|
||||
/// The recording itself.
|
||||
final Recording recording;
|
||||
|
||||
/// Information on the performances within this recording.
|
||||
final List<PerformanceInfo> performances;
|
||||
|
||||
RecordingInfo({
|
||||
this.recording,
|
||||
this.performances,
|
||||
});
|
||||
|
||||
factory RecordingInfo.fromJson(Map<String, dynamic> json) => RecordingInfo(
|
||||
recording: Recording.fromJson(json['recording']),
|
||||
performances: json['performances']
|
||||
.map<PerformanceInfo>((j) => PerformanceInfo.fromJson(j))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'recording': recording.toJson(),
|
||||
'performances': performances.map((p) => p.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ class CompositionsController extends ResourceController {
|
|||
|
||||
@Operation.get('id')
|
||||
Future<Response> getWorks(@Bind.path('id') int id) async {
|
||||
final works = db.worksByComposer(id).get();
|
||||
final works = await db.getWorks(id);
|
||||
return Response.ok(works);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
import 'package:aqueduct/aqueduct.dart';
|
||||
import 'package:musicus_database/musicus_database.dart';
|
||||
|
||||
class PerformancesController extends ResourceController {
|
||||
final Database db;
|
||||
|
||||
PerformancesController(this.db);
|
||||
|
||||
@Operation.get('id')
|
||||
Future<Response> getPerformances(@Bind.path('id') int id) async {
|
||||
final performances = await db.performancesByRecording(id).get();
|
||||
return Response.ok(performances);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ class RecordingsController extends ResourceController {
|
|||
|
||||
@Operation.get('id')
|
||||
Future<Response> getRecording(@Bind.path('id') int id) async {
|
||||
final recording = await db.recordingById(id).getSingle();
|
||||
final recording = await db.getRecording(id);
|
||||
if (recording != null) {
|
||||
return Response.ok(recording);
|
||||
} else {
|
||||
|
|
@ -21,6 +21,7 @@ class RecordingsController extends ResourceController {
|
|||
@Bind.path('id') int id, @Bind.body() Map<String, dynamic> json) async {
|
||||
final data = RecordingData.fromJson(json);
|
||||
await db.updateRecording(data);
|
||||
return Response.ok(null);
|
||||
|
||||
return Response.ok(await db.getRecording(id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,8 @@ import 'compositions.dart';
|
|||
import 'configuration.dart';
|
||||
import 'ensembles.dart';
|
||||
import 'instruments.dart';
|
||||
import 'performances.dart';
|
||||
import 'persons.dart';
|
||||
import 'recordings.dart';
|
||||
import 'work_parts.dart';
|
||||
import 'works.dart';
|
||||
|
||||
class MusicusServer extends ApplicationChannel {
|
||||
|
|
@ -35,10 +33,7 @@ class MusicusServer extends ApplicationChannel {
|
|||
..route('/persons/:id/works').link(() => CompositionsController(db))
|
||||
..route('/instruments/[:id]').link(() => InstrumentsController(db))
|
||||
..route('/works/:id').link(() => WorksController(db))
|
||||
..route('/works/:id/parts').link(() => WorkPartsController(db))
|
||||
..route('/works/:id/recordings').link(() => WorkRecordingsController(db))
|
||||
..route('/ensembles/[:id]').link(() => EnsemblesController(db))
|
||||
..route('/recordings/:id').link(() => RecordingsController(db))
|
||||
..route('/recordings/:id/performances')
|
||||
.link(() => PerformancesController(db));
|
||||
..route('/recordings/:id').link(() => RecordingsController(db));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
import 'package:aqueduct/aqueduct.dart';
|
||||
import 'package:musicus_database/musicus_database.dart';
|
||||
|
||||
class WorkPartsController extends ResourceController {
|
||||
final Database db;
|
||||
|
||||
WorkPartsController(this.db);
|
||||
|
||||
@Operation.get('id')
|
||||
Future<Response> getParts(@Bind.path('id') int id) async {
|
||||
final parts = await db.workParts(id).get();
|
||||
return Response.ok(parts);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ class WorkRecordingsController extends ResourceController {
|
|||
|
||||
@Operation.get('id')
|
||||
Future<Response> getRecordings(@Bind.path('id') int id) async {
|
||||
final recordings = await db.recordingsByWork(id).get();
|
||||
final recordings = await db.getRecordings(id);
|
||||
return Response.ok(recordings);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class WorksController extends ResourceController {
|
|||
|
||||
@Operation.get('id')
|
||||
Future<Response> getWork(@Bind.path('id') int id) async {
|
||||
final work = await db.workById(id).getSingle();
|
||||
final work = await db.getWork(id);
|
||||
if (work != null) {
|
||||
return Response.ok(work);
|
||||
} else {
|
||||
|
|
@ -21,6 +21,7 @@ class WorksController extends ResourceController {
|
|||
@Bind.path('id') int id, @Bind.body() Map<String, dynamic> json) async {
|
||||
final data = WorkData.fromJson(json);
|
||||
await db.updateWork(data);
|
||||
return Response.ok(null);
|
||||
|
||||
return Response.ok(await db.getWork(id));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue