diff --git a/database.go b/database.go index d78fbd0..25cf90e 100644 --- a/database.go +++ b/database.go @@ -18,6 +18,7 @@ type DatabaseService interface { Get(context.Context, DatabaseID) (*Database, error) List(context.Context, *Pagination) (*DatabaseListResponse, error) Query(context.Context, DatabaseID, *DatabaseQueryRequest) (*DatabaseQueryResponse, error) + Update(context.Context, DatabaseID, *DatabaseUpdateRequest) (*Database, error) } type DatabaseClient struct { @@ -72,6 +73,20 @@ func (dc *DatabaseClient) Query(ctx context.Context, id DatabaseID, requestBody return &response, nil } +// Update https://developers.notion.com/reference/update-a-database +func (dc *DatabaseClient) Update(ctx context.Context, id DatabaseID, requestBody *DatabaseUpdateRequest) (*Database, error) { + res, err := dc.apiClient.request(ctx, http.MethodPatch, fmt.Sprintf("databases/%s", id.String()), nil, requestBody) + if err != nil { + return nil, err + } + + var response Database + if err := json.NewDecoder(res.Body).Decode(&response); err != nil { + return nil, err + } + return &response, nil +} + type Database struct { Object ObjectType `json:"object"` ID ObjectID `json:"id"` @@ -105,7 +120,7 @@ func (qr *DatabaseQueryRequest) MarshalJSON() ([]byte, error) { var filter interface{} if qr.PropertyFilter != nil { filter = qr.PropertyFilter - } else if qr.CompoundFilter != nil{ + } else if qr.CompoundFilter != nil { filter = qr.CompoundFilter } return json.Marshal(struct { @@ -127,3 +142,8 @@ type DatabaseQueryResponse struct { HasMore bool `json:"has_more"` NextCursor Cursor `json:"next_cursor"` } + +type DatabaseUpdateRequest struct { + Title []RichText `json:"title,omitempty"` + Properties PropertyConfigs `json:"properties,omitempty"` +} diff --git a/database_test.go b/database_test.go index 6fe3d6a..f03df81 100644 --- a/database_test.go +++ b/database_test.go @@ -2,11 +2,12 @@ package notionapi_test import ( "context" - "github.com/jomei/notionapi" "net/http" "reflect" "testing" "time" + + "github.com/jomei/notionapi" ) func TestDatabaseClient(t *testing.T) { @@ -207,6 +208,72 @@ func TestDatabaseClient(t *testing.T) { }) } }) + + t.Run("Update", func(t *testing.T) { + tests := []struct { + name string + filePath string + statusCode int + id notionapi.DatabaseID + request *notionapi.DatabaseUpdateRequest + want *notionapi.Database + wantErr bool + err error + }{ + { + name: "returns update results", + filePath: "testdata/database_update.json", + statusCode: http.StatusOK, + id: "some_id", + request: ¬ionapi.DatabaseUpdateRequest{ + Title: []notionapi.RichText{ + { + Type: notionapi.ObjectTypeText, + Text: notionapi.Text{Content: "patch"}, + }, + }, + Properties: notionapi.PropertyConfigs{ + "patch": notionapi.TitlePropertyConfig{ + Type: notionapi.PropertyConfigTypeRichText, + Title: notionapi.RichText{ + Type: notionapi.ObjectTypeText, + Text: notionapi.Text{Content: "patch"}, + }, + }, + }, + }, + want: ¬ionapi.Database{ + Object: notionapi.ObjectTypeDatabase, + ID: "some_id", + CreatedTime: timestamp, + LastEditedTime: timestamp, + Title: []notionapi.RichText{ + { + Type: notionapi.ObjectTypeText, + Text: notionapi.Text{Content: "patch"}, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := newMockedClient(t, tt.filePath, tt.statusCode) + client := notionapi.NewClient("some_token", notionapi.WithHTTPClient(c)) + got, err := client.Database.Update(context.Background(), tt.id, tt.request) + + if (err != nil) != tt.wantErr { + t.Errorf("Update() error = %v, wantErr %v", err, tt.wantErr) + return + } + got.Properties = nil + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("Update() got = %v, want %v", got, tt.want) + } + }) + } + }) } func TestDatabaseQueryRequest_MarshalJSON(t *testing.T) { diff --git a/testdata/database_update.json b/testdata/database_update.json new file mode 100644 index 0000000..4bdaab2 --- /dev/null +++ b/testdata/database_update.json @@ -0,0 +1,137 @@ +{ + "object": "database", + "id": "some_id", + "created_time": "2021-05-24T05:06:34.827Z", + "last_edited_time": "2021-05-24T05:06:34.827Z", + "parent": { + "type": "page_id", + "page_id": "48f8fee9-cd79-4180-bc2f-ec0398253067" + }, + "icon": { + "type": "emoji", + "emoji": "🎉" + }, + "cover": { + "type": "external", + "external": { + "url": "https://website.domain/images/image.png" + } + }, + "title": [ + { + "type": "text", + "text": { + "content": "patch" + } + } + ], + "properties": { + "Name": { + "id": "title", + "type": "title", + "title": {} + }, + "Description": { + "id": "J@cS", + "type": "rich_text", + "rich_text": {} + }, + "In stock": { + "id": "xY`", + "type": "checkbox", + "checkbox": {} + }, + "Food group": { + "id": "TJmr", + "type": "select", + "multi_select": { + "options": [ + { + "id": "96eb622f-4b88-4283-919d-ece2fbed3841", + "name": "Vegetable", + "color": "green" + }, + { + "id": "bb443819-81dc-46fb-882d-ebee6e22c432", + "name": "Fruit", + "color": "red" + }, + { + "id": "7da9d1b9-8685-472e-9da3-3af57bdb221e", + "name": "Protein", + "color": "yellow" + } + ] + } + }, + "Price": { + "id": "cU^N", + "type": "number", + "number": { + "format": "dollar" + } + }, + "Cost of next trip": { + "id": "p:sC", + "type": "formula", + "formula": { + "value": "if(prop(\"In stock\"), 0, prop(\"Price\"))" + } + }, + "Last ordered": { + "id": "]\\R[", + "type": "date", + "date": {} + }, + "Meals": { + "type": "relation", + "relation": { + "database": "668d797c-76fa-4934-9b05-ad288df2d136", + "synced_property_name": null + } + }, + "Number of meals": { + "id": "Z\\Eh", + "type": "rollup", + "rollup": { + "rollup_property_name": "Name", + "relation_property_name": "Meals", + "rollup_property_id": "title", + "relation_property_id": "mxp^", + "function": "count" + } + }, + "Store availability": { + "type": "multi_select", + "multi_select": { + "options": [ + { + "id": "d209b920-212c-4040-9d4a-bdf349dd8b2a", + "name": "Duc Loi Market", + "color": "blue" + }, + { + "id": "70104074-0f91-467b-9787-00d59e6e1e41", + "name": "Rainbow Grocery", + "color": "gray" + }, + { + "id": "6c3867c5-d542-4f84-b6e9-a420c43094e7", + "name": "Gus's Community Market", + "color": "yellow" + }, + { + "id": "a62fbb5f-fed4-44a4-8cac-cba5f518c1a1", + "name": "Good life grocery", + "color": "orange" + } + ] + } + }, + "Photo": { + "id": "aTIT", + "type": "url", + "url": {} + } + } +}