Skip to content

Commit cb95dc1

Browse files
committed
Filter reworked
1 parent 9e5dc58 commit cb95dc1

File tree

6 files changed

+231
-26
lines changed

6 files changed

+231
-26
lines changed

database.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,31 @@ type DatabaseListResponse struct {
9393
}
9494

9595
type DatabaseQueryRequest struct {
96-
Filter Filter `json:"filter,omitempty"`
97-
Sorts []SortObject `json:"sorts"`
98-
StartCursor Cursor `json:"start_cursor,omitempty"`
99-
PageSize int `json:"page_size,omitempty"`
96+
PropertyFilter *PropertyFilter
97+
CompoundFilter *CompoundFilter
98+
Sorts []SortObject `json:"sorts,omitempty"`
99+
StartCursor Cursor `json:"start_cursor,omitempty"`
100+
PageSize int `json:"page_size,omitempty"`
101+
}
102+
103+
func (qr *DatabaseQueryRequest) MarshalJSON() ([]byte, error) {
104+
var filter interface{}
105+
if qr.PropertyFilter != nil {
106+
filter = qr.PropertyFilter
107+
} else {
108+
filter = qr.CompoundFilter
109+
}
110+
return json.Marshal(struct {
111+
Sorts []SortObject `json:"sorts,omitempty"`
112+
StartCursor Cursor `json:"start_cursor,omitempty"`
113+
PageSize int `json:"page_size,omitempty"`
114+
Filter interface{} `json:"filter"`
115+
}{
116+
Sorts: qr.Sorts,
117+
StartCursor: qr.StartCursor,
118+
PageSize: qr.PageSize,
119+
Filter: filter,
120+
})
100121
}
101122

102123
type DatabaseQueryResponse struct {

database_test.go

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,10 @@ func TestDatabaseClient(t *testing.T) {
166166
filePath: "testdata/database_query.json",
167167
statusCode: http.StatusOK,
168168
request: &notionapi.DatabaseQueryRequest{
169-
Filter: &notionapi.PropertyFilter{
169+
PropertyFilter: &notionapi.PropertyFilter{
170170
Property: "Name",
171-
Text: map[notionapi.Condition]string{
172-
notionapi.ConditionContains: "Hel",
171+
Text: &notionapi.TextFilterCondition{
172+
Contains: "Hel",
173173
},
174174
},
175175
},
@@ -213,3 +213,96 @@ func TestDatabaseClient(t *testing.T) {
213213
}
214214
})
215215
}
216+
217+
func TestDatabaseQueryRequest_MarshalJSON(t *testing.T) {
218+
timeObj, err := time.Parse(time.RFC3339, "2021-05-10T02:43:42Z")
219+
if err != nil {
220+
t.Error(err)
221+
return
222+
}
223+
dateObj := notionapi.Date(timeObj)
224+
tests := []struct {
225+
name string
226+
req *notionapi.DatabaseQueryRequest
227+
want []byte
228+
wantErr bool
229+
}{
230+
{
231+
name: "with property filter without sort",
232+
req: &notionapi.DatabaseQueryRequest{
233+
PropertyFilter: &notionapi.PropertyFilter{
234+
Property: "Status",
235+
Select: &notionapi.SelectFilterCondition{
236+
Equals: "Reading",
237+
},
238+
},
239+
},
240+
want: []byte(`{"filter":{"property":"Status","select":{"equals":"Reading"}}}`),
241+
},
242+
{
243+
name: "with property filter with sort",
244+
req: &notionapi.DatabaseQueryRequest{
245+
PropertyFilter: &notionapi.PropertyFilter{
246+
Property: "Status",
247+
Select: &notionapi.SelectFilterCondition{
248+
Equals: "Reading",
249+
},
250+
},
251+
Sorts: []notionapi.SortObject{
252+
{
253+
Property: "Score /5",
254+
Direction: notionapi.SortOrderASC,
255+
},
256+
},
257+
},
258+
want: []byte(`{"sorts":[{"property":"Score /5","direction":"ascending"}],"filter":{"property":"Status","select":{"equals":"Reading"}}}`),
259+
},
260+
{
261+
name: "compound filter",
262+
req: &notionapi.DatabaseQueryRequest{
263+
CompoundFilter: &notionapi.CompoundFilter{
264+
notionapi.FilterOperatorOR: []notionapi.PropertyFilter{
265+
{
266+
Property: "Status",
267+
Select: &notionapi.SelectFilterCondition{
268+
Equals: "Reading",
269+
},
270+
},
271+
{
272+
Property: "Publisher",
273+
Select: &notionapi.SelectFilterCondition{
274+
Equals: "NYT",
275+
},
276+
},
277+
},
278+
},
279+
},
280+
want: []byte(`{"filter":{"or":[{"property":"Status","select":{"equals":"Reading"}},{"property":"Publisher","select":{"equals":"NYT"}}]}}`),
281+
},
282+
{
283+
name: "date filter",
284+
req: &notionapi.DatabaseQueryRequest{
285+
PropertyFilter: &notionapi.PropertyFilter{
286+
Property: "created_at",
287+
Date: &notionapi.DateFilterCondition{
288+
Equals: &dateObj,
289+
PastWeek: &struct{}{},
290+
},
291+
},
292+
},
293+
want: []byte(`{"filter":{"property":"created_at","date":{"equals":"2021-05-10T02:43:42Z","past_week":{}}}}`),
294+
},
295+
}
296+
for _, tt := range tests {
297+
t.Run(tt.name, func(t *testing.T) {
298+
got, err := tt.req.MarshalJSON()
299+
if (err != nil) != tt.wantErr {
300+
t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
301+
return
302+
}
303+
if !reflect.DeepEqual(got, tt.want) {
304+
t.Errorf("MarshalJSON() got = %s, want %s", got, tt.want)
305+
}
306+
})
307+
}
308+
}

filter.go

Lines changed: 95 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,104 @@
11
package notionapi
22

3-
import "time"
4-
53
type FilterOperator string
64

7-
type Filter interface{}
8-
9-
type CompoundFilter map[FilterOperator]Filter
5+
type CompoundFilter map[FilterOperator][]PropertyFilter
106

117
type Condition string
128

139
type PropertyFilter struct {
14-
Property PropertyType `json:"property"`
15-
Text map[Condition]string `json:"text,omitempty"`
16-
Number map[Condition]float64 `json:"number,omitempty"`
17-
Checkbox map[Condition]bool `json:"checkbox,omitempty"`
18-
Select map[Condition]interface{} `json:"select,omitempty"`
19-
MultiSelect map[Condition]interface{} `json:"multi_select,omitempty"`
20-
Date map[Condition]time.Time `json:"date,omitempty"`
21-
People map[Condition]interface{} `json:"people,omitempty"`
22-
Files map[Condition]bool `json:"files,omitempty"`
23-
Relation map[Condition]interface{} `json:"relation,omitempty"`
24-
Formula map[PropertyType]PropertyFilter `json:"formula,omitempty"`
10+
Property string `json:"property"`
11+
Text *TextFilterCondition `json:"text,omitempty"`
12+
Number *NumberFilterCondition `json:"number,omitempty"`
13+
Checkbox *CheckboxFilterCondition `json:"checkbox,omitempty"`
14+
Select *SelectFilterCondition `json:"select,omitempty"`
15+
MultiSelect *MultiSelectFilterCondition `json:"multi_select,omitempty"`
16+
Date *DateFilterCondition `json:"date,omitempty"`
17+
People *PeopleFilterCondition `json:"people,omitempty"`
18+
Files *FilesFilterCondition `json:"files,omitempty"`
19+
Relation *RelationFilterCondition `json:"relation,omitempty"`
20+
Formula *FormulaFilterCondition `json:"formula,omitempty"`
21+
}
22+
23+
type TextFilterCondition struct {
24+
Equals string `json:"equals,omitempty"`
25+
DoesNotEqual string `json:"does_not_equal,omitempty"`
26+
Contains string `json:"contains,omitempty"`
27+
DoesNotContain string `json:"does_not_contain,omitempty"`
28+
StartsWith string `json:"starts_with,omitempty"`
29+
EndsWith string `json:"ends_with,omitempty"`
30+
IsEmpty bool `json:"is_empty,omitempty"`
31+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
32+
}
33+
34+
type NumberFilterCondition struct {
35+
Equals float64 `json:"equals,omitempty"`
36+
DoesNotEqual float64 `json:"does_not_equal,omitempty"`
37+
GreaterThan float64 `json:"greater_than,omitempty"`
38+
LessThan float64 `json:"less_than,omitempty"`
39+
GreaterThanOrEqualTo float64 `json:"greater_than_or_equal_to"`
40+
LessThanOrEqualTo float64 `json:"less_than_or_equal_to"`
41+
IsEmpty bool `json:"is_empty,omitempty"`
42+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
43+
}
44+
45+
type CheckboxFilterCondition struct {
46+
Equals bool `json:"equals,omitempty"`
47+
DoesNotEqual bool `json:"does_not_equal,omitempty"`
48+
}
49+
50+
type SelectFilterCondition struct {
51+
Equals string `json:"equals,omitempty"`
52+
DoesNotEqual string `json:"does_not_equal,omitempty"`
53+
IsEmpty bool `json:"is_empty,omitempty"`
54+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
55+
}
56+
57+
type MultiSelectFilterCondition struct {
58+
Contains string `json:"contains,omitempty"`
59+
DoesNotContain string `json:"does_not_contain,omitempty"`
60+
IsEmpty bool `json:"is_empty,omitempty"`
61+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
62+
}
63+
64+
type DateFilterCondition struct {
65+
Equals *Date `json:"equals,omitempty"`
66+
Before *Date `json:"before,omitempty"`
67+
After *Date `json:"after,omitempty"`
68+
OnOrBefore *Date `json:"on_or_before,omitempty"`
69+
OnOrAfter *Date `json:"on_or_after,omitempty"`
70+
PastWeek *struct{} `json:"past_week,omitempty"`
71+
PastMonth *struct{} `json:"past_month,omitempty"`
72+
PastYear *struct{} `json:"past_year,omitempty"`
73+
NextWeek *struct{} `json:"next_week,omitempty"`
74+
NextMonth *struct{} `json:"next_month,omitempty"`
75+
NextYear *struct{} `json:"next_year,omitempty"`
76+
IsEmpty bool `json:"is_empty,omitempty"`
77+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
78+
}
79+
80+
type PeopleFilterCondition struct {
81+
Contains string `json:"contains,omitempty"`
82+
DoesNotContain string `json:"does_not_contain,omitempty"`
83+
IsEmpty bool `json:"is_empty,omitempty"`
84+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
85+
}
86+
87+
type FilesFilterCondition struct {
88+
IsEmpty bool `json:"is_empty,omitempty"`
89+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
90+
}
91+
92+
type RelationFilterCondition struct {
93+
Contains string `json:"contains,omitempty"`
94+
DoesNotContain string `json:"does_not_contain,omitempty"`
95+
IsEmpty bool `json:"is_empty,omitempty"`
96+
IsNotEmpty bool `json:"is_not_empty,omitempty"`
97+
}
98+
99+
type FormulaFilterCondition struct {
100+
Text *TextFilterCondition `json:"text,omitempty"`
101+
Checkbox *CheckboxFilterCondition `json:"checkbox,omitempty"`
102+
Number *NumberFilterCondition `json:"number,omitempty"`
103+
Date *DateFilterCondition `json:"date,omitempty"`
25104
}

object.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package notionapi
22

3+
import "time"
4+
35
type ObjectType string
46

57
func (ot ObjectType) String() string {
@@ -66,3 +68,13 @@ type Cursor string
6668
func (c Cursor) String() string {
6769
return string(c)
6870
}
71+
72+
type Date time.Time
73+
74+
func (d *Date) String() string {
75+
return time.Time(*d).Format(time.RFC3339)
76+
}
77+
78+
func (d *Date) MarshalText() ([]byte, error) {
79+
return []byte(d.String()), nil
80+
}

search.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (sc *SearchClient) Do(ctx context.Context, request *SearchRequest) (*Search
3434
type SearchRequest struct {
3535
Query string `json:"query,omitempty"`
3636
Sort *SortObject `json:"sort,omitempty"`
37-
Filter Filter `json:"filter,omitempty"`
37+
Filter interface{} `json:"filter,omitempty"`
3838
StartCursor Cursor `json:"start_cursor,omitempty"`
3939
PageSize int `json:"page_size"`
4040
}

sort.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ type TimestampType string
66

77
type SortObject struct {
88
Property string `json:"property,omitempty"`
9-
Timestamp TimestampType `json:"timestamp"`
10-
Direction SortOrder `json:"direction"`
9+
Timestamp TimestampType `json:"timestamp,omitempty"`
10+
Direction SortOrder `json:"direction,omitempty"`
1111
}

0 commit comments

Comments
 (0)