Add option to exclude properties for equal check
JulianBissekkou opened this issue · 3 comments
Is your feature request related to a problem? Please describe.
I am doing an equal check on two instances and I want to have a nice syntax for excluding properties.
Describe the solution you'd like
Since this might be a niche problem my suggestion would be to provide a static helper function that does this.
I would not add this to the EqualtableMixin
.
Here is a small example:
static bool isEqualExcluding<T extends EquatableMixin>(
T lhs,
T rhs,
Object Function(T)? excludeProperty,
) {
if (excludeProperty == null) return lhs == rhs;
final lhsProperties = lhs.props
.where((property) => property == excludeProperty(lhs))
.toList();
final rhsProperties = rhs.props
.where((property) => property == excludeProperty(rhs))
.toList();
return equatable_utils.equals(lhsProperties, rhsProperties);
}
(The current implementation will not work if a class has two properties with the same value)
just don't include that excluded properties on props list, i don't know what's the use case for this tbh
Excluding a property just for a specific operation. Excluding the property in the props list will affect all equal checks.
I don't think that's possible. In your app you cant compare two objects of the same class using different combination of fields (directly), it would be hard to implement something so generic without some magic (like code generation, which some don't like).
However, you can always create helper methods, like this:
import 'package:equatable/equatable.dart';
class Person extends Equatable {
final int age;
final String name;
Person(this.name, this.age);
bool equalsByAge(Person other) {
return age == other.age;
}
bool equalsByName(Person other) {
return name == other.name;
}
@override
List<Object> get props => [age, name];
}
void main() {
final someBob = Person('Bob', 42);
final anotherBob = Person('Bob', 42);
final alice = Person('Alice', 69);
// By all fields
print(someBob == anotherBob); // true
// By specific fields
print(someBob.equalsByAge(anotherBob)); // true
print(someBob.equalsByName(anotherBob)); // true
print(someBob.equalsByName(alice)); // false
print(someBob.equalsByAge(alice)); // false
}
But of course you can only use that for client equality tests, for collections you have to use something else. I've come up with this:
abstract class PersonEquality extends Person {
PersonEquality(String name, int age) : super(name, age);
}
class PersonEqualityByAge extends PersonEquality {
PersonEqualityByAge(String name, int age) : super(name, age);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! Person) return false;
return age == other.age;
}
@override
int get hashCode => age.hashCode;
}
class PersonEqualityByName extends PersonEquality {
PersonEqualityByName(String name, int age) : super(name, age);
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
if (other is! Person) return false;
return name == other.name;
}
@override
int get hashCode => age.hashCode;
}
void main() {
final people = <PersonEquality>{
PersonEqualityByAge('John Doe', 69),
};
print(people.contains(PersonEqualityByAge('John', 69))); // true
print(people.contains(PersonEqualityByName('John Doe', 69))); // true
print(people.contains(PersonEqualityByAge('Johny', 18))); // false
}
As you can see it's not the most concise way of doing things, but I think, considering the limitations of the language, it's good enough and can get you quite flexible results (such as comparing multiple fields).