Skip to content

Commit

Permalink
feat: Added ModelImageUri and ModelVideoUri.
Browse files Browse the repository at this point in the history
  • Loading branch information
mathrunet committed Jul 4, 2023
1 parent 9ba4b69 commit 3d9456e
Show file tree
Hide file tree
Showing 14 changed files with 1,464 additions and 306 deletions.
1 change: 1 addition & 0 deletions packages/katana_model/lib/katana_model.dart
Expand Up @@ -34,6 +34,7 @@ part 'src/document_base.dart';
part 'src/model_adapter.dart';
part 'src/no_sql_database.dart';
part 'src/model_ref.dart';
part 'src/model_uri.dart';
part 'src/model_query.dart';
part 'src/collection_base.dart';
part 'src/listenable_listener.dart';
Expand Down
248 changes: 4 additions & 244 deletions packages/katana_model/lib/src/model_field_value.dart
Expand Up @@ -129,6 +129,8 @@ abstract class ModelFieldValue<T> {
const ModelTimestampConverter(),
const ModelGeoValueConverter(),
const ModelUriConverter(),
const ModelImageUriConverter(),
const ModelVideoUriConverter(),
const ModelSearchConverter(),
const ModelRefConverter(),
};
Expand All @@ -152,6 +154,8 @@ abstract class ModelFieldValue<T> {
const ModelTimestampFilter(),
const ModelGeoValueFilter(),
const ModelUriFilter(),
const ModelImageUriFilter(),
const ModelVideoUriFilter(),
const ModelSearchFilter(),
const ModelRefFilter(),
};
Expand Down Expand Up @@ -991,250 +995,6 @@ class ModelTimestampFilter extends ModelFieldValueFilter<ModelTimestamp> {
}
}

/// Define the field as a URI.
///
/// The base value is given as [value]. An empty [Uri] is defined.
///
/// Use [ModelUri] if you want to be sure to define it as a URI.
///
/// フィールドをURIとして定義します。
///
/// ベースの値を[value]として与えます。空の[Uri]が定義されます。
///
/// 必ずURIとしての定義を行いたい場合は[ModelUri]を利用してください。
@immutable
class ModelUri extends ModelFieldValue<Uri> {
/// Define the field as a URI.
///
/// The base value is given as [value]. An empty [Uri] is defined.
///
/// Use [ModelUri] if you want to be sure to define it as a URI.
///
/// フィールドをURIとして定義します。
///
/// ベースの値を[value]として与えます。空の[Uri]が定義されます。
///
/// 必ずURIとしての定義を行いたい場合は[ModelUri]を利用してください。
const factory ModelUri([Uri? value]) = _ModelUri;

/// Define the field as a URI.
///
/// The base value is given as [value]. An empty [Uri] is defined.
///
/// Use [ModelUri] if you want to be sure to define it as a URI.
///
/// フィールドをURIとして定義します。
///
/// ベースの値を[value]として与えます。空の[Uri]が定義されます。
///
/// 必ずURIとしての定義を行いたい場合は[ModelUri]を利用してください。
factory ModelUri.parse([String? value]) {
return ModelUri(value == null ? null : Uri.parse(value));
}

/// Used to disguise the retrieval of data from the server.
///
/// Use for testing purposes.
///
/// サーバーからのデータの取得に偽装するために利用します。
///
/// テスト用途で用いてください。
const factory ModelUri.fromServer([Uri? value]) = _ModelUri.fromServer;

/// Convert from [json] map to [ModelUri].
///
/// [json]のマップから[ModelUri]に変換します。
factory ModelUri.fromJson(DynamicMap json) {
final uri = json.get(kUriKey, "");
return ModelUri.fromServer(
Uri.tryParse(uri),
);
}

const ModelUri._([
Uri? value,
ModelFieldValueSource source = ModelFieldValueSource.user,
]) : _value = value,
_source = source;

/// Key to save time.
///
/// 時間を保存しておくキー。
static const kUriKey = "@uri";

/// Key to store the data source.
///
/// データソースを保存しておくキー。
static const kSourceKey = "@source";

@override
Uri get value => _value ?? Uri();
final Uri? _value;

final ModelFieldValueSource _source;

@override
String toString() {
return value.toString();
}

@override
DynamicMap toJson() => {
kTypeFieldKey: (ModelUri).toString(),
kUriKey: value.toString(),
kSourceKey: _source.name,
};

@override
bool operator ==(Object other) => hashCode == other.hashCode;

@override
int get hashCode => _value.hashCode;
}

@immutable
class _ModelUri extends ModelUri with ModelFieldValueAsMapMixin<Uri> {
const _ModelUri([
Uri? value,
ModelFieldValueSource source = ModelFieldValueSource.user,
]) : super._(value, source);
const _ModelUri.fromServer([Uri? value])
: super._(value, ModelFieldValueSource.server);
}

/// [ModelFieldValueConverter] to enable automatic conversion of [ModelUri] as [ModelFieldValue].
///
/// [ModelUri][ModelFieldValue]として自動変換できるようにするための[ModelFieldValueConverter]
@immutable
class ModelUriConverter extends ModelFieldValueConverter<ModelUri> {
/// [ModelFieldValueConverter] to enable automatic conversion of [ModelUri] as [ModelFieldValue].
///
/// [ModelUri][ModelFieldValue]として自動変換できるようにするための[ModelFieldValueConverter]
const ModelUriConverter();

@override
ModelUri fromJson(Map<String, Object?> map) {
return ModelUri.fromJson(map);
}

@override
Map<String, Object?> toJson(ModelUri value) {
return value.toJson();
}
}

/// Filter class to make [ModelUri] available to [ModelQuery.filters].
///
/// [ModelUri][ModelQuery.filters]で利用できるようにするためのフィルタークラス。
@immutable
class ModelUriFilter extends ModelFieldValueFilter<ModelUri> {
/// Filter class to make [ModelUri] available to [ModelQuery.filters].
///
/// [ModelUri][ModelQuery.filters]で利用できるようにするためのフィルタークラス。
const ModelUriFilter();

@override
int? compare(dynamic a, dynamic b) {
return _hasMatch(a, b, (a, b) => a.toString().compareTo(b.toString()));
}

@override
bool? hasMatch(ModelQueryFilter filter, dynamic source) {
final target = filter.value;
switch (filter.type) {
case ModelQueryFilterType.equalTo:
return _hasMatch(source, target, (source, target) => source == target);
case ModelQueryFilterType.notEqualTo:
return _hasMatch(source, target, (source, target) => source != target);
case ModelQueryFilterType.lessThan:
case ModelQueryFilterType.greaterThan:
case ModelQueryFilterType.lessThanOrEqualTo:
case ModelQueryFilterType.greaterThanOrEqualTo:
return null;
case ModelQueryFilterType.arrayContains:
if (source is List) {
if (source.any((s) =>
_hasMatch(s, target, (source, target) => source == target) ??
false)) {
return true;
}
}
break;
case ModelQueryFilterType.arrayContainsAny:
if (source is List && target is List && target.isNotEmpty) {
if (source.any((s) => target.any((t) =>
_hasMatch(s, t, (source, target) => source == target) ??
false))) {
return true;
}
}
break;
case ModelQueryFilterType.whereIn:
if (target is List && target.isNotEmpty) {
final matches = target.mapAndRemoveEmpty((t) =>
_hasMatch(source, t, (source, target) => source == target));
if (matches.isNotEmpty) {
return matches.any((element) => element);
}
}
break;
case ModelQueryFilterType.whereNotIn:
if (target is List && target.isNotEmpty) {
final matches = target.mapAndRemoveEmpty((t) =>
_hasMatch(source, t, (source, target) => source == target));
if (matches.isNotEmpty) {
return !matches.any((element) => element);
}
}
break;
default:
return null;
}
return null;
}

T? _hasMatch<T>(
dynamic source,
dynamic target,
T Function(Uri source, Uri target) filter,
) {
if (source is ModelUri && target is ModelUri) {
return filter(source.value, target.value);
} else if (source is ModelUri && target is Uri) {
return filter(source.value, target);
} else if (source is Uri && target is ModelUri) {
return filter(source, target.value);
} else if (source is ModelUri && target is String) {
final uri = Uri.tryParse(target);
if (uri == null) {
return null;
}
return filter(source.value, uri);
} else if (source is String && target is ModelUri) {
final uri = Uri.tryParse(source);
if (uri == null) {
return null;
}
return filter(uri, target.value);
} else if (source is ModelUri &&
target is DynamicMap &&
target.get(kTypeFieldKey, "") == (ModelUri).toString()) {
return filter(source.value, ModelUri.fromJson(target).value);
} else if (source is DynamicMap &&
target is ModelUri &&
source.get(kTypeFieldKey, "") == (ModelUri).toString()) {
return filter(ModelUri.fromJson(source).value, target.value);
} else if (source is DynamicMap &&
target is DynamicMap &&
source.get(kTypeFieldKey, "") == (ModelUri).toString() &&
target.get(kTypeFieldKey, "") == (ModelUri).toString()) {
return filter(
ModelUri.fromJson(source).value, ModelUri.fromJson(target).value);
}
return null;
}
}

/// Define searchable fields.
///
/// You can store values as searchable values and search for elements that contain all of those defined in [ModelQueryFilter.equal].
Expand Down

0 comments on commit 3d9456e

Please sign in to comment.