@@ -15,3 +15,4 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
export 'enums/where_query_type.dart';
|
||||
export 'mixins/operation.dart';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/// Defines different query types for WhereQuery.
|
||||
enum WhereQueryType {
|
||||
isEqualTo,
|
||||
isNotEqualTo,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2023 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
|
||||
/// Defines every write operation in CRUD.
|
||||
mixin CreateOperation<Model extends ObjectModel, Out> on AsyncUseCase<Model, Out> {}
|
||||
|
||||
/// Defines every read operation in CRUD.
|
||||
mixin ReadOperation<Model extends ObjectModel, In, Out> on AsyncUseCase<In, Out> {}
|
||||
|
||||
/// Defines every update operation in CRUD.
|
||||
mixin UpdateOperation<Model extends ObjectModel, In> on AsyncUseCase<In, void> {}
|
||||
|
||||
/// Defines every delete operation in CRUD.
|
||||
mixin DeleteOperation<Model extends ObjectModel, In> on AsyncUseCase<In, void> {}
|
||||
+6
-2
@@ -17,13 +17,17 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/extensions/num_extension.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/data_sources/crud_data_source.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/data_sources/data_sources.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||
|
||||
/// {@template crud_in_memory_data_source_impl}
|
||||
/// A [CrudDataSource] that stores data in memory.
|
||||
/// {@endtemplate}
|
||||
class CrudInMemoryDataSourceImpl<Model extends ObjectModel>
|
||||
extends CrudDataSource<Model> {
|
||||
/// {@macro crud_in_memory_data_source_impl}
|
||||
CrudInMemoryDataSourceImpl({required this.toMap, Map<String, Model>? data})
|
||||
: _data = data ?? {};
|
||||
final Map<String, Model> _data;
|
||||
|
||||
+8
@@ -20,15 +20,23 @@ import 'package:wyatt_crud_bloc/src/domain/data_sources/crud_data_source.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
|
||||
/// {@template crud_firestore_data_source_impl}
|
||||
/// A concrete implementation of [CrudDataSource] that uses
|
||||
/// [FirebaseFirestore] as the data source.
|
||||
/// {@endtemplate}
|
||||
class CrudFirestoreDataSourceImpl<Model extends ObjectModel, Entity>
|
||||
extends CrudDataSource<Model> {
|
||||
/// {@macro crud_firestore_data_source_impl}
|
||||
CrudFirestoreDataSourceImpl(
|
||||
String collection, {
|
||||
/// The function that converts a [DocumentSnapshot] to a [Model].
|
||||
required Model Function(
|
||||
DocumentSnapshot<Map<String, dynamic>>,
|
||||
SnapshotOptions?,
|
||||
)
|
||||
fromFirestore,
|
||||
|
||||
/// The function that converts a [Model] to a [Map<String, Object?>].
|
||||
required Map<String, Object?> Function(Model, SetOptions?) toFirestore,
|
||||
FirebaseFirestore? firestore,
|
||||
}) : _firestore = firestore ?? FirebaseFirestore.instance,
|
||||
|
||||
@@ -21,9 +21,13 @@ import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
import 'package:wyatt_type_utils/wyatt_type_utils.dart';
|
||||
|
||||
/// {@template crud_repository_impl}
|
||||
/// A repository that implements the [CrudRepository] interface.
|
||||
/// {@endtemplate}
|
||||
class CrudRepositoryImpl<Model extends ObjectModel>
|
||||
extends CrudRepository<Model> {
|
||||
CrudRepositoryImpl({
|
||||
/// {@macro crud_repository_impl}
|
||||
const CrudRepositoryImpl({
|
||||
required CrudDataSource<Model> crudDataSource,
|
||||
}) : _crudDataSource = crudDataSource;
|
||||
final CrudDataSource<Model> _crudDataSource;
|
||||
@@ -99,6 +103,6 @@ class CrudRepositoryImpl<Model extends ObjectModel>
|
||||
if (lst.isNotNull) {
|
||||
return Ok<List<Model?>, AppException>(lst);
|
||||
}
|
||||
return Err<List<Model?>, AppException>(ServerException());
|
||||
return Err<List<Model?>, AppException>(const ServerException());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -17,27 +17,42 @@
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
|
||||
/// {@template crud_data_source}
|
||||
/// A [BaseDataSource] that provides SCRUD operations.
|
||||
/// {@endtemplate}
|
||||
abstract class CrudDataSource<Model> extends BaseDataSource {
|
||||
/// {@macro crud_data_source}
|
||||
const CrudDataSource();
|
||||
|
||||
/// Creates a new [Model] object.
|
||||
Future<void> create(Model object, {String? id});
|
||||
|
||||
/// Gets a [Model] object by its [id].
|
||||
Future<Model?> get(String id);
|
||||
|
||||
/// Gets all [Model] objects.
|
||||
Future<List<Model?>> getAll();
|
||||
|
||||
/// Updates a [Model] object by its [id].
|
||||
Future<void> update(
|
||||
String id, {
|
||||
Model? object,
|
||||
Map<String, dynamic>? raw,
|
||||
});
|
||||
|
||||
/// Updates all [Model] objects.
|
||||
Future<void> updateAll(Map<String, Object?>? data);
|
||||
|
||||
/// Deletes a [Model] object by its [id].
|
||||
Future<void> delete(String id);
|
||||
|
||||
/// Deletes all [Model] objects.
|
||||
Future<void> deleteAll();
|
||||
|
||||
/// Queries [Model] objects by [conditions].
|
||||
Future<List<Model?>> query(List<QueryInterface> conditions);
|
||||
|
||||
/// Streams [Model] objects by [conditions].
|
||||
Stream<List<Model?>> stream({
|
||||
String? id,
|
||||
List<QueryInterface>? conditions,
|
||||
|
||||
@@ -16,6 +16,13 @@
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
|
||||
/// {@template object_model}
|
||||
/// An abstract class that represents an object model.
|
||||
/// {@endtemplate}
|
||||
abstract class ObjectModel extends Entity {
|
||||
/// {@macro object_model}
|
||||
const ObjectModel();
|
||||
|
||||
/// The id of the object model.
|
||||
String? get id;
|
||||
}
|
||||
|
||||
@@ -17,27 +17,59 @@
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart';
|
||||
|
||||
// ignore: one_member_abstracts
|
||||
abstract class QueryParser<Q> {
|
||||
Q parser(QueryInterface condition, Q query);
|
||||
// // ignore: one_member_abstracts
|
||||
// abstract class QueryParser<Q> {
|
||||
// Q parser(QueryInterface condition, Q query);
|
||||
// }
|
||||
|
||||
typedef QueryParser<Q> = Q Function(QueryInterface condition, Q query);
|
||||
|
||||
/// {@template query}
|
||||
/// An abstract class that represents a query.
|
||||
/// {@endtemplate}
|
||||
abstract class QueryInterface extends Entity {
|
||||
/// {@macro query}
|
||||
const QueryInterface();
|
||||
}
|
||||
|
||||
abstract class QueryInterface extends Entity {}
|
||||
|
||||
/// {@template where_query}
|
||||
/// Represents a where query.
|
||||
/// {@endtemplate}
|
||||
class WhereQuery<Value> extends QueryInterface {
|
||||
WhereQuery(this.type, this.field, this.value);
|
||||
/// {@macro where_query}
|
||||
const WhereQuery(this.type, this.field, this.value);
|
||||
|
||||
/// The type of the where query.
|
||||
final WhereQueryType type;
|
||||
|
||||
/// The field of the where query.
|
||||
final String field;
|
||||
|
||||
/// The value of the where query.
|
||||
final Value value;
|
||||
}
|
||||
|
||||
/// {@template limit_query}
|
||||
/// Represents a limit query.
|
||||
/// {@endtemplate}
|
||||
class LimitQuery extends QueryInterface {
|
||||
LimitQuery(this.limit);
|
||||
/// {@macro limit_query}
|
||||
const LimitQuery(this.limit);
|
||||
|
||||
/// The limit of the limit query.
|
||||
final int limit;
|
||||
}
|
||||
|
||||
/// {@template offset_query}
|
||||
/// Represents an offset query.
|
||||
/// {@endtemplate}
|
||||
class OrderByQuery extends QueryInterface {
|
||||
OrderByQuery(this.field, {this.ascending = true});
|
||||
/// {@macro offset_query}
|
||||
const OrderByQuery(this.field, {this.ascending = true});
|
||||
|
||||
/// The field of the order by query.
|
||||
final String field;
|
||||
|
||||
/// The ascending of the order by query.
|
||||
final bool ascending;
|
||||
}
|
||||
|
||||
@@ -18,20 +18,43 @@ import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
|
||||
/// {@template crud_repository}
|
||||
/// An abstract class that represents a SCRUD repository.
|
||||
/// {@endtemplate}
|
||||
abstract class CrudRepository<Model extends ObjectModel>
|
||||
extends BaseRepository {
|
||||
/// {@macro crud_repository}
|
||||
const CrudRepository();
|
||||
|
||||
/// Creates a new object.
|
||||
FutureOrResult<void> create(Model object, {String? id});
|
||||
|
||||
/// Gets an object by its [id].
|
||||
FutureOrResult<Model?> get(String id);
|
||||
|
||||
/// Gets all objects.
|
||||
FutureOrResult<List<Model?>> getAll();
|
||||
|
||||
/// Updates an object by its [id].
|
||||
FutureOrResult<void> update(
|
||||
String id, {
|
||||
Model? object,
|
||||
Map<String, dynamic>? raw,
|
||||
});
|
||||
|
||||
/// Updates all objects.
|
||||
FutureOrResult<void> updateAll(Map<String, Object?> raw);
|
||||
|
||||
/// Deletes an object by its [id].
|
||||
FutureOrResult<void> delete(String id);
|
||||
|
||||
/// Deletes all objects.
|
||||
FutureOrResult<void> deleteAll();
|
||||
|
||||
/// Queries objects by [conditions].
|
||||
FutureOrResult<List<Model?>> query(List<QueryInterface> conditions);
|
||||
|
||||
/// Streams objects by [conditions].
|
||||
StreamResult<List<Model?>> stream({
|
||||
String? id,
|
||||
List<QueryInterface>? conditions,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
@@ -18,13 +17,19 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
class Create<Model extends ObjectModel> extends AsyncUseCase<Model, void> {
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
/// {@template create}
|
||||
/// A use case that creates an object model.
|
||||
/// {@endtemplate}
|
||||
class Create<Model extends ObjectModel> extends AsyncUseCase<Model, void>
|
||||
with CreateOperation<Model, void> {
|
||||
/// {@macro create}
|
||||
const Create(this._crudRepository);
|
||||
|
||||
Create(this._crudRepository);
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(Model? params) {
|
||||
|
||||
@@ -17,17 +17,24 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
class Delete<Model extends ObjectModel> extends AsyncUseCase<String, void> {
|
||||
Delete(this._crudRepository);
|
||||
/// {@template delete}
|
||||
/// A use case that deletes an object model.
|
||||
/// {@endtemplate}
|
||||
class Delete<Model extends ObjectModel> extends AsyncUseCase<String, void>
|
||||
with DeleteOperation<Model, String> {
|
||||
/// {@macro delete}
|
||||
const Delete(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(String? params) {
|
||||
if (params == null) {
|
||||
throw ClientException('Id cannot be null.');
|
||||
throw const ClientException('Id cannot be null.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
class DeleteAll<Model extends ObjectModel> extends AsyncUseCase<void, void> {
|
||||
DeleteAll(this._crudRepository);
|
||||
/// {@template delete_all}
|
||||
/// A use case that deletes all the object models.
|
||||
/// {@endtemplate}
|
||||
class DeleteAll<Model extends ObjectModel> extends AsyncUseCase<void, void>
|
||||
with DeleteOperation<Model, void> {
|
||||
/// {@macro delete_all}
|
||||
const DeleteAll(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
|
||||
@@ -17,17 +17,24 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
class Get<Model extends ObjectModel> extends AsyncUseCase<String, Model?> {
|
||||
/// {@template get}
|
||||
/// A use case that gets an object model.
|
||||
/// {@endtemplate}
|
||||
class Get<Model extends ObjectModel> extends AsyncUseCase<String, Model?>
|
||||
with ReadOperation<Model, String, Model?> {
|
||||
/// {@macro get}
|
||||
Get(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(String? params) {
|
||||
if (params == null) {
|
||||
throw ClientException('Id cannot be null.');
|
||||
throw const ClientException('Id cannot be null.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,18 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
class GetAll<Model extends ObjectModel>
|
||||
extends AsyncUseCase<void, List<Model?>> {
|
||||
GetAll(this._crudRepository);
|
||||
/// {@template get_all}
|
||||
/// A use case that gets all the object models.
|
||||
/// {@endtemplate}
|
||||
class GetAll<Model extends ObjectModel> extends AsyncUseCase<void, List<Model?>>
|
||||
with ReadOperation<Model, void, List<Model?>> {
|
||||
/// {@macro get_all}
|
||||
const GetAll(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
@@ -17,12 +16,19 @@
|
||||
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
|
||||
/// {@template stream_parameters}
|
||||
/// Represents the parameters for a query stream
|
||||
/// {@endtemplate}
|
||||
class StreamParameters {
|
||||
final String? id;
|
||||
final List<QueryInterface>? conditions;
|
||||
|
||||
StreamParameters({
|
||||
/// {@macro stream_parameters}
|
||||
const StreamParameters({
|
||||
this.id,
|
||||
this.conditions,
|
||||
});
|
||||
|
||||
/// The id of the object model.
|
||||
final String? id;
|
||||
|
||||
/// The conditions of the query.
|
||||
final List<QueryInterface>? conditions;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
@@ -15,14 +14,23 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/// {@template update_parameters}
|
||||
/// Represents the parameters for an update use case
|
||||
/// {@endtemplate}
|
||||
class UpdateParameters<Model> {
|
||||
final String id;
|
||||
final Model? object;
|
||||
final Map<String, dynamic>? raw;
|
||||
|
||||
UpdateParameters({
|
||||
/// {@macro update_parameters}
|
||||
const UpdateParameters({
|
||||
required this.id,
|
||||
this.object,
|
||||
this.raw,
|
||||
});
|
||||
|
||||
/// The id of the object model.
|
||||
final String id;
|
||||
|
||||
/// The object model.
|
||||
final Model? object;
|
||||
|
||||
/// The raw data.
|
||||
final Map<String, dynamic>? raw;
|
||||
}
|
||||
|
||||
@@ -17,19 +17,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
/// {@template query}
|
||||
/// A use case that queries the object models.
|
||||
/// {@endtemplate}
|
||||
class Query<Model extends ObjectModel>
|
||||
extends AsyncUseCase<List<QueryInterface>, List<Model?>> {
|
||||
Query(this._crudRepository);
|
||||
extends AsyncUseCase<List<QueryInterface>, List<Model?>>
|
||||
with ReadOperation<Model, List<QueryInterface>, List<Model?>> {
|
||||
/// {@macro query}
|
||||
const Query(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(List<QueryInterface>? params) {
|
||||
if (params == null) {
|
||||
throw ClientException('List of conditions cannot be null.');
|
||||
throw const ClientException('List of conditions cannot be null.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// class Stream<Model extends ObjectModel> extends UseCase<StreamParameters,
|
||||
//List<Model?>> {
|
||||
// final CrudRepository<Model> _crudRepository;
|
||||
|
||||
// Stream(this._crudRepository);
|
||||
|
||||
// @override
|
||||
// StreamResult<List<Model?>> call(StreamParameters params) =>
|
||||
// _crudRepository.stream(id: params.id, conditions: params.conditions);
|
||||
// }
|
||||
|
||||
// class StreamQuery<Model extends ObjectModel>
|
||||
// extends StreamUseCase<StreamParameters, List<Model?>> {
|
||||
// final CrudRepository<Model> _crudRepository;
|
||||
|
||||
// StreamQuery(this._crudRepository);
|
||||
|
||||
// @override
|
||||
// FutureOr<void> onStart(StreamParameters? params) {
|
||||
// if(params == null){
|
||||
// throw ClientException('Stream parameters cannot be null.');
|
||||
// }
|
||||
// }
|
||||
|
||||
// @override
|
||||
// FutureOrResult<Stream<List<Model?>>> call(StreamParameters? params) =>
|
||||
// _crudRepository.stream();
|
||||
// }
|
||||
@@ -17,19 +17,26 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart';
|
||||
|
||||
/// {@template update}
|
||||
/// A use case that updates an object model.
|
||||
/// {@endtemplate}
|
||||
class Update<Model extends ObjectModel>
|
||||
extends AsyncUseCase<UpdateParameters<Model>, void> {
|
||||
Update(this._crudRepository);
|
||||
extends AsyncUseCase<UpdateParameters<Model>, void>
|
||||
with UpdateOperation<Model, UpdateParameters<Model>> {
|
||||
/// {@macro update}
|
||||
const Update(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(UpdateParameters<Model>? params) {
|
||||
if (params == null) {
|
||||
throw ClientException('Update parameters cannot be null.');
|
||||
throw const ClientException('Update parameters cannot be null.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,18 +17,25 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/repositories/crud_repository.dart';
|
||||
|
||||
/// {@template update_all}
|
||||
/// A use case that updates all the object models.
|
||||
/// {@endtemplate}
|
||||
class UpdateAll<Model extends ObjectModel>
|
||||
extends AsyncUseCase<Map<String, Object?>, void> {
|
||||
UpdateAll(this._crudRepository);
|
||||
extends AsyncUseCase<Map<String, Object?>, void>
|
||||
with UpdateOperation<Model, Map<String, Object?>> {
|
||||
/// {@macro update_all}
|
||||
const UpdateAll(this._crudRepository);
|
||||
|
||||
final CrudRepository<Model> _crudRepository;
|
||||
|
||||
@override
|
||||
FutureOr<void> onStart(Map<String, Object?>? params) {
|
||||
if (params == null) {
|
||||
throw ClientException('Data cannot be null.');
|
||||
throw const ClientException('Data cannot be null.');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,5 @@ export 'get.dart';
|
||||
export 'get_all.dart';
|
||||
export 'params/params.dart';
|
||||
export 'query.dart';
|
||||
export 'stream_query.dart';
|
||||
export 'update.dart';
|
||||
export 'update_all.dart';
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// Copyright (C) 2023 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart';
|
||||
|
||||
/// {@template crud_cubit_advanced}
|
||||
/// Cubit that handles CRUD operations with more granularity.
|
||||
/// {@endtemplate}
|
||||
abstract class CrudAdvancedCubit<Model extends ObjectModel>
|
||||
extends CrudBaseCubit {
|
||||
/// {@macro crud_cubit}
|
||||
CrudAdvancedCubit() : super();
|
||||
|
||||
Create<Model>? get crudCreate;
|
||||
DeleteAll<Model>? get crudDeleteAll;
|
||||
Delete<Model>? get crudDelete;
|
||||
GetAll<Model>? get crudGetAll;
|
||||
Get<Model>? get crudGet;
|
||||
Query<Model>? get crudQuery;
|
||||
UpdateAll<Model>? get crudUpdateAll;
|
||||
Update<Model>? get crudUpdate;
|
||||
|
||||
FutureOr<void> create(Model model) async {
|
||||
final crud = crudCreate;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(model);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data == null) {
|
||||
return CrudLoaded<Model?>(model);
|
||||
}
|
||||
if (stateCopy.data!.id == model.id) {
|
||||
return CrudLoaded<Model?>(model);
|
||||
}
|
||||
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
if (stateCopy.data.isEmpty) {
|
||||
return CrudListLoaded<Model?>([model]);
|
||||
}
|
||||
final List<Model?> lst = stateCopy.data.toList()..add(model);
|
||||
|
||||
return CrudListLoaded<Model?>(lst);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> delete(String id) async {
|
||||
final crud = crudDelete;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data?.id == id) {
|
||||
return CrudLoaded<Model?>(null);
|
||||
}
|
||||
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(
|
||||
stateCopy.data.where((element) => element?.id != id).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> deleteAll() async {
|
||||
final crud = crudDeleteAll;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
return CrudLoaded<Model?>(null);
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(const []);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> get(String id) async {
|
||||
final crud = crudGet;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> getAll() async {
|
||||
final crud = crudGetAll;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> query(List<QueryInterface> conditions) async {
|
||||
final crud = crudQuery;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(conditions);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> update(UpdateParameters<Model> param) async {
|
||||
final crud = crudUpdate;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data?.id == param.id) {
|
||||
// Same object, need to update actual stateCopy
|
||||
final crudGet = this.crudGet;
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final newVersion = await crudGet.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
final bool listContains =
|
||||
stateCopy.data.any((element) => element?.id == param.id);
|
||||
if (listContains) {
|
||||
// Loaded objects contains the modified object.
|
||||
|
||||
final crudGet = this.crudGet;
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final newVersion = await crudGet.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
final newList = stateCopy.data
|
||||
.where(
|
||||
(element) => element?.id != param.id,
|
||||
)
|
||||
.toList();
|
||||
return CrudListLoaded<Model?>(newList + [newVersion.ok]);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> updateAll(Map<String, Object?> param) async {
|
||||
final crud = crudUpdateAll;
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
// Same object, need to update actual stateCopy
|
||||
final crudGet = this.crudGet;
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final actualId = stateCopy.data?.id;
|
||||
final newVersion = await crudGet.call(actualId ?? '');
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
final crudQuery = this.crudQuery;
|
||||
if (crudQuery == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
// Load all id to retrieve exactly same object
|
||||
// (not all because previous stateCopy can be a query result)
|
||||
final List<String?> ids = stateCopy.data
|
||||
.map(
|
||||
(e) => e?.id,
|
||||
)
|
||||
.toList();
|
||||
final result = await crudQuery.call([
|
||||
WhereQuery(
|
||||
WhereQueryType.whereIn,
|
||||
'id',
|
||||
ids,
|
||||
)
|
||||
]);
|
||||
if (result.isOk) {
|
||||
return CrudListLoaded<Model?>(result.ok ?? []);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
-32
@@ -14,38 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
extension NumExtension on num? {
|
||||
bool operator <(num? other) {
|
||||
if (this == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return this < other;
|
||||
}
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
bool operator >(num? other) {
|
||||
if (this == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return this > other;
|
||||
}
|
||||
part 'crud_state.dart';
|
||||
|
||||
bool operator <=(num? other) {
|
||||
if (this == null && other == null) {
|
||||
return true;
|
||||
}
|
||||
if (this == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return this <= other;
|
||||
}
|
||||
|
||||
bool operator >=(num? other) {
|
||||
if (this == null && other == null) {
|
||||
return true;
|
||||
}
|
||||
if (this == null || other == null) {
|
||||
return false;
|
||||
}
|
||||
return this >= other;
|
||||
}
|
||||
/// {@template crud_base_cubit}
|
||||
/// A base [Cubit] that handles SCRUD operations.
|
||||
/// {@endtemplate}
|
||||
abstract class CrudBaseCubit extends Cubit<CrudState> {
|
||||
/// {@macro crud_base_cubit}
|
||||
CrudBaseCubit() : super(const CrudInitial());
|
||||
}
|
||||
+30
-10
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Copyright (C) 2023 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
@@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
part of 'crud_cubit.dart';
|
||||
part of 'crud_base_cubit.dart';
|
||||
|
||||
abstract class CrudState extends Equatable {
|
||||
const CrudState();
|
||||
@@ -23,18 +23,17 @@ abstract class CrudState extends Equatable {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class CrudInitial extends CrudState {}
|
||||
|
||||
class CrudLoading extends CrudState {}
|
||||
|
||||
abstract class CrudSuccess extends CrudState {
|
||||
const CrudSuccess();
|
||||
/// Initial state of the CrudBaseCubit.
|
||||
class CrudInitial extends CrudState {
|
||||
const CrudInitial();
|
||||
}
|
||||
|
||||
class CrudOkReturn extends CrudState {
|
||||
const CrudOkReturn();
|
||||
/// Loading state of the CrudBaseCubit.
|
||||
class CrudLoading extends CrudState {
|
||||
const CrudLoading();
|
||||
}
|
||||
|
||||
/// Error state of the CrudBaseCubit.
|
||||
class CrudError extends CrudState {
|
||||
const CrudError(this.message);
|
||||
final String? message;
|
||||
@@ -43,6 +42,24 @@ class CrudError extends CrudState {
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
|
||||
/// Success state of the CrudBaseCubit.
|
||||
/// This state is used to indicate that the operation was successful.
|
||||
/// Can be one or list of objects.
|
||||
abstract class CrudSuccess extends CrudState {
|
||||
const CrudSuccess();
|
||||
}
|
||||
|
||||
/// Success state of the CrudBaseCubit.
|
||||
/// This state is used to indicate that the operation was successful.
|
||||
/// Contains no objects.
|
||||
/// Used for create, update, delete operations.
|
||||
class CrudOkReturn extends CrudSuccess {
|
||||
const CrudOkReturn();
|
||||
}
|
||||
|
||||
/// Loaded state of the CrudBaseCubit.
|
||||
/// This state is used to indicate that the operation was successful.
|
||||
/// Contains one object.
|
||||
class CrudLoaded<T> extends CrudSuccess {
|
||||
const CrudLoaded(this.data);
|
||||
final T? data;
|
||||
@@ -51,6 +68,9 @@ class CrudLoaded<T> extends CrudSuccess {
|
||||
List<Object?> get props => [data];
|
||||
}
|
||||
|
||||
/// Loaded state of the CrudBaseCubit.
|
||||
/// This state is used to indicate that the operation was successful.
|
||||
/// Contains list of objects.
|
||||
class CrudListLoaded<T> extends CrudSuccess {
|
||||
const CrudListLoaded(this.data);
|
||||
final List<T?> data;
|
||||
@@ -0,0 +1,369 @@
|
||||
// Copyright (C) 2023 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/mixins/operation.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart';
|
||||
|
||||
/// {@template crud_cubit}
|
||||
/// Cubit that handles CRUD operations.
|
||||
/// {@endtemplate}
|
||||
abstract class CrudCubit<Model extends ObjectModel> extends CrudBaseCubit {
|
||||
/// {@macro crud_cubit}
|
||||
CrudCubit() : super();
|
||||
|
||||
/// Create operation.
|
||||
/// Can be create.
|
||||
CreateOperation<Model, dynamic>? get createOperation;
|
||||
|
||||
/// Read operation.
|
||||
/// Can be get, getAll, query.
|
||||
ReadOperation<Model, dynamic, dynamic>? get readOperation;
|
||||
|
||||
/// Update operation.
|
||||
/// Can be update, updateAll.
|
||||
UpdateOperation<Model, dynamic>? get updateOperation;
|
||||
|
||||
/// Delete operation.
|
||||
/// Can be delete or deleteAll.
|
||||
DeleteOperation<Model, dynamic>? get deleteOperation;
|
||||
|
||||
Expected? _checkOperation<Expected>(dynamic operation) {
|
||||
if (operation == null) {
|
||||
return null;
|
||||
}
|
||||
if (operation is! Expected) {
|
||||
return null;
|
||||
}
|
||||
return operation;
|
||||
}
|
||||
|
||||
FutureOr<void> create(Model model) async {
|
||||
if (_checkOperation<Create<Model>>(createOperation) != null) {
|
||||
return _create(model);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> read({String? id, List<QueryInterface>? conditions}) async {
|
||||
if (_checkOperation<Get<Model>>(readOperation) != null && id != null) {
|
||||
return _get(id);
|
||||
}
|
||||
if (_checkOperation<GetAll<Model>>(readOperation) != null) {
|
||||
return _getAll();
|
||||
}
|
||||
if (_checkOperation<Query<Model>>(readOperation) != null &&
|
||||
conditions != null) {
|
||||
return _query(conditions);
|
||||
}
|
||||
if (_checkOperation<Query<Model>>(readOperation) != null &&
|
||||
conditions == null) {
|
||||
return _getAll();
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> update(
|
||||
UpdateParameters<Model>? single,
|
||||
Map<String, dynamic>? all,
|
||||
) async {
|
||||
if (_checkOperation<Update<Model>>(updateOperation) != null &&
|
||||
single != null) {
|
||||
return _update(single);
|
||||
}
|
||||
|
||||
if (_checkOperation<UpdateAll<Model>>(updateOperation) != null &&
|
||||
all != null) {
|
||||
return _updateAll(all);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> delete({String? id}) async {
|
||||
if (_checkOperation<Delete<Model>>(deleteOperation) != null && id != null) {
|
||||
return _delete(id);
|
||||
}
|
||||
if (_checkOperation<DeleteAll<Model>>(deleteOperation) != null) {
|
||||
return _deleteAll();
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _create(Model model) async {
|
||||
final crud = _checkOperation<Create<Model>>(createOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(model);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data == null) {
|
||||
return CrudLoaded<Model?>(model);
|
||||
}
|
||||
if (stateCopy.data!.id == model.id) {
|
||||
return CrudLoaded<Model?>(model);
|
||||
}
|
||||
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
if (stateCopy.data.isEmpty) {
|
||||
return CrudListLoaded<Model?>([model]);
|
||||
}
|
||||
final List<Model?> lst = stateCopy.data.toList()..add(model);
|
||||
|
||||
return CrudListLoaded<Model?>(lst);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _delete(String id) async {
|
||||
final crud = _checkOperation<Delete<Model>>(deleteOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data?.id == id) {
|
||||
return CrudLoaded<Model?>(null);
|
||||
}
|
||||
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(
|
||||
stateCopy.data.where((element) => element?.id != id).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _deleteAll() async {
|
||||
final crud = _checkOperation<DeleteAll<Model>>(deleteOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
return CrudLoaded<Model?>(null);
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(const []);
|
||||
}
|
||||
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _get(String id) async {
|
||||
final crud = _checkOperation<Get<Model>>(readOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _getAll() async {
|
||||
final crud = _checkOperation<GetAll<Model>>(readOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _query(List<QueryInterface> conditions) async {
|
||||
final crud = _checkOperation<Query<Model>>(readOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(conditions);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _update(UpdateParameters<Model> param) async {
|
||||
final crud = _checkOperation<Update<Model>>(updateOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data?.id == param.id) {
|
||||
// Same object, need to update actual stateCopy
|
||||
final crudGet = _checkOperation<Get<Model>>(readOperation);
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final newVersion = await crudGet.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
final bool listContains =
|
||||
stateCopy.data.any((element) => element?.id == param.id);
|
||||
if (listContains) {
|
||||
// Loaded objects contains the modified object.
|
||||
|
||||
final crudGet = _checkOperation<Get<Model>>(readOperation);
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final newVersion = await crudGet.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
final newList = stateCopy.data
|
||||
.where(
|
||||
(element) => element?.id != param.id,
|
||||
)
|
||||
.toList();
|
||||
return CrudListLoaded<Model?>(newList + [newVersion.ok]);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
FutureOr<void> _updateAll(Map<String, Object?> param) async {
|
||||
final crud = _checkOperation<UpdateAll<Model>>(updateOperation);
|
||||
if (crud == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final stateCopy = state;
|
||||
emit(const CrudLoading());
|
||||
final result = await crud.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
// Same object, need to update actual stateCopy
|
||||
final crudGet = _checkOperation<Get<Model>>(readOperation);
|
||||
if (crudGet == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
final actualId = stateCopy.data?.id;
|
||||
final newVersion = await crudGet.call(actualId ?? '');
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
final crudQuery = _checkOperation<Query<Model>>(readOperation);
|
||||
if (crudQuery == null) {
|
||||
// No read operation, can't update stateCopy.
|
||||
return stateCopy;
|
||||
}
|
||||
// Load all id to retrieve exactly same object
|
||||
// (not all because previous stateCopy can be a query result)
|
||||
final List<String?> ids = stateCopy.data
|
||||
.map(
|
||||
(e) => e?.id,
|
||||
)
|
||||
.toList();
|
||||
final result = await crudQuery.call([
|
||||
WhereQuery(
|
||||
WhereQueryType.whereIn,
|
||||
'id',
|
||||
ids,
|
||||
)
|
||||
]);
|
||||
if (result.isOk) {
|
||||
return CrudListLoaded<Model?>(result.ok ?? []);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,19 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:wyatt_crud_bloc/src/features/crud/cubit/crud_cubit.dart';
|
||||
import 'package:wyatt_crud_bloc/src/features/crud/blocs/crud_base_cubit/crud_base_cubit.dart';
|
||||
|
||||
/// {@template crud_builder}
|
||||
/// A widget that builds itself based on the latest snapshot of interaction
|
||||
/// with a [CrudBaseCubit].
|
||||
///
|
||||
/// * I = Initial State
|
||||
/// * L = Loading State
|
||||
/// * S = Success State
|
||||
/// * E = Error State
|
||||
/// {@endtemplate}
|
||||
class CrudBuilder<I, L, S, E> extends StatelessWidget {
|
||||
/// `<I, L, S, E>`
|
||||
///
|
||||
/// - I: the Initial State
|
||||
/// - L: the Loading State
|
||||
/// - S: the Success State
|
||||
/// - E: the Error State
|
||||
/// {@macro crud_builder}
|
||||
const CrudBuilder({
|
||||
required this.state,
|
||||
required this.builder,
|
||||
@@ -34,11 +38,11 @@ class CrudBuilder<I, L, S, E> extends StatelessWidget {
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// `<CrudInitial, CrudLoading, S extends CrudSuccess, CrudError>`
|
||||
/// {@macro crud_builder}
|
||||
///
|
||||
/// - S: the Success State
|
||||
///
|
||||
/// For CrudStates only.
|
||||
/// This factory constructor is used to create a [CrudBuilder] with
|
||||
/// [CrudState]s. `S` is the Success State, and it must be a subtype of
|
||||
/// [CrudSuccess]. It the only type that you have to specify.
|
||||
static CrudBuilder<CrudInitial, CrudLoading, CrudSuccess, CrudError>
|
||||
typed<S extends CrudSuccess>({
|
||||
required CrudState state,
|
||||
|
||||
@@ -14,5 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
export 'blocs/crud_advanced_cubit.dart';
|
||||
export 'blocs/crud_base_cubit/crud_base_cubit.dart';
|
||||
export 'blocs/crud_cubit.dart';
|
||||
export 'builder/builder.dart';
|
||||
export 'cubit/crud_cubit.dart';
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
// Copyright (C) 2022 WYATT GROUP
|
||||
// Please see the AUTHORS file for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:wyatt_architecture/wyatt_architecture.dart';
|
||||
import 'package:wyatt_crud_bloc/src/core/enums/where_query_type.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/object_model.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/entities/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/create.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/delete_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/get_all.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/params/update_parameters.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/query.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update.dart';
|
||||
import 'package:wyatt_crud_bloc/src/domain/usecases/update_all.dart';
|
||||
|
||||
part 'crud_state.dart';
|
||||
|
||||
abstract class CrudCubit<Model extends ObjectModel> extends Cubit<CrudState> {
|
||||
CrudCubit() : super(CrudInitial());
|
||||
Create<Model>? get crudCreate;
|
||||
DeleteAll<Model>? get crudDeleteAll;
|
||||
Delete<Model>? get crudDelete;
|
||||
GetAll<Model>? get crudGetAll;
|
||||
Get<Model>? get crudGet;
|
||||
Query<Model>? get crudQuery;
|
||||
UpdateAll<Model>? get crudUpdateAll;
|
||||
Update<Model>? get crudUpdate;
|
||||
|
||||
FutureOr<void> create(Model model) async {
|
||||
if (crudCreate != null) {
|
||||
final stateCopy = state;
|
||||
emit(CrudLoading());
|
||||
final result = await crudCreate!.call(model);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
if (stateCopy.data.isEmpty) {
|
||||
return CrudListLoaded<Model?>([model]);
|
||||
}
|
||||
final List<Model?> lst = stateCopy.data.toList()..add(model);
|
||||
return CrudListLoaded<Model?>(lst);
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> delete(String id) async {
|
||||
if (crudDelete != null) {
|
||||
final stateCopy = state;
|
||||
emit(CrudLoading());
|
||||
final result = await crudDelete!.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(
|
||||
stateCopy.data.where((element) => element?.id != id).toList(),
|
||||
);
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> deleteAll() async {
|
||||
if (crudDeleteAll != null) {
|
||||
final stateCopy = state;
|
||||
emit(CrudLoading());
|
||||
final result = await crudDeleteAll!.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
(_) {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
return CrudLoaded<Model?>(null);
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
return CrudListLoaded<Model?>(const []);
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> get(String id) async {
|
||||
if (crudGet != null) {
|
||||
emit(CrudLoading());
|
||||
final result = await crudGet!.call(id);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> getAll() async {
|
||||
if (crudGetAll != null) {
|
||||
emit(CrudLoading());
|
||||
final result = await crudGetAll!.call(null);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> query(List<QueryInterface> conditions) async {
|
||||
if (crudQuery != null) {
|
||||
emit(CrudLoading());
|
||||
final result = await crudQuery!.call(conditions);
|
||||
emit(
|
||||
result.fold(
|
||||
CrudListLoaded<Model?>.new,
|
||||
(error) => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> update(UpdateParameters<Model> param) async {
|
||||
if (crudUpdate != null) {
|
||||
final stateCopy = state;
|
||||
emit(CrudLoading());
|
||||
final result = await crudUpdate!.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
if (stateCopy.data?.id == param.id) {
|
||||
// Same object, need to update actual stateCopy
|
||||
if (crudGet == null) {
|
||||
throw ClientException(
|
||||
'Need to init Get usecase to use update.',
|
||||
);
|
||||
}
|
||||
final newVersion = await crudGet!.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
final bool listContains =
|
||||
stateCopy.data.any((element) => element?.id == param.id);
|
||||
if (listContains) {
|
||||
// Loaded objects contains the modified object.
|
||||
if (crudGet == null) {
|
||||
throw ClientException(
|
||||
'Need to init Get usecase to use update.',
|
||||
);
|
||||
}
|
||||
final newVersion = await crudGet!.call(param.id);
|
||||
if (newVersion.isOk) {
|
||||
final newList = stateCopy.data
|
||||
.where(
|
||||
(element) => element?.id != param.id,
|
||||
)
|
||||
.toList();
|
||||
return CrudListLoaded<Model?>(newList + [newVersion.ok]);
|
||||
}
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> updateAll(Map<String, Object?> param) async {
|
||||
if (crudUpdateAll != null) {
|
||||
final stateCopy = state;
|
||||
emit(CrudLoading());
|
||||
final result = await crudUpdateAll!.call(param);
|
||||
emit(
|
||||
await result.foldAsync(
|
||||
(_) async {
|
||||
if (stateCopy is CrudLoaded<Model?>) {
|
||||
// Same object, need to update actual stateCopy
|
||||
if (crudGet == null) {
|
||||
throw ClientException(
|
||||
'Need to init Get usecase to use updateAll.',
|
||||
);
|
||||
}
|
||||
final actualId = stateCopy.data?.id;
|
||||
final newVersion = await crudGet!.call(actualId ?? '');
|
||||
if (newVersion.isOk) {
|
||||
return CrudLoaded<Model?>(newVersion.ok);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
if (stateCopy is CrudListLoaded<Model?>) {
|
||||
if (crudQuery == null) {
|
||||
throw ClientException(
|
||||
'Need to init Query usecase to use updateAll.',
|
||||
);
|
||||
}
|
||||
// Load all id to retrieve exactly same object
|
||||
// (not all because previous stateCopy can be a query result)
|
||||
final List<String?> ids = stateCopy.data
|
||||
.map(
|
||||
(e) => e?.id,
|
||||
)
|
||||
.toList();
|
||||
final result = await crudQuery!.call([
|
||||
WhereQuery(
|
||||
WhereQueryType.whereIn,
|
||||
'id',
|
||||
ids,
|
||||
)
|
||||
]);
|
||||
if (result.isOk) {
|
||||
return CrudListLoaded<Model?>(result.ok ?? []);
|
||||
}
|
||||
return stateCopy;
|
||||
}
|
||||
return const CrudOkReturn();
|
||||
},
|
||||
(error) async => CrudError(error.toString()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user