Skip to content

Commit 740671b

Browse files
authored
Merge pull request #26 from talkjs/feat/filter-by-subject-date
Implement new Feed Filters
2 parents 74bac2a + 1a22223 commit 740671b

File tree

2 files changed

+131
-10
lines changed

2 files changed

+131
-10
lines changed

lib/src/predicate.dart

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import 'package:flutter/foundation.dart';
55
class FieldPredicate<T> {
66
final String _operand;
77
String? _value;
8-
List<String>? _values;
8+
List<String?>? _values;
9+
bool _useValue;
910

10-
FieldPredicate.equals(T value) : _operand = '==', _value = value.toString();
11-
FieldPredicate.notEquals(T value) : _operand = '!=', _value = value.toString();
12-
FieldPredicate.oneOf(List<T> values) : _operand = 'oneOf', _values = values.map((value) => value.toString()).toList();
13-
FieldPredicate.notOneOf(List<T> values) : _operand = '!oneOf', _values = values.map((value) => value.toString()).toList();
11+
FieldPredicate.equals(T value) : _operand = '==', _value = value?.toString(), _useValue = true;
12+
FieldPredicate.notEquals(T value) : _operand = '!=', _value = value?.toString(), _useValue = true;
13+
FieldPredicate.oneOf(List<T> values) : _operand = 'oneOf', _values = values.map((value) => value?.toString()).toList(), _useValue = false;
14+
FieldPredicate.notOneOf(List<T> values) : _operand = '!oneOf', _values = values.map((value) => value?.toString()).toList(), _useValue = false;
1415

1516
FieldPredicate.of(FieldPredicate<T> other)
1617
: _operand = other._operand,
1718
_value = other._value,
18-
_values = (other._values != null ? List<String>.of(other._values!) : null);
19+
_values = (other._values != null ? List<String?>.of(other._values!) : null),
20+
_useValue = other._useValue;
1921

2022
@override
2123
String toString() {
@@ -27,7 +29,7 @@ class FieldPredicate<T> {
2729

2830
result.add(_operand);
2931

30-
if (_value != null) {
32+
if (_useValue) {
3133
result.add(_value);
3234
}
3335

@@ -59,13 +61,18 @@ class FieldPredicate<T> {
5961
return false;
6062
}
6163

64+
if (_useValue != other._useValue) {
65+
return false;
66+
}
67+
6268
return true;
6369
}
6470

6571
int get hashCode => Object.hash(
6672
_operand,
6773
_value,
6874
(_values != null ? Object.hashAll(_values!) : _values),
75+
_useValue,
6976
);
7077
}
7178

@@ -113,6 +120,10 @@ class CustomFieldPredicate extends FieldPredicate<String> {
113120
return false;
114121
}
115122

123+
if (_useValue != other._useValue) {
124+
return false;
125+
}
126+
116127
if (_exists != other._exists) {
117128
return false;
118129
}
@@ -124,10 +135,80 @@ class CustomFieldPredicate extends FieldPredicate<String> {
124135
_operand,
125136
_value,
126137
(_values != null ? Object.hashAll(_values!) : _values),
138+
_useValue,
127139
_exists,
128140
);
129141
}
130142

143+
class NumberPredicate {
144+
final String _operand;
145+
double? _value;
146+
List<double>? _values;
147+
148+
NumberPredicate.greaterThan(double value) : _operand = '>', _value = value;
149+
NumberPredicate.lessThan(double value) : _operand = '<', _value = value;
150+
NumberPredicate.greaterOrEquals(double value) : _operand = '>=', _value = value;
151+
NumberPredicate.lessOrEquals(double value) : _operand = '<=', _value = value;
152+
NumberPredicate.between(List<double> values) : _operand = 'between', _values = List<double>.of(values);
153+
NumberPredicate.notBetween(List<double> values) : _operand = '!between', _values = List<double>.of(values);
154+
155+
NumberPredicate.of(NumberPredicate other)
156+
: _operand = other._operand,
157+
_value = other._value,
158+
_values = (other._values != null ? List<double>.of(other._values!) : null);
159+
160+
@override
161+
String toString() {
162+
return json.encode(this);
163+
}
164+
165+
dynamic toJson() {
166+
final result = <dynamic>[];
167+
168+
result.add(_operand);
169+
170+
if (_value != null) {
171+
result.add(_value);
172+
}
173+
174+
if (_values != null) {
175+
result.add(_values);
176+
}
177+
178+
return result;
179+
}
180+
181+
bool operator ==(Object other) {
182+
if (identical(this, other)) {
183+
return true;
184+
}
185+
186+
if (!(other is NumberPredicate)) {
187+
return false;
188+
}
189+
190+
if (_operand != other._operand) {
191+
return false;
192+
}
193+
194+
if (_value != other._value) {
195+
return false;
196+
}
197+
198+
if (!listEquals(_values, other._values)) {
199+
return false;
200+
}
201+
202+
return true;
203+
}
204+
205+
int get hashCode => Object.hash(
206+
_operand,
207+
_value,
208+
(_values != null ? Object.hashAll(_values!) : _values),
209+
);
210+
}
211+
131212
class ConversationAccessLevel {
132213
final String _value;
133214

@@ -151,12 +232,20 @@ class ConversationPredicate {
151232
/// Set this field to only select conversations that have, or don't have any, unread messages.
152233
final bool? hasUnreadMessages;
153234

154-
const ConversationPredicate({this.access, this.custom, this.hasUnreadMessages});
235+
/// Only select conversations that have the last message sent in a particular time interval.
236+
final NumberPredicate? lastMessageTs;
237+
238+
/// Only select conversations that have the subject set to particular values.
239+
final FieldPredicate<String?>? subject;
240+
241+
const ConversationPredicate({this.access, this.custom, this.hasUnreadMessages, this.lastMessageTs, this.subject});
155242

156243
ConversationPredicate.of(ConversationPredicate other)
157244
: access = (other.access != null ? FieldPredicate<ConversationAccessLevel>.of(other.access!) : null),
158245
custom = (other.custom != null ? Map<String, CustomFieldPredicate>.of(other.custom!) : null),
159-
hasUnreadMessages = other.hasUnreadMessages;
246+
hasUnreadMessages = other.hasUnreadMessages,
247+
lastMessageTs = (other.lastMessageTs != null ? NumberPredicate.of(other.lastMessageTs!) : null),
248+
subject = (other.subject != null ? FieldPredicate<String?>.of(other.subject!) : null);
160249

161250
@override
162251
String toString() {
@@ -178,6 +267,14 @@ class ConversationPredicate {
178267
result['hasUnreadMessages'] = hasUnreadMessages;
179268
}
180269

270+
if (lastMessageTs != null) {
271+
result['lastMessageTs'] = lastMessageTs;
272+
}
273+
274+
if (subject != null) {
275+
result['subject'] = subject;
276+
}
277+
181278
return result;
182279
}
183280

@@ -202,6 +299,14 @@ class ConversationPredicate {
202299
return false;
203300
}
204301

302+
if (lastMessageTs != other.lastMessageTs) {
303+
return false;
304+
}
305+
306+
if (subject != other.subject) {
307+
return false;
308+
}
309+
205310
return true;
206311
}
207312

@@ -210,6 +315,8 @@ class ConversationPredicate {
210315
(custom != null ? Object.hashAll(custom!.keys) : custom),
211316
(custom != null ? Object.hashAll(custom!.values) : custom),
212317
hasUnreadMessages,
318+
lastMessageTs,
319+
subject,
213320
);
214321
}
215322

test/talkjs_test.dart

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ void main() {
3131
'visibility': CustomFieldPredicate.equals('visible'),
3232
},
3333
hasUnreadMessages: false,
34+
lastMessageTs: NumberPredicate.greaterThan(1679298371586),
35+
subject: FieldPredicate.equals(null),
3436
) == ConversationPredicate(
3537
access: FieldPredicate.notEquals(ConversationAccessLevel.none),
3638
custom: {
@@ -39,6 +41,8 @@ void main() {
3941
'visibility': CustomFieldPredicate.equals('visible'),
4042
},
4143
hasUnreadMessages: false,
44+
lastMessageTs: NumberPredicate.greaterThan(1679298371586),
45+
subject: FieldPredicate.equals(null),
4246
)
4347
, true);
4448
});
@@ -120,6 +124,10 @@ void main() {
120124
expect(CustomFieldPredicate.of(CustomFieldPredicate.oneOf(['it', 'fr'])) == CustomFieldPredicate.oneOf(['it', 'fr']), true);
121125
});
122126

127+
test('test NumberPredicate.of', () {
128+
expect(NumberPredicate.of(NumberPredicate.notBetween([100, 300])) == NumberPredicate.notBetween([100, 300]), true);
129+
});
130+
123131
test('test ConversationPredicate of', () {
124132
expect(
125133
ConversationPredicate.of(ConversationPredicate(
@@ -130,6 +138,8 @@ void main() {
130138
'visibility': CustomFieldPredicate.equals('visible'),
131139
},
132140
hasUnreadMessages: false,
141+
lastMessageTs: NumberPredicate.greaterThan(1679298371586),
142+
subject: FieldPredicate.notEquals('Pink shoes'),
133143
)) == ConversationPredicate(
134144
access: FieldPredicate.notEquals(ConversationAccessLevel.none),
135145
custom: {
@@ -138,6 +148,8 @@ void main() {
138148
'visibility': CustomFieldPredicate.equals('visible'),
139149
},
140150
hasUnreadMessages: false,
151+
lastMessageTs: NumberPredicate.greaterThan(1679298371586),
152+
subject: FieldPredicate.notEquals('Pink shoes'),
141153
)
142154
, true);
143155
});
@@ -218,8 +230,10 @@ void main() {
218230
'visibility': CustomFieldPredicate.equals('visible'),
219231
},
220232
hasUnreadMessages: false,
233+
lastMessageTs: NumberPredicate.greaterThan(1679298371586),
234+
subject: FieldPredicate.oneOf(['Pink shoes', null]),
221235
)),
222-
'{"access":["!=","None"],"custom":{"seller":"exists","category":["oneOf",["shoes","sandals"]],"visibility":["==","visible"]},"hasUnreadMessages":false}'
236+
'{"access":["!=","None"],"custom":{"seller":"exists","category":["oneOf",["shoes","sandals"]],"visibility":["==","visible"]},"hasUnreadMessages":false,"lastMessageTs":[">",1679298371586.0],"subject":["oneOf",["Pink shoes",null]]}'
223237
);
224238
});
225239

0 commit comments

Comments
 (0)