category repo
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
import '../../domain/category/category.dart';
|
||||
|
||||
part 'category_dtos.freezed.dart';
|
||||
part 'category_dtos.g.dart';
|
||||
|
||||
part 'dtos/category_dto.dart';
|
||||
@@ -0,0 +1,675 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'category_dtos.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
ListCategoryDto _$ListCategoryDtoFromJson(Map<String, dynamic> json) {
|
||||
return _ListCategoryDto.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$ListCategoryDto {
|
||||
@JsonKey(name: "categories")
|
||||
List<CategoryDto>? get categories => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "total_count")
|
||||
int? get totalCount => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "page")
|
||||
int? get page => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "limit")
|
||||
int? get limit => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "total_pages")
|
||||
int? get totalPages => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this ListCategoryDto to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of ListCategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$ListCategoryDtoCopyWith<ListCategoryDto> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ListCategoryDtoCopyWith<$Res> {
|
||||
factory $ListCategoryDtoCopyWith(
|
||||
ListCategoryDto value,
|
||||
$Res Function(ListCategoryDto) then,
|
||||
) = _$ListCategoryDtoCopyWithImpl<$Res, ListCategoryDto>;
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: "categories") List<CategoryDto>? categories,
|
||||
@JsonKey(name: "total_count") int? totalCount,
|
||||
@JsonKey(name: "page") int? page,
|
||||
@JsonKey(name: "limit") int? limit,
|
||||
@JsonKey(name: "total_pages") int? totalPages,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ListCategoryDtoCopyWithImpl<$Res, $Val extends ListCategoryDto>
|
||||
implements $ListCategoryDtoCopyWith<$Res> {
|
||||
_$ListCategoryDtoCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of ListCategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? categories = freezed,
|
||||
Object? totalCount = freezed,
|
||||
Object? page = freezed,
|
||||
Object? limit = freezed,
|
||||
Object? totalPages = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
categories: freezed == categories
|
||||
? _value.categories
|
||||
: categories // ignore: cast_nullable_to_non_nullable
|
||||
as List<CategoryDto>?,
|
||||
totalCount: freezed == totalCount
|
||||
? _value.totalCount
|
||||
: totalCount // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
page: freezed == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
limit: freezed == limit
|
||||
? _value.limit
|
||||
: limit // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
totalPages: freezed == totalPages
|
||||
? _value.totalPages
|
||||
: totalPages // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$ListCategoryDtoImplCopyWith<$Res>
|
||||
implements $ListCategoryDtoCopyWith<$Res> {
|
||||
factory _$$ListCategoryDtoImplCopyWith(
|
||||
_$ListCategoryDtoImpl value,
|
||||
$Res Function(_$ListCategoryDtoImpl) then,
|
||||
) = __$$ListCategoryDtoImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: "categories") List<CategoryDto>? categories,
|
||||
@JsonKey(name: "total_count") int? totalCount,
|
||||
@JsonKey(name: "page") int? page,
|
||||
@JsonKey(name: "limit") int? limit,
|
||||
@JsonKey(name: "total_pages") int? totalPages,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$ListCategoryDtoImplCopyWithImpl<$Res>
|
||||
extends _$ListCategoryDtoCopyWithImpl<$Res, _$ListCategoryDtoImpl>
|
||||
implements _$$ListCategoryDtoImplCopyWith<$Res> {
|
||||
__$$ListCategoryDtoImplCopyWithImpl(
|
||||
_$ListCategoryDtoImpl _value,
|
||||
$Res Function(_$ListCategoryDtoImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of ListCategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? categories = freezed,
|
||||
Object? totalCount = freezed,
|
||||
Object? page = freezed,
|
||||
Object? limit = freezed,
|
||||
Object? totalPages = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$ListCategoryDtoImpl(
|
||||
categories: freezed == categories
|
||||
? _value._categories
|
||||
: categories // ignore: cast_nullable_to_non_nullable
|
||||
as List<CategoryDto>?,
|
||||
totalCount: freezed == totalCount
|
||||
? _value.totalCount
|
||||
: totalCount // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
page: freezed == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
limit: freezed == limit
|
||||
? _value.limit
|
||||
: limit // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
totalPages: freezed == totalPages
|
||||
? _value.totalPages
|
||||
: totalPages // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$ListCategoryDtoImpl extends _ListCategoryDto {
|
||||
const _$ListCategoryDtoImpl({
|
||||
@JsonKey(name: "categories") final List<CategoryDto>? categories,
|
||||
@JsonKey(name: "total_count") this.totalCount,
|
||||
@JsonKey(name: "page") this.page,
|
||||
@JsonKey(name: "limit") this.limit,
|
||||
@JsonKey(name: "total_pages") this.totalPages,
|
||||
}) : _categories = categories,
|
||||
super._();
|
||||
|
||||
factory _$ListCategoryDtoImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$ListCategoryDtoImplFromJson(json);
|
||||
|
||||
final List<CategoryDto>? _categories;
|
||||
@override
|
||||
@JsonKey(name: "categories")
|
||||
List<CategoryDto>? get categories {
|
||||
final value = _categories;
|
||||
if (value == null) return null;
|
||||
if (_categories is EqualUnmodifiableListView) return _categories;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey(name: "total_count")
|
||||
final int? totalCount;
|
||||
@override
|
||||
@JsonKey(name: "page")
|
||||
final int? page;
|
||||
@override
|
||||
@JsonKey(name: "limit")
|
||||
final int? limit;
|
||||
@override
|
||||
@JsonKey(name: "total_pages")
|
||||
final int? totalPages;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ListCategoryDto(categories: $categories, totalCount: $totalCount, page: $page, limit: $limit, totalPages: $totalPages)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$ListCategoryDtoImpl &&
|
||||
const DeepCollectionEquality().equals(
|
||||
other._categories,
|
||||
_categories,
|
||||
) &&
|
||||
(identical(other.totalCount, totalCount) ||
|
||||
other.totalCount == totalCount) &&
|
||||
(identical(other.page, page) || other.page == page) &&
|
||||
(identical(other.limit, limit) || other.limit == limit) &&
|
||||
(identical(other.totalPages, totalPages) ||
|
||||
other.totalPages == totalPages));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_categories),
|
||||
totalCount,
|
||||
page,
|
||||
limit,
|
||||
totalPages,
|
||||
);
|
||||
|
||||
/// Create a copy of ListCategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$ListCategoryDtoImplCopyWith<_$ListCategoryDtoImpl> get copyWith =>
|
||||
__$$ListCategoryDtoImplCopyWithImpl<_$ListCategoryDtoImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$ListCategoryDtoImplToJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _ListCategoryDto extends ListCategoryDto {
|
||||
const factory _ListCategoryDto({
|
||||
@JsonKey(name: "categories") final List<CategoryDto>? categories,
|
||||
@JsonKey(name: "total_count") final int? totalCount,
|
||||
@JsonKey(name: "page") final int? page,
|
||||
@JsonKey(name: "limit") final int? limit,
|
||||
@JsonKey(name: "total_pages") final int? totalPages,
|
||||
}) = _$ListCategoryDtoImpl;
|
||||
const _ListCategoryDto._() : super._();
|
||||
|
||||
factory _ListCategoryDto.fromJson(Map<String, dynamic> json) =
|
||||
_$ListCategoryDtoImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: "categories")
|
||||
List<CategoryDto>? get categories;
|
||||
@override
|
||||
@JsonKey(name: "total_count")
|
||||
int? get totalCount;
|
||||
@override
|
||||
@JsonKey(name: "page")
|
||||
int? get page;
|
||||
@override
|
||||
@JsonKey(name: "limit")
|
||||
int? get limit;
|
||||
@override
|
||||
@JsonKey(name: "total_pages")
|
||||
int? get totalPages;
|
||||
|
||||
/// Create a copy of ListCategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$ListCategoryDtoImplCopyWith<_$ListCategoryDtoImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
CategoryDto _$CategoryDtoFromJson(Map<String, dynamic> json) {
|
||||
return _CategoryDto.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CategoryDto {
|
||||
@JsonKey(name: "id")
|
||||
String? get id => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "organization_id")
|
||||
String? get organizationId => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "name")
|
||||
String? get name => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "description")
|
||||
String? get description => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "business_type")
|
||||
String? get businessType => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "order")
|
||||
int? get order => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "metadata")
|
||||
Map<String, dynamic>? get metadata => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "created_at")
|
||||
String? get createdAt => throw _privateConstructorUsedError;
|
||||
@JsonKey(name: "updated_at")
|
||||
String? get updatedAt => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this CategoryDto to a JSON map.
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of CategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$CategoryDtoCopyWith<CategoryDto> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CategoryDtoCopyWith<$Res> {
|
||||
factory $CategoryDtoCopyWith(
|
||||
CategoryDto value,
|
||||
$Res Function(CategoryDto) then,
|
||||
) = _$CategoryDtoCopyWithImpl<$Res, CategoryDto>;
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: "id") String? id,
|
||||
@JsonKey(name: "organization_id") String? organizationId,
|
||||
@JsonKey(name: "name") String? name,
|
||||
@JsonKey(name: "description") String? description,
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "order") int? order,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CategoryDtoCopyWithImpl<$Res, $Val extends CategoryDto>
|
||||
implements $CategoryDtoCopyWith<$Res> {
|
||||
_$CategoryDtoCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? organizationId = freezed,
|
||||
Object? name = freezed,
|
||||
Object? description = freezed,
|
||||
Object? businessType = freezed,
|
||||
Object? order = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
organizationId: freezed == organizationId
|
||||
? _value.organizationId
|
||||
: organizationId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
name: freezed == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
businessType: freezed == businessType
|
||||
? _value.businessType
|
||||
: businessType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
order: freezed == order
|
||||
? _value.order
|
||||
: order // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
metadata: freezed == metadata
|
||||
? _value.metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
createdAt: freezed == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
updatedAt: freezed == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CategoryDtoImplCopyWith<$Res>
|
||||
implements $CategoryDtoCopyWith<$Res> {
|
||||
factory _$$CategoryDtoImplCopyWith(
|
||||
_$CategoryDtoImpl value,
|
||||
$Res Function(_$CategoryDtoImpl) then,
|
||||
) = __$$CategoryDtoImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
@JsonKey(name: "id") String? id,
|
||||
@JsonKey(name: "organization_id") String? organizationId,
|
||||
@JsonKey(name: "name") String? name,
|
||||
@JsonKey(name: "description") String? description,
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "order") int? order,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CategoryDtoImplCopyWithImpl<$Res>
|
||||
extends _$CategoryDtoCopyWithImpl<$Res, _$CategoryDtoImpl>
|
||||
implements _$$CategoryDtoImplCopyWith<$Res> {
|
||||
__$$CategoryDtoImplCopyWithImpl(
|
||||
_$CategoryDtoImpl _value,
|
||||
$Res Function(_$CategoryDtoImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of CategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? id = freezed,
|
||||
Object? organizationId = freezed,
|
||||
Object? name = freezed,
|
||||
Object? description = freezed,
|
||||
Object? businessType = freezed,
|
||||
Object? order = freezed,
|
||||
Object? metadata = freezed,
|
||||
Object? createdAt = freezed,
|
||||
Object? updatedAt = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$CategoryDtoImpl(
|
||||
id: freezed == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
organizationId: freezed == organizationId
|
||||
? _value.organizationId
|
||||
: organizationId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
name: freezed == name
|
||||
? _value.name
|
||||
: name // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
description: freezed == description
|
||||
? _value.description
|
||||
: description // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
businessType: freezed == businessType
|
||||
? _value.businessType
|
||||
: businessType // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
order: freezed == order
|
||||
? _value.order
|
||||
: order // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
metadata: freezed == metadata
|
||||
? _value._metadata
|
||||
: metadata // ignore: cast_nullable_to_non_nullable
|
||||
as Map<String, dynamic>?,
|
||||
createdAt: freezed == createdAt
|
||||
? _value.createdAt
|
||||
: createdAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
updatedAt: freezed == updatedAt
|
||||
? _value.updatedAt
|
||||
: updatedAt // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$CategoryDtoImpl extends _CategoryDto {
|
||||
const _$CategoryDtoImpl({
|
||||
@JsonKey(name: "id") this.id,
|
||||
@JsonKey(name: "organization_id") this.organizationId,
|
||||
@JsonKey(name: "name") this.name,
|
||||
@JsonKey(name: "description") this.description,
|
||||
@JsonKey(name: "business_type") this.businessType,
|
||||
@JsonKey(name: "order") this.order,
|
||||
@JsonKey(name: "metadata") final Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "created_at") this.createdAt,
|
||||
@JsonKey(name: "updated_at") this.updatedAt,
|
||||
}) : _metadata = metadata,
|
||||
super._();
|
||||
|
||||
factory _$CategoryDtoImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$CategoryDtoImplFromJson(json);
|
||||
|
||||
@override
|
||||
@JsonKey(name: "id")
|
||||
final String? id;
|
||||
@override
|
||||
@JsonKey(name: "organization_id")
|
||||
final String? organizationId;
|
||||
@override
|
||||
@JsonKey(name: "name")
|
||||
final String? name;
|
||||
@override
|
||||
@JsonKey(name: "description")
|
||||
final String? description;
|
||||
@override
|
||||
@JsonKey(name: "business_type")
|
||||
final String? businessType;
|
||||
@override
|
||||
@JsonKey(name: "order")
|
||||
final int? order;
|
||||
final Map<String, dynamic>? _metadata;
|
||||
@override
|
||||
@JsonKey(name: "metadata")
|
||||
Map<String, dynamic>? get metadata {
|
||||
final value = _metadata;
|
||||
if (value == null) return null;
|
||||
if (_metadata is EqualUnmodifiableMapView) return _metadata;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableMapView(value);
|
||||
}
|
||||
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
final String? createdAt;
|
||||
@override
|
||||
@JsonKey(name: "updated_at")
|
||||
final String? updatedAt;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CategoryDto(id: $id, organizationId: $organizationId, name: $name, description: $description, businessType: $businessType, order: $order, metadata: $metadata, createdAt: $createdAt, updatedAt: $updatedAt)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$CategoryDtoImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.organizationId, organizationId) ||
|
||||
other.organizationId == organizationId) &&
|
||||
(identical(other.name, name) || other.name == name) &&
|
||||
(identical(other.description, description) ||
|
||||
other.description == description) &&
|
||||
(identical(other.businessType, businessType) ||
|
||||
other.businessType == businessType) &&
|
||||
(identical(other.order, order) || other.order == order) &&
|
||||
const DeepCollectionEquality().equals(other._metadata, _metadata) &&
|
||||
(identical(other.createdAt, createdAt) ||
|
||||
other.createdAt == createdAt) &&
|
||||
(identical(other.updatedAt, updatedAt) ||
|
||||
other.updatedAt == updatedAt));
|
||||
}
|
||||
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
id,
|
||||
organizationId,
|
||||
name,
|
||||
description,
|
||||
businessType,
|
||||
order,
|
||||
const DeepCollectionEquality().hash(_metadata),
|
||||
createdAt,
|
||||
updatedAt,
|
||||
);
|
||||
|
||||
/// Create a copy of CategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CategoryDtoImplCopyWith<_$CategoryDtoImpl> get copyWith =>
|
||||
__$$CategoryDtoImplCopyWithImpl<_$CategoryDtoImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$CategoryDtoImplToJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _CategoryDto extends CategoryDto {
|
||||
const factory _CategoryDto({
|
||||
@JsonKey(name: "id") final String? id,
|
||||
@JsonKey(name: "organization_id") final String? organizationId,
|
||||
@JsonKey(name: "name") final String? name,
|
||||
@JsonKey(name: "description") final String? description,
|
||||
@JsonKey(name: "business_type") final String? businessType,
|
||||
@JsonKey(name: "order") final int? order,
|
||||
@JsonKey(name: "metadata") final Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "created_at") final String? createdAt,
|
||||
@JsonKey(name: "updated_at") final String? updatedAt,
|
||||
}) = _$CategoryDtoImpl;
|
||||
const _CategoryDto._() : super._();
|
||||
|
||||
factory _CategoryDto.fromJson(Map<String, dynamic> json) =
|
||||
_$CategoryDtoImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: "id")
|
||||
String? get id;
|
||||
@override
|
||||
@JsonKey(name: "organization_id")
|
||||
String? get organizationId;
|
||||
@override
|
||||
@JsonKey(name: "name")
|
||||
String? get name;
|
||||
@override
|
||||
@JsonKey(name: "description")
|
||||
String? get description;
|
||||
@override
|
||||
@JsonKey(name: "business_type")
|
||||
String? get businessType;
|
||||
@override
|
||||
@JsonKey(name: "order")
|
||||
int? get order;
|
||||
@override
|
||||
@JsonKey(name: "metadata")
|
||||
Map<String, dynamic>? get metadata;
|
||||
@override
|
||||
@JsonKey(name: "created_at")
|
||||
String? get createdAt;
|
||||
@override
|
||||
@JsonKey(name: "updated_at")
|
||||
String? get updatedAt;
|
||||
|
||||
/// Create a copy of CategoryDto
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CategoryDtoImplCopyWith<_$CategoryDtoImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'category_dtos.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$ListCategoryDtoImpl _$$ListCategoryDtoImplFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) => _$ListCategoryDtoImpl(
|
||||
categories: (json['categories'] as List<dynamic>?)
|
||||
?.map((e) => CategoryDto.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
totalCount: (json['total_count'] as num?)?.toInt(),
|
||||
page: (json['page'] as num?)?.toInt(),
|
||||
limit: (json['limit'] as num?)?.toInt(),
|
||||
totalPages: (json['total_pages'] as num?)?.toInt(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$ListCategoryDtoImplToJson(
|
||||
_$ListCategoryDtoImpl instance,
|
||||
) => <String, dynamic>{
|
||||
'categories': instance.categories,
|
||||
'total_count': instance.totalCount,
|
||||
'page': instance.page,
|
||||
'limit': instance.limit,
|
||||
'total_pages': instance.totalPages,
|
||||
};
|
||||
|
||||
_$CategoryDtoImpl _$$CategoryDtoImplFromJson(Map<String, dynamic> json) =>
|
||||
_$CategoryDtoImpl(
|
||||
id: json['id'] as String?,
|
||||
organizationId: json['organization_id'] as String?,
|
||||
name: json['name'] as String?,
|
||||
description: json['description'] as String?,
|
||||
businessType: json['business_type'] as String?,
|
||||
order: (json['order'] as num?)?.toInt(),
|
||||
metadata: json['metadata'] as Map<String, dynamic>?,
|
||||
createdAt: json['created_at'] as String?,
|
||||
updatedAt: json['updated_at'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$CategoryDtoImplToJson(_$CategoryDtoImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'organization_id': instance.organizationId,
|
||||
'name': instance.name,
|
||||
'description': instance.description,
|
||||
'business_type': instance.businessType,
|
||||
'order': instance.order,
|
||||
'metadata': instance.metadata,
|
||||
'created_at': instance.createdAt,
|
||||
'updated_at': instance.updatedAt,
|
||||
};
|
||||
@@ -0,0 +1,349 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:data_channel/data_channel.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:sqflite/sqflite.dart';
|
||||
|
||||
import '../../../common/constant/app_constant.dart';
|
||||
import '../../../common/database/database_helper.dart';
|
||||
import '../../../domain/category/category.dart';
|
||||
import '../category_dtos.dart';
|
||||
|
||||
@injectable
|
||||
class CategoryLocalDataProvider {
|
||||
final DatabaseHelper _databaseHelper;
|
||||
final _logName = 'CategoryLocalDataProvider';
|
||||
|
||||
CategoryLocalDataProvider(this._databaseHelper);
|
||||
|
||||
final Map<String, List<CategoryDto>> _queryCache = {};
|
||||
final Duration _cacheExpiry = Duration(minutes: AppConstant.cacheExpire);
|
||||
final Map<String, DateTime> _cacheTimestamps = {};
|
||||
|
||||
Future<DC<CategoryFailure, void>> saveCategoriesBatch(
|
||||
List<CategoryDto> categories, {
|
||||
bool clearFirst = false,
|
||||
}) async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
await db.transaction((txn) async {
|
||||
if (clearFirst) {
|
||||
log('🗑️ Clearing existing categories...', name: _logName);
|
||||
await txn.delete('categories');
|
||||
}
|
||||
|
||||
log(
|
||||
'💾 Batch saving ${categories.length} categories...',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
// Batch insert categories
|
||||
final batch = txn.batch();
|
||||
for (final category in categories) {
|
||||
batch.insert(
|
||||
'categories',
|
||||
category.toMap(),
|
||||
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||
);
|
||||
}
|
||||
await batch.commit(noResult: true);
|
||||
});
|
||||
|
||||
// Clear cache after update
|
||||
clearCache();
|
||||
log(
|
||||
'✅ Successfully batch saved ${categories.length} categories',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
return DC.data(null);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error batch saving categories',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return DC.error(CategoryFailure.dynamicErrorMessage(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<CategoryFailure, List<CategoryDto>>> getCachedCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
String? search,
|
||||
}) async {
|
||||
final cacheKey = _generateCacheKey(page, limit, isActive, search);
|
||||
final now = DateTime.now();
|
||||
|
||||
try {
|
||||
// Check cache first
|
||||
if (_queryCache.containsKey(cacheKey) &&
|
||||
_cacheTimestamps.containsKey(cacheKey)) {
|
||||
final cacheTime = _cacheTimestamps[cacheKey]!;
|
||||
if (now.difference(cacheTime) < _cacheExpiry) {
|
||||
log(
|
||||
'🚀 Cache HIT: $cacheKey (${_queryCache[cacheKey]!.length} categories)',
|
||||
name: _logName,
|
||||
);
|
||||
return DC.data(_queryCache[cacheKey]!);
|
||||
}
|
||||
}
|
||||
|
||||
log('📀 Cache MISS: $cacheKey, querying database...', name: _logName);
|
||||
|
||||
// Cache miss, query database
|
||||
final result = await getCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
);
|
||||
|
||||
// Check if result has data or error
|
||||
if (result.hasData) {
|
||||
final categories = result.data!;
|
||||
|
||||
// Store in cache
|
||||
_queryCache[cacheKey] = categories;
|
||||
_cacheTimestamps[cacheKey] = now;
|
||||
|
||||
log(
|
||||
'💾 Cached ${categories.length} categories for key: $cacheKey',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
return DC.data(categories);
|
||||
} else {
|
||||
// Return error from database query
|
||||
return DC.error(result.error!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting cached categories',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return DC.error(CategoryFailure.localStorageError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<CategoryFailure, List<CategoryDto>>> getCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
String? search,
|
||||
}) async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
String query = 'SELECT * FROM categories WHERE 1=1';
|
||||
List<dynamic> whereArgs = [];
|
||||
|
||||
// Note: Assuming is_active will be added to database schema
|
||||
if (isActive) {
|
||||
query += ' AND is_active = ?';
|
||||
whereArgs.add(1);
|
||||
}
|
||||
|
||||
if (search != null && search.isNotEmpty) {
|
||||
query += ' AND (name LIKE ? OR description LIKE ?)';
|
||||
whereArgs.add('%$search%');
|
||||
whereArgs.add('%$search%');
|
||||
}
|
||||
|
||||
// query += ' ORDER BY name ASC';
|
||||
|
||||
if (limit > 0) {
|
||||
query += ' LIMIT ?';
|
||||
whereArgs.add(limit);
|
||||
|
||||
if (page > 1) {
|
||||
query += ' OFFSET ?';
|
||||
whereArgs.add((page - 1) * limit);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Map<String, dynamic>> maps = await db.rawQuery(
|
||||
query,
|
||||
whereArgs,
|
||||
);
|
||||
|
||||
final categories = maps.map((map) => CategoryDto.fromMap(map)).toList();
|
||||
|
||||
log(
|
||||
'📊 Retrieved ${categories.length} categories from database',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
return DC.data(categories);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting categories',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return DC.error(CategoryFailure.localStorageError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<DC<CategoryFailure, CategoryDto>> getCategoryById(String id) async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
final List<Map<String, dynamic>> maps = await db.query(
|
||||
'categories',
|
||||
where: 'id = ?',
|
||||
whereArgs: [id],
|
||||
);
|
||||
|
||||
if (maps.isEmpty) {
|
||||
log('❌ Category not found: $id', name: _logName);
|
||||
return DC.error(CategoryFailure.empty());
|
||||
}
|
||||
|
||||
final category = CategoryDto.fromMap(maps.first);
|
||||
log('✅ Category found: ${category.name}', name: _logName);
|
||||
return DC.data(category);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting category by ID',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return DC.error(CategoryFailure.localStorageError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> getTotalCount({bool isActive = true, String? search}) async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
String query = 'SELECT COUNT(*) FROM categories WHERE 1=1';
|
||||
List<dynamic> whereArgs = [];
|
||||
|
||||
if (isActive) {
|
||||
query += ' AND is_active = ?';
|
||||
whereArgs.add(1);
|
||||
}
|
||||
|
||||
if (search != null && search.isNotEmpty) {
|
||||
query += ' AND (name LIKE ? OR description LIKE ?)';
|
||||
whereArgs.add('%$search%');
|
||||
whereArgs.add('%$search%');
|
||||
}
|
||||
|
||||
final result = await db.rawQuery(query, whereArgs);
|
||||
final count = Sqflite.firstIntValue(result) ?? 0;
|
||||
log(
|
||||
'📊 Category total count: $count (isActive: $isActive, search: $search)',
|
||||
name: _logName,
|
||||
);
|
||||
return count;
|
||||
} catch (e) {
|
||||
log('❌ Error getting category total count: $e', name: _logName);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> hasCategories() async {
|
||||
final count = await getTotalCount();
|
||||
final hasData = count > 0;
|
||||
log('🔍 Has categories: $hasData ($count categories)', name: _logName);
|
||||
return hasData;
|
||||
}
|
||||
|
||||
Future<DC<CategoryFailure, Map<String, dynamic>>> getDatabaseStats() async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
final categoryCount =
|
||||
Sqflite.firstIntValue(
|
||||
await db.rawQuery('SELECT COUNT(*) FROM categories'),
|
||||
) ??
|
||||
0;
|
||||
|
||||
final activeCount =
|
||||
Sqflite.firstIntValue(
|
||||
await db.rawQuery(
|
||||
'SELECT COUNT(*) FROM categories WHERE is_active = 1',
|
||||
),
|
||||
) ??
|
||||
0;
|
||||
|
||||
final stats = {
|
||||
'total_categories': categoryCount,
|
||||
'active_categories': activeCount,
|
||||
'cache_entries': _queryCache.length,
|
||||
'last_updated': DateTime.now().toIso8601String(),
|
||||
};
|
||||
|
||||
log('📊 Category Database Stats: $stats', name: _logName);
|
||||
return DC.data(stats);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting category database stats',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return DC.error(
|
||||
CategoryFailure.localStorageError(
|
||||
'Gagal memuat statistik database: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> clearAllCategories() async {
|
||||
final db = await _databaseHelper.database;
|
||||
|
||||
try {
|
||||
await db.delete('categories');
|
||||
clearCache();
|
||||
log('🗑️ All categories cleared from local DB');
|
||||
} catch (e) {
|
||||
log('❌ Error clearing categories: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
void clearCache() {
|
||||
final count = _queryCache.length;
|
||||
_queryCache.clear();
|
||||
_cacheTimestamps.clear();
|
||||
log('🧹 Category cache cleared: $count entries removed', name: _logName);
|
||||
}
|
||||
|
||||
String _generateCacheKey(int page, int limit, bool isActive, String? search) {
|
||||
return 'categories_${page}_${limit}_${isActive}_${search ?? 'null'}';
|
||||
}
|
||||
|
||||
void clearExpiredCache() {
|
||||
final now = DateTime.now();
|
||||
final expiredKeys = <String>[];
|
||||
|
||||
_cacheTimestamps.forEach((key, timestamp) {
|
||||
if (now.difference(timestamp) > _cacheExpiry) {
|
||||
expiredKeys.add(key);
|
||||
}
|
||||
});
|
||||
|
||||
for (final key in expiredKeys) {
|
||||
_queryCache.remove(key);
|
||||
_cacheTimestamps.remove(key);
|
||||
}
|
||||
|
||||
if (expiredKeys.isNotEmpty) {
|
||||
log(
|
||||
'⏰ Expired category cache cleared: ${expiredKeys.length} entries',
|
||||
name: _logName,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:data_channel/data_channel.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../common/api/api_client.dart';
|
||||
import '../../../common/api/api_failure.dart';
|
||||
import '../../../common/function/app_function.dart';
|
||||
import '../../../common/url/api_path.dart';
|
||||
import '../../../domain/category/category.dart';
|
||||
import '../category_dtos.dart';
|
||||
|
||||
@injectable
|
||||
class CategoryRemoteDataProvider {
|
||||
final ApiClient _apiClient;
|
||||
final _logName = 'CategoryRemoteDataProvider';
|
||||
|
||||
CategoryRemoteDataProvider(this._apiClient);
|
||||
|
||||
Future<DC<CategoryFailure, ListCategoryDto>> fetchCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
ApiPath.categories,
|
||||
params: {'page': page, 'limit': limit},
|
||||
headers: getAuthorizationHeader(),
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(CategoryFailure.empty());
|
||||
}
|
||||
|
||||
final categories = ListCategoryDto.fromJson(
|
||||
response.data['data'] as Map<String, dynamic>,
|
||||
);
|
||||
|
||||
return DC.data(categories);
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('fetchCategoryError', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(CategoryFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
part of '../category_dtos.dart';
|
||||
|
||||
@freezed
|
||||
class ListCategoryDto with _$ListCategoryDto {
|
||||
const ListCategoryDto._();
|
||||
|
||||
const factory ListCategoryDto({
|
||||
@JsonKey(name: "categories") List<CategoryDto>? categories,
|
||||
@JsonKey(name: "total_count") int? totalCount,
|
||||
@JsonKey(name: "page") int? page,
|
||||
@JsonKey(name: "limit") int? limit,
|
||||
@JsonKey(name: "total_pages") int? totalPages,
|
||||
}) = _ListCategoryDto;
|
||||
|
||||
factory ListCategoryDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$ListCategoryDtoFromJson(json);
|
||||
|
||||
ListCategory toDomain() => ListCategory(
|
||||
categories: categories?.map((dto) => dto.toDomain()).toList() ?? [],
|
||||
totalCount: totalCount ?? 0,
|
||||
page: page ?? 0,
|
||||
limit: limit ?? 0,
|
||||
totalPages: totalPages ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class CategoryDto with _$CategoryDto {
|
||||
const CategoryDto._();
|
||||
|
||||
const factory CategoryDto({
|
||||
@JsonKey(name: "id") String? id,
|
||||
@JsonKey(name: "organization_id") String? organizationId,
|
||||
@JsonKey(name: "name") String? name,
|
||||
@JsonKey(name: "description") String? description,
|
||||
@JsonKey(name: "business_type") String? businessType,
|
||||
@JsonKey(name: "order") int? order,
|
||||
@JsonKey(name: "metadata") Map<String, dynamic>? metadata,
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
}) = _CategoryDto;
|
||||
|
||||
factory CategoryDto.fromJson(Map<String, dynamic> json) =>
|
||||
_$CategoryDtoFromJson(json);
|
||||
|
||||
/// Mapping ke domain
|
||||
Category toDomain() => Category(
|
||||
id: id ?? '',
|
||||
organizationId: organizationId ?? '',
|
||||
name: name ?? '',
|
||||
description: description ?? '',
|
||||
businessType: businessType ?? '',
|
||||
order: order ?? 0,
|
||||
metadata: metadata ?? {},
|
||||
createdAt: createdAt ?? '',
|
||||
updatedAt: updatedAt ?? '',
|
||||
);
|
||||
|
||||
/// Mapping ke Map untuk SQLite
|
||||
Map<String, dynamic> toMap() => {
|
||||
'id': id,
|
||||
'organization_id': organizationId,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'business_type': businessType,
|
||||
'order': order,
|
||||
'metadata': metadata != null ? jsonEncode(metadata) : null,
|
||||
'created_at': createdAt,
|
||||
'updated_at': updatedAt,
|
||||
};
|
||||
|
||||
/// Mapping dari Map SQLite
|
||||
factory CategoryDto.fromMap(Map<String, dynamic> map) => CategoryDto(
|
||||
id: map['id'] as String?,
|
||||
organizationId: map['organization_id'] as String?,
|
||||
name: map['name'] as String?,
|
||||
description: map['description'] as String?,
|
||||
businessType: map['business_type'] as String?,
|
||||
order: map['order'] as int?,
|
||||
metadata: map['metadata'] != null
|
||||
? jsonDecode(map['metadata'] as String) as Map<String, dynamic>
|
||||
: null,
|
||||
createdAt: map['created_at'] as String?,
|
||||
updatedAt: map['updated_at'] as String?,
|
||||
);
|
||||
|
||||
factory CategoryDto.fromDomain(Category category) => CategoryDto(
|
||||
id: category.id,
|
||||
organizationId: category.organizationId,
|
||||
name: category.name,
|
||||
description: category.description,
|
||||
businessType: category.businessType,
|
||||
order: category.order,
|
||||
metadata: category.metadata,
|
||||
createdAt: category.createdAt,
|
||||
updatedAt: category.updatedAt,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/category/category.dart';
|
||||
import '../category_dtos.dart';
|
||||
import '../datasources/local_data_provider.dart';
|
||||
import '../datasources/remote_data_provider.dart';
|
||||
|
||||
@Injectable(as: ICategoryRepository)
|
||||
class CategoryRepository implements ICategoryRepository {
|
||||
final CategoryRemoteDataProvider _remoteDataProvider;
|
||||
final CategoryLocalDataProvider _localDataProvider;
|
||||
|
||||
final _logName = 'CategoryRepository';
|
||||
|
||||
CategoryRepository(this._remoteDataProvider, this._localDataProvider);
|
||||
|
||||
@override
|
||||
Future<Either<CategoryFailure, ListCategory>> getCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
String? search,
|
||||
bool forceRemote = false,
|
||||
}) async {
|
||||
try {
|
||||
log(
|
||||
'📱 Getting categories - page: $page, isActive: $isActive, search: $search, forceRemote: $forceRemote',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
// Clean expired cache
|
||||
_localDataProvider.clearExpiredCache();
|
||||
|
||||
// Check if we should try remote first
|
||||
if (forceRemote || !await _localDataProvider.hasCategories()) {
|
||||
log('🌐 Attempting remote fetch first...', name: _logName);
|
||||
|
||||
final remoteResult = await _getRemoteCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
isActive: isActive,
|
||||
);
|
||||
|
||||
return await remoteResult.fold(
|
||||
(failure) async {
|
||||
log('❌ Remote fetch failed: $failure', name: _logName);
|
||||
log('📱 Falling back to local data...', name: _logName);
|
||||
return await _getLocalCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
);
|
||||
},
|
||||
(data) async {
|
||||
log(
|
||||
'✅ Remote fetch successful, syncing to local...',
|
||||
name: _logName,
|
||||
);
|
||||
|
||||
// Sync remote data to local
|
||||
if (data.categories.isNotEmpty) {
|
||||
await _syncToLocal(data.categories, clearFirst: page == 1);
|
||||
}
|
||||
|
||||
return Right(data);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
log('📱 Using local data (cache available)...', name: _logName);
|
||||
return await _getLocalCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log('❌ Error in getCategories', name: _logName, error: e, stackTrace: s);
|
||||
return Left(
|
||||
CategoryFailure.dynamicErrorMessage('Gagal memuat kategori: $e'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<CategoryFailure, Category>> getCategoryById(String id) async {
|
||||
try {
|
||||
log('🔍 Getting category by ID: $id', name: _logName);
|
||||
|
||||
final result = await _localDataProvider.getCategoryById(id);
|
||||
|
||||
if (result.hasData) {
|
||||
final category = result.data!.toDomain();
|
||||
log('✅ Category found: ${category.name}', name: _logName);
|
||||
return Right(category);
|
||||
} else {
|
||||
log('❌ Category not found or error: ${result.error}', name: _logName);
|
||||
return Left(result.error!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting category by ID',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return Left(
|
||||
CategoryFailure.localStorageError('Gagal memuat kategori: $e'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<CategoryFailure, Map<String, dynamic>>>
|
||||
getDatabaseStats() async {
|
||||
try {
|
||||
log('📊 Getting database stats...', name: _logName);
|
||||
|
||||
final result = await _localDataProvider.getDatabaseStats();
|
||||
|
||||
if (result.hasData) {
|
||||
final stats = result.data!;
|
||||
log('📊 Category database stats: $stats', name: _logName);
|
||||
return Right(stats);
|
||||
} else {
|
||||
log('❌ Error getting stats: ${result.error}', name: _logName);
|
||||
return Left(result.error!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting database stats',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return Left(
|
||||
CategoryFailure.localStorageError(
|
||||
'Gagal memuat statistik database: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> hasLocalCategories() async {
|
||||
final hasCategories = await _localDataProvider.hasCategories();
|
||||
log('📊 Has local categories: $hasCategories', name: _logName);
|
||||
return hasCategories;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<CategoryFailure, ListCategory>> refreshCategories({
|
||||
bool isActive = true,
|
||||
String? search,
|
||||
}) async {
|
||||
try {
|
||||
log('🔄 Refreshing categories...', name: _logName);
|
||||
|
||||
// Clear cache before refresh
|
||||
_localDataProvider.clearCache();
|
||||
|
||||
return await getCategories(
|
||||
page: 1,
|
||||
limit: 10,
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
forceRemote: true, // Force remote refresh
|
||||
);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error refreshing categories',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return Left(
|
||||
CategoryFailure.localStorageError('Gagal memperbarui kategori: $e'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<CategoryFailure, String>> syncAllCategories() async {
|
||||
try {
|
||||
log('🔄 Starting manual sync of all categories...', name: _logName);
|
||||
|
||||
int page = 1;
|
||||
const limit = 50; // Higher limit for bulk sync
|
||||
bool hasMore = true;
|
||||
int totalSynced = 0;
|
||||
|
||||
// Clear local data first for fresh sync
|
||||
await _localDataProvider.clearAllCategories();
|
||||
|
||||
while (hasMore) {
|
||||
log('📄 Syncing page $page...');
|
||||
|
||||
final result = await _remoteDataProvider.fetchCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
// isActive: true,
|
||||
);
|
||||
|
||||
// If fetchCategories returns DC directly, handle it directly
|
||||
final data = result.data!.toDomain();
|
||||
|
||||
if (data.categories.isNotEmpty) {
|
||||
await _localDataProvider.saveCategoriesBatch(
|
||||
data.categories
|
||||
.map((category) => CategoryDto.fromDomain(category))
|
||||
.toList(),
|
||||
clearFirst: false, // Don't clear on subsequent pages
|
||||
);
|
||||
totalSynced += data.categories.length;
|
||||
|
||||
// Check if we have more pages
|
||||
hasMore = page < data.totalPages;
|
||||
page++;
|
||||
|
||||
log(
|
||||
'📦 Page ${page - 1} synced: ${data.categories.length} categories',
|
||||
);
|
||||
} else {
|
||||
hasMore = false;
|
||||
}
|
||||
}
|
||||
|
||||
final message = 'Berhasil sinkronisasi $totalSynced kategori';
|
||||
log('✅ $message');
|
||||
return Right(message);
|
||||
} catch (e) {
|
||||
final error = 'Gagal sinkronisasi kategori: $e';
|
||||
log('❌ $error');
|
||||
return Left(CategoryFailure.localStorageError(error));
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<CategoryFailure, ListCategory>> _getRemoteCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
}) async {
|
||||
try {
|
||||
log('🌐 Fetching categories from remote...', name: _logName);
|
||||
|
||||
final result = await _remoteDataProvider.fetchCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
);
|
||||
|
||||
// Convert DC to Either and DTO to Domain
|
||||
if (result.hasData) {
|
||||
final categories = result.data!.toDomain();
|
||||
return Right(categories);
|
||||
} else {
|
||||
return Left(result.error!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log('❌ Remote fetch error', name: _logName, error: e, stackTrace: s);
|
||||
return Left(
|
||||
CategoryFailure.dynamicErrorMessage(
|
||||
'Gagal mengambil data dari server: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Either<CategoryFailure, ListCategory>> _getLocalCategories({
|
||||
int page = 1,
|
||||
int limit = 10,
|
||||
bool isActive = true,
|
||||
String? search,
|
||||
}) async {
|
||||
try {
|
||||
log('💾 Fetching categories from local...', name: _logName);
|
||||
|
||||
final result = await _localDataProvider.getCachedCategories(
|
||||
page: page,
|
||||
limit: limit,
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
);
|
||||
|
||||
final totalCount = await _localDataProvider.getTotalCount(
|
||||
isActive: isActive,
|
||||
search: search,
|
||||
);
|
||||
|
||||
// Convert DC to Either and DTO to Domain
|
||||
if (result.hasData) {
|
||||
final categories = result.data!.map((dto) => dto.toDomain()).toList();
|
||||
final categoryData = ListCategory(
|
||||
categories: categories,
|
||||
totalCount: totalCount,
|
||||
page: page,
|
||||
limit: limit,
|
||||
totalPages: totalCount > 0 ? (totalCount / limit).ceil() : 0,
|
||||
);
|
||||
log('✅ Returned ${categories.length} local categories', name: _logName);
|
||||
return Right(categoryData);
|
||||
} else {
|
||||
log(
|
||||
'❌ Error getting local categories: ${result.error}',
|
||||
name: _logName,
|
||||
);
|
||||
return Left(result.error!);
|
||||
}
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Error getting local categories',
|
||||
name: _logName,
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
return Left(
|
||||
CategoryFailure.localStorageError(
|
||||
'Gagal memuat kategori dari database lokal: $e',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _syncToLocal(
|
||||
List<Category> categories, {
|
||||
bool clearFirst = false,
|
||||
}) async {
|
||||
try {
|
||||
log(
|
||||
'💾 Syncing ${categories.length} categories to local database...',
|
||||
name: _logName,
|
||||
);
|
||||
await _localDataProvider.saveCategoriesBatch(
|
||||
categories.map((category) => CategoryDto.fromDomain(category)).toList(),
|
||||
clearFirst: clearFirst,
|
||||
);
|
||||
log('✅ Categories synced to local successfully', name: _logName);
|
||||
} catch (e) {
|
||||
log('❌ Error syncing categories to local: $e', name: _logName);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void clearCache() {
|
||||
log('🧹 Clearing category cache', name: _logName);
|
||||
_localDataProvider.clearCache();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user