From 59d93d3e451c953ea1a3e68186e1fa60f9e94111 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 26 Oct 2025 22:11:12 +0530 Subject: [PATCH 01/27] Introduce DataSources client --- .../Api/DataSources/DataSourcesClient.cs | 12 ++++++++++++ .../Api/DataSources/IDataSourcesClient.cs | 9 +++++++++ Src/Notion.Client/NotionClient.cs | 9 ++++++++- Src/Notion.Client/NotionClientFactory.cs | 1 + 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Api/DataSources/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs diff --git a/Src/Notion.Client/Api/DataSources/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/DataSourcesClient.cs new file mode 100644 index 00000000..e376d500 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/DataSourcesClient.cs @@ -0,0 +1,12 @@ +namespace Notion.Client +{ + public sealed partial class DataSourcesClient : IDataSourcesClient + { + private readonly IRestClient _restClient; + + public DataSourcesClient(IRestClient restClient) + { + _restClient = restClient; + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs new file mode 100644 index 00000000..4a3527f5 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -0,0 +1,9 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public interface IDataSourcesClient + { + } +} diff --git a/Src/Notion.Client/NotionClient.cs b/Src/Notion.Client/NotionClient.cs index 6f21ccf7..6b0c705a 100644 --- a/Src/Notion.Client/NotionClient.cs +++ b/Src/Notion.Client/NotionClient.cs @@ -18,8 +18,11 @@ public interface INotionClient IBlocksClient Blocks { get; } ICommentsClient Comments { get; } + IFileUploadsClient FileUploads { get; } + IDataSourcesClient DataSources { get; } + IRestClient RestClient { get; } } @@ -34,7 +37,8 @@ public NotionClient( ICommentsClient comments, IBlocksClient blocks, IAuthenticationClient authenticationClient, - IFileUploadsClient fileUploadsClient) + IFileUploadsClient fileUploadsClient, + IDataSourcesClient dataSourcesClient) { RestClient = restClient; Users = users; @@ -45,6 +49,7 @@ public NotionClient( Blocks = blocks; AuthenticationClient = authenticationClient; FileUploads = fileUploadsClient; + DataSources = dataSourcesClient; } public IAuthenticationClient AuthenticationClient { get; } @@ -63,6 +68,8 @@ public NotionClient( public IFileUploadsClient FileUploads { get; } + public IDataSourcesClient DataSources { get; } + public IRestClient RestClient { get; } } } diff --git a/Src/Notion.Client/NotionClientFactory.cs b/Src/Notion.Client/NotionClientFactory.cs index 2fc9acac..d2720082 100644 --- a/Src/Notion.Client/NotionClientFactory.cs +++ b/Src/Notion.Client/NotionClientFactory.cs @@ -16,6 +16,7 @@ public static NotionClient Create(ClientOptions options) , new BlocksClient(restClient) , new AuthenticationClient(restClient) , new FileUploadsClient(restClient) + , new DataSourcesClient(restClient) ); } } From 0f38db645b8f50852c29b9cc7febfd9b0c7662a4 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 27 Oct 2025 01:48:04 +0530 Subject: [PATCH 02/27] Add support to retrieve data source --- Src/Notion.Client/Api/ApiEndpoints.cs | 5 + .../Api/DataSources/IDataSourcesClient.cs | 10 ++ .../DataSources/Models/DataSourceResponse.cs | 97 +++++++++++++++++++ .../PageCover/ExternalPageCoverResponse.cs | 16 +++ .../Models/PageCover/FilePageCoverResponse.cs | 16 +++ .../Models/PageCover/IPageCoverResponse.cs | 10 ++ .../PageIcon/CustomEmojiPageIconResponse.cs | 16 +++ .../Models/PageIcon/CustomEmojiResponse.cs | 20 ++++ .../Models/PageIcon/EmojiPageIconResponse.cs | 16 +++ .../Models/PageIcon/ExternalFileResponse.cs | 14 +++ .../PageIcon/ExternalPageIconResponse.cs | 16 +++ .../Models/PageIcon/FilePageIconResponse.cs | 16 +++ .../Models/PageIcon/IPageIconResponse.cs | 16 +++ .../Models/PageIcon/InternalFileResponse.cs | 18 ++++ .../Models/Parents/BlockParentResponse.cs | 16 +++ .../Parents/DataSourceParentResponse.cs | 19 ++++ .../Models/Parents/DatabaseParentResponse.cs | 16 +++ .../Parents/IParentOfDataSourceResponse.cs | 14 +++ .../Parents/IParentOfDatabaseResponse.cs | 10 ++ .../Models/Parents/PageParentResponse.cs | 16 +++ .../Models/Parents/WorkspaceParentResponse.cs | 16 +++ .../ButtonDataSourcePropertyConfigResponse.cs | 13 +++ ...heckboxDataSourcePropertyConfigResponse.cs | 13 +++ ...eatedByDataSourcePropertyConfigResponse.cs | 13 +++ ...tedTimeDataSourcePropertyConfigResponse.cs | 13 +++ .../DataSourcePropertyConfigResponse.cs | 46 +++++++++ .../PropertyConfig/DataSourcePropertyType.cs | 28 ++++++ .../DateDataSourcePropertyConfigResponse.cs | 13 +++ .../EmailDataSourcePropertyConfigResponse.cs | 13 +++ .../FilesDataSourcePropertyConfigResponse.cs | 13 +++ ...FormulaDataSourcePropertyConfigResponse.cs | 22 +++++ ...ditedByDataSourcePropertyConfigResponse.cs | 13 +++ ...tedTimeDataSourcePropertyConfigResponse.cs | 13 +++ ...iSelectDataSourcePropertyConfigResponse.cs | 12 +++ .../NumberDataSourcePropertyConfigResponse.cs | 22 +++++ .../PeopleDataSourcePropertyConfigResponse.cs | 13 +++ ...eNumberDataSourcePropertyConfigResponse.cs | 13 +++ .../DualPropertyRelationResponse.cs | 25 +++++ .../RelationProperty/RelationDataResponse.cs | 23 +++++ ...elationDataSourcePropertyConfigResponse.cs | 12 +++ .../SinglePropertyRelationResponse.cs | 13 +++ ...ichTextDataSourcePropertyConfigResponse.cs | 13 +++ .../RollupDataSourcePropertyConfigResponse.cs | 34 +++++++ .../SelectDataSourcePropertyConfigResponse.cs | 41 ++++++++ .../StatusDataSourcePropertyConfigResponse.cs | 13 +++ .../TitleDataSourcePropertyConfigResponse.cs | 13 +++ ...niqueIdDataSourcePropertyConfigResponse.cs | 13 +++ .../UrlDataSourcePropertyConfigResponse.cs | 13 +++ .../DataSources/Retrieve/DataSourcesClient.cs | 30 ++++++ .../IRetrieveDataSourcePathParameters.cs | 7 ++ .../Request/RetrieveDataSourceRequest.cs | 7 ++ .../Response/RetrieveDataSourceResponse.cs | 6 ++ Src/Notion.Client/Models/ObjectType.cs | 3 + .../DataSourcesClientTests.cs | 90 +++++++++++++++++ 54 files changed, 1022 insertions(+) create mode 100644 Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageCover/ExternalPageCoverResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageCover/FilePageCoverResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageCover/IPageCoverResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiPageIconResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/EmojiPageIconResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalFileResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalPageIconResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/FilePageIconResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/IPageIconResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PageIcon/InternalFileResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/BlockParentResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/DataSourceParentResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/DatabaseParentResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDataSourceResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/PageParentResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Parents/WorkspaceParentResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/ButtonDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CheckboxDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedByDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedTimeDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyType.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DateDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/EmailDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FilesDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FormulaDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedByDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedTimeDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/MultiSelectDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/NumberDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PeopleDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PhoneNumberDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/DualPropertyRelationResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/SinglePropertyRelationResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RichTextDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RollupDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/SelectDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/StatusDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/TitleDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UniqueIdDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UrlDataSourcePropertyConfigResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Retrieve/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/Retrieve/Request/IRetrieveDataSourcePathParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Retrieve/Request/RetrieveDataSourceRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Retrieve/Response/RetrieveDataSourceResponse.cs create mode 100644 Test/Notion.UnitTests/DataSourcesClientTests.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 300c2482..9084781e 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -148,5 +148,10 @@ public static class FileUploadsApiUrls public static string List => "/v1/file_uploads"; public static string Retrieve(IRetrieveFileUploadPathParameters pathParameters) => $"/v1/file_uploads/{pathParameters.FileUploadId}"; } + + public static class DataSourcesApiUrls + { + public static string Retrieve(IRetrieveDataSourcePathParameters pathParameters) => $"/v1/data_sources/{pathParameters.DataSourceId}"; + } } } diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs index 4a3527f5..ad3151e7 100644 --- a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -5,5 +5,15 @@ namespace Notion.Client { public interface IDataSourcesClient { + /// + /// Retrieves a data source by its ID. + /// + /// + /// + /// + Task RetrieveAsync( + RetrieveDataSourceRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs new file mode 100644 index 00000000..0271a30e --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceResponse : IObject, IObjectModificationData + { + public string Id { get; set; } + + public ObjectType Object => ObjectType.DataSource; + + /// + /// The title of the data source. + /// + [JsonProperty("title")] + public IEnumerable Title { get; set; } + + /// + /// A description of the data source. + /// + [JsonProperty("description")] + public IEnumerable Description { get; set; } + + /// + /// The parent of the data source. + /// + [JsonProperty("parent")] + public IParentOfDataSourceResponse Parent { get; set; } + + /// + /// The parent of the data source's containing database. This is typically a page, block, + /// or workspace, but can be another database in the case of wikis. + /// + [JsonProperty("database_parent")] + public IParentOfDatabaseResponse DatabaseParent { get; set; } + + /// + /// Indicates whether the data source is inline within its parent database. + /// + [JsonProperty("is_inline")] + public bool IsInline { get; set; } + + /// + /// Indicates whether the data source is archived. + /// + [JsonProperty("archived")] + public bool Archived { get; set; } + + /// + /// Indicates whether the data source is in the trash. + /// + [JsonProperty("in_trash")] + public bool InTrash { get; set; } + + public DateTime CreatedTime { get; set; } + + public DateTime LastEditedTime { get; set; } + + public PartialUser CreatedBy { get; set; } + + public PartialUser LastEditedBy { get; set; } + + /// + /// The properties schema of the data source. + /// + [JsonProperty("properties")] + public IDictionary Properties { get; set; } + + /// + /// The icon of the data source. + /// + [JsonProperty("icon")] + public IPageIconResponse Icon { get; set; } + + /// + /// The cover image of the data source. + /// + [JsonProperty("cover")] + public IPageCoverResponse Cover { get; set; } + + /// + /// The URL of the data source. + /// + [JsonProperty("url")] + public string Url { get; set; } + + /// + /// The public page URL if the data source has been published to the web. Otherwise, null. + /// + [JsonProperty("public_url")] + public string PublicUrl { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageCover/ExternalPageCoverResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageCover/ExternalPageCoverResponse.cs new file mode 100644 index 00000000..c9e2186d --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageCover/ExternalPageCoverResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ExternalPageCoverResponse : IPageCoverResponse + { + public string Type { get; set; } = "external"; + + [JsonProperty("external")] + public ExternalFileResponse External { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageCover/FilePageCoverResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageCover/FilePageCoverResponse.cs new file mode 100644 index 00000000..f567ae64 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageCover/FilePageCoverResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FilePageCoverResponse : IPageCoverResponse + { + public string Type { get; set; } = "file"; + + [JsonProperty("file")] + public InternalFileResponse File { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageCover/IPageCoverResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageCover/IPageCoverResponse.cs new file mode 100644 index 00000000..9db1719e --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageCover/IPageCoverResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IPageCoverResponse + { + [JsonProperty("type")] + string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiPageIconResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiPageIconResponse.cs new file mode 100644 index 00000000..6cefac3e --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiPageIconResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmojiPageIconResponse : IPageIconResponse + { + public string Type { get; set; } = "custom_emoji"; + + [JsonProperty("custom_emoji")] + public CustomEmojiResponse CustomEmoji { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiResponse.cs new file mode 100644 index 00000000..ae227f60 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/CustomEmojiResponse.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmojiResponse + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/EmojiPageIconResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/EmojiPageIconResponse.cs new file mode 100644 index 00000000..0ebb1428 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/EmojiPageIconResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EmojiPageIconResponse : IPageIconResponse + { + public string Type { get; set; } = "emoji"; + + [JsonProperty("emoji")] + public string Emoji { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalFileResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalFileResponse.cs new file mode 100644 index 00000000..414469cc --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalFileResponse.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ExternalFileResponse + { + [JsonProperty("url")] + public string Url { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalPageIconResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalPageIconResponse.cs new file mode 100644 index 00000000..14852fb5 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/ExternalPageIconResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ExternalPageIconResponse : IPageIconResponse + { + public string Type { get; set; } = "external"; + + [JsonProperty("external")] + public ExternalFileResponse External { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/FilePageIconResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/FilePageIconResponse.cs new file mode 100644 index 00000000..3acdf762 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/FilePageIconResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FilePageIconResponse : IPageIconResponse + { + public string Type { get; set; } = "file"; + + [JsonProperty("file")] + public InternalFileResponse File { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/IPageIconResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/IPageIconResponse.cs new file mode 100644 index 00000000..5d401c99 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/IPageIconResponse.cs @@ -0,0 +1,16 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmojiPageIconResponse), "emoji]")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CustomEmojiPageIconResponse), "custom_emoji")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FilePageIconResponse), "file")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ExternalPageIconResponse), "external")] + public interface IPageIconResponse + { + [JsonProperty("type")] + string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PageIcon/InternalFileResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PageIcon/InternalFileResponse.cs new file mode 100644 index 00000000..7979c08f --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PageIcon/InternalFileResponse.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class InternalFileResponse + { + [JsonProperty("url")] + public string Url { get; set; } + + [JsonProperty("expiry_time")] + public DateTime ExpiryTime { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/BlockParentResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/BlockParentResponse.cs new file mode 100644 index 00000000..8a4a309b --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/BlockParentResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class BlockParentResponse : IParentOfDatabaseResponse + { + public string Type { get; set; } = "block_id"; + + [JsonProperty("block_id")] + public string BlockId { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/DataSourceParentResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/DataSourceParentResponse.cs new file mode 100644 index 00000000..a1a6911b --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/DataSourceParentResponse.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceParentResponse : IParentOfDataSourceResponse + { + public string Type { get; set; } = "data_source_id"; + + [JsonProperty("data_source_id")] + public string DataSourceId { get; set; } + + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/DatabaseParentResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/DatabaseParentResponse.cs new file mode 100644 index 00000000..93fc299c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/DatabaseParentResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DatabaseParentResponse : IParentOfDataSourceResponse, IParentOfDatabaseResponse + { + public string Type { get; set; } = "database_id"; + + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDataSourceResponse.cs new file mode 100644 index 00000000..9f842172 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDataSourceResponse.cs @@ -0,0 +1,14 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatabaseParentResponse), "database_id")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DataSourceParentResponse), "data_source_id")] + public interface IParentOfDataSourceResponse + { + [JsonProperty("type")] + string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs new file mode 100644 index 00000000..e28f785e --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IParentOfDatabaseResponse + { + [JsonProperty("type")] + string Type { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/PageParentResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/PageParentResponse.cs new file mode 100644 index 00000000..554b2407 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/PageParentResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PageParentResponse : IParentOfDatabaseResponse + { + public string Type { get; set; } = "page_id"; + + [JsonProperty("page_id")] + public string PageId { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/WorkspaceParentResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/WorkspaceParentResponse.cs new file mode 100644 index 00000000..2c715f13 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/WorkspaceParentResponse.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class WorkspaceParentResponse : IParentOfDatabaseResponse + { + public string Type { get; set; } = "workspace"; + + [JsonProperty("workspace")] + public bool Workspace { get; set; } = true; + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/ButtonDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/ButtonDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..d6c98978 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/ButtonDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ButtonDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Button; + + [JsonProperty("button")] + public Dictionary Button { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CheckboxDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CheckboxDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..30683558 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CheckboxDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CheckboxDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Checkbox; + + [JsonProperty("checkbox")] + public Dictionary Checkbox { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedByDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedByDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..96baeacc --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedByDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedByDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.CreatedBy; + + [JsonProperty("created_by")] + public Dictionary CreatedBy { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedTimeDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedTimeDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..b6933269 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/CreatedTimeDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedTimeDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.CreatedTime; + + [JsonProperty("created_time")] + public Dictionary CreatedTime { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..b925006b --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using JsonSubTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CheckboxDataSourcePropertyConfigResponse), DataSourcePropertyType.Checkbox)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedByDataSourcePropertyConfigResponse), DataSourcePropertyType.CreatedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(CreatedTimeDataSourcePropertyConfigResponse), DataSourcePropertyType.CreatedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DateDataSourcePropertyConfigResponse), DataSourcePropertyType.Date)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(EmailDataSourcePropertyConfigResponse), DataSourcePropertyType.Email)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FilesDataSourcePropertyConfigResponse), DataSourcePropertyType.Files)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(FormulaDataSourcePropertyConfigResponse), DataSourcePropertyType.Formula)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedByDataSourcePropertyConfigResponse), DataSourcePropertyType.LastEditedBy)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(LastEditedTimeDataSourcePropertyConfigResponse), DataSourcePropertyType.LastEditedTime)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(MultiSelectDataSourcePropertyConfigResponse), DataSourcePropertyType.MultiSelect)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(NumberDataSourcePropertyConfigResponse), DataSourcePropertyType.Number)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PeopleDataSourcePropertyConfigResponse), DataSourcePropertyType.People)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PhoneNumberDataSourcePropertyConfigResponse), DataSourcePropertyType.PhoneNumber)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RelationDataSourcePropertyConfigResponse), DataSourcePropertyType.Relation)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RichTextDataSourcePropertyConfigResponse), DataSourcePropertyType.RichText)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(RollupDataSourcePropertyConfigResponse), DataSourcePropertyType.Rollup)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SelectDataSourcePropertyConfigResponse), DataSourcePropertyType.Select)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(StatusDataSourcePropertyConfigResponse), DataSourcePropertyType.Status)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(TitleDataSourcePropertyConfigResponse), DataSourcePropertyType.Title)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UrlDataSourcePropertyConfigResponse), DataSourcePropertyType.Url)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(UniqueIdDataSourcePropertyConfigResponse), DataSourcePropertyType.UniqueId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(ButtonDataSourcePropertyConfigResponse), DataSourcePropertyType.Button)] + public class DataSourcePropertyConfigResponse + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public virtual string Type { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyType.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyType.cs new file mode 100644 index 00000000..79633208 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyType.cs @@ -0,0 +1,28 @@ +namespace Notion.Client +{ + public static class DataSourcePropertyType + { + public const string Title = "title"; + public const string RichText = "rich_text"; + public const string Number = "number"; + public const string Select = "select"; + public const string MultiSelect = "multi_select"; + public const string Date = "date"; + public const string People = "people"; + public const string Files = "files"; + public const string Checkbox = "checkbox"; + public const string Url = "url"; + public const string Email = "email"; + public const string PhoneNumber = "phone_number"; + public const string Formula = "formula"; + public const string Relation = "relation"; + public const string Rollup = "rollup"; + public const string CreatedTime = "created_time"; + public const string CreatedBy = "created_by"; + public const string LastEditedBy = "last_edited_by"; + public const string LastEditedTime = "last_edited_time"; + public const string Status = "status"; + public const string UniqueId = "unique_id"; + public const string Button = "button"; + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DateDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DateDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..433c6f24 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DateDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DateDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Date; + + [JsonProperty("date")] + public Dictionary Date { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/EmailDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/EmailDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..af60e018 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/EmailDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EmailDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Email; + + [JsonProperty("email")] + public Dictionary Email { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FilesDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FilesDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..5af49732 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FilesDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FilesDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Files; + + [JsonProperty("files")] + public Dictionary Files { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FormulaDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FormulaDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..af42e2a5 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/FormulaDataSourcePropertyConfigResponse.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FormulaDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Formula; + + [JsonProperty("formula")] + public FormulaResponse Formula { get; set; } + } + + public class FormulaResponse + { + [JsonProperty("expression")] + public string Expression { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedByDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedByDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..1e42ca2f --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedByDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedByDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.LastEditedBy; + + [JsonProperty("last_edited_by")] + public Dictionary LastEditedBy { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedTimeDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedTimeDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..e7e6acf0 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/LastEditedTimeDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedTimeDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.LastEditedTime; + + [JsonProperty("last_edited_time")] + public Dictionary LastEditedTime { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/MultiSelectDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/MultiSelectDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..eb0a708d --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/MultiSelectDataSourcePropertyConfigResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class MultiSelectDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.MultiSelect; + + [JsonProperty("multi_select")] + public OptionWrapper MultiSelect { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/NumberDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/NumberDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..0dcd7de6 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/NumberDataSourcePropertyConfigResponse.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class NumberDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Number; + + [JsonProperty("number")] + public NumberResponse Number { get; set; } + } + + public class NumberResponse + { + [JsonProperty("format")] + public string Format { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PeopleDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PeopleDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..00124a83 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PeopleDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PeopleDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.People; + + [JsonProperty("people")] + public Dictionary People { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PhoneNumberDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PhoneNumberDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..a7de1096 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/PhoneNumberDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PhoneNumberDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.PhoneNumber; + + [JsonProperty("phone_number")] + public Dictionary PhoneNumber { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/DualPropertyRelationResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/DualPropertyRelationResponse.cs new file mode 100644 index 00000000..c042dcd1 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/DualPropertyRelationResponse.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DualPropertyRelationResponse : RelationDataResponse + { + public override string Type => "dual_property"; + + [JsonProperty("dual_property")] + public Data DualProperty { get; set; } + + public class Data + { + [JsonProperty("synced_property_name")] + public string SyncedPropertyName { get; set; } + + [JsonProperty("synced_property_id")] + public string SyncedPropertyId { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs new file mode 100644 index 00000000..19d8877f --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using JsonSubTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(SinglePropertyRelationResponse), "single_property")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DualPropertyRelationResponse), "dual_property")] + public abstract class RelationDataResponse + { + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] + public virtual string Type { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..ab8754d0 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataSourcePropertyConfigResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RelationDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Relation; + + [JsonProperty("relation")] + public RelationDataResponse Relation { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/SinglePropertyRelationResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/SinglePropertyRelationResponse.cs new file mode 100644 index 00000000..c50a75e9 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/SinglePropertyRelationResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SinglePropertyRelationResponse : RelationDataResponse + { + public override string Type => "single_property"; + + [JsonProperty("single_property")] + public Dictionary SingleProperty { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RichTextDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RichTextDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..5d53cbe4 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RichTextDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RichTextDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.RichText; + + [JsonProperty("rich_text")] + public Dictionary RichText { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RollupDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RollupDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..afdad4a8 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RollupDataSourcePropertyConfigResponse.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RollupDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Rollup; + + [JsonProperty("rollup")] + public RollupResponse Rollup { get; set; } + } + + public class RollupResponse + { + [JsonProperty("relation_property_name")] + public string RelationPropertyName { get; set; } + + [JsonProperty("relation_property_id")] + public string RelationPropertyId { get; set; } + + [JsonProperty("rollup_property_name")] + public string RollupPropertyName { get; set; } + + [JsonProperty("rollup_property_id")] + public string RollupPropertyId { get; set; } + + [JsonProperty("function")] + public string Function { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/SelectDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/SelectDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..ee7e6af4 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/SelectDataSourcePropertyConfigResponse.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + [SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")] + public class SelectDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Select; + + public OptionWrapper Select { get; set; } + } + + public class SelectOptionResponse + { + /// + /// Name of the option as it appears in Notion. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// ID of the option. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Color of the option. Possible values are: "default", "gray", "brown", "red", "orange", "yellow", "green", "blue", + /// "purple", "pink". Defaults to "default". + /// + [JsonProperty("color")] + [JsonConverter(typeof(StringEnumConverter))] + public Color? Color { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/StatusDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/StatusDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..727fc2a2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/StatusDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class StatusDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Status; + + [JsonProperty("status")] + public Dictionary Status { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/TitleDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/TitleDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..23f2fc68 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/TitleDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class TitleDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Title; + + [JsonProperty("title")] + public Dictionary Title { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UniqueIdDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UniqueIdDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..4ceac5ba --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UniqueIdDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UniqueIdDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.UniqueId; + + [JsonProperty("unique_id")] + public Dictionary UniqueId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UrlDataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UrlDataSourcePropertyConfigResponse.cs new file mode 100644 index 00000000..5e25eaa9 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/UrlDataSourcePropertyConfigResponse.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UrlDataSourcePropertyConfigResponse : DataSourcePropertyConfigResponse + { + public override string Type => DataSourcePropertyType.Url; + + [JsonProperty("url")] + public Dictionary Url { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Retrieve/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/Retrieve/DataSourcesClient.cs new file mode 100644 index 00000000..41412911 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Retrieve/DataSourcesClient.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DataSourcesClient + { + public async Task RetrieveAsync( + RetrieveDataSourceRequest request, + CancellationToken cancellationToken = default) + { + IRetrieveDataSourcePathParameters pathParameters = request; + + if (pathParameters == null) + { + throw new ArgumentNullException(nameof(pathParameters)); + } + + if (string.IsNullOrWhiteSpace(pathParameters.DataSourceId)) + { + throw new ArgumentException("DataSourceId cannot be null or empty.", nameof(pathParameters.DataSourceId)); + } + + var endpoint = ApiEndpoints.DataSourcesApiUrls.Retrieve(pathParameters); + + return await _restClient.GetAsync(endpoint, cancellationToken: cancellationToken); + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Retrieve/Request/IRetrieveDataSourcePathParameters.cs b/Src/Notion.Client/Api/DataSources/Retrieve/Request/IRetrieveDataSourcePathParameters.cs new file mode 100644 index 00000000..fcf97aaf --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Retrieve/Request/IRetrieveDataSourcePathParameters.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public interface IRetrieveDataSourcePathParameters + { + string DataSourceId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Retrieve/Request/RetrieveDataSourceRequest.cs b/Src/Notion.Client/Api/DataSources/Retrieve/Request/RetrieveDataSourceRequest.cs new file mode 100644 index 00000000..8d5d2727 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Retrieve/Request/RetrieveDataSourceRequest.cs @@ -0,0 +1,7 @@ +namespace Notion.Client +{ + public class RetrieveDataSourceRequest : IRetrieveDataSourcePathParameters + { + public string DataSourceId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Retrieve/Response/RetrieveDataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Retrieve/Response/RetrieveDataSourceResponse.cs new file mode 100644 index 00000000..88a15e6a --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Retrieve/Response/RetrieveDataSourceResponse.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + public class RetrieveDataSourceResponse : DataSourceResponse + { + } +} diff --git a/Src/Notion.Client/Models/ObjectType.cs b/Src/Notion.Client/Models/ObjectType.cs index 61188a31..f3db8cf9 100644 --- a/Src/Notion.Client/Models/ObjectType.cs +++ b/Src/Notion.Client/Models/ObjectType.cs @@ -21,5 +21,8 @@ public enum ObjectType [EnumMember(Value = "file_upload")] FileUpload, + + [EnumMember(Value = "data_source")] + DataSource, } } diff --git a/Test/Notion.UnitTests/DataSourcesClientTests.cs b/Test/Notion.UnitTests/DataSourcesClientTests.cs new file mode 100644 index 00000000..90b818ed --- /dev/null +++ b/Test/Notion.UnitTests/DataSourcesClientTests.cs @@ -0,0 +1,90 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Moq; +using Moq.AutoMock; +using Notion.Client; +using Xunit; + +namespace Notion.UnitTests; + +public class DataSourcesClientTests +{ + private readonly AutoMocker _mocker = new(); + private readonly Mock _restClient; + private readonly IDataSourcesClient _dataSourcesClient; + private readonly CancellationToken _cancellationToken = CancellationToken.None; + + public DataSourcesClientTests() + { + _restClient = _mocker.GetMock(); + _dataSourcesClient = _mocker.CreateInstance(); + } + + #region RetrieveAsync Tests + + [Fact] + public async Task RetrieveAsync_ShouldThrowArgumentNullException_WhenRequestIsNull() + { + // Arrange + RetrieveDataSourceRequest request = null; + + // Act & Assert + await Assert.ThrowsAsync(() => _dataSourcesClient.RetrieveAsync(request, _cancellationToken)); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData(null)] + public async Task RetrieveAsync_ShouldThrowArgumentException_WhenDataSourceIdIsInvalid(string dataSourceId) + { + // Arrange + var request = new RetrieveDataSourceRequest + { + DataSourceId = dataSourceId + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => _dataSourcesClient.RetrieveAsync(request, _cancellationToken)); + Assert.Equal("DataSourceId cannot be null or empty. (Parameter 'DataSourceId')", exception.Message); + } + + [Fact] + public async Task RetrieveAsync_ShouldReturnDataSource() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var expectedDataSource = new RetrieveDataSourceResponse + { + Id = dataSourceId, + Title = new RichTextBase[] + { + new RichTextText + { + Text = new Text + { + Content = "Test Data Source" + } + } + } + }; + + var request = new RetrieveDataSourceRequest + { + DataSourceId = dataSourceId + }; + + _restClient + .Setup(client => client.GetAsync(ApiEndpoints.DataSourcesApiUrls.Retrieve(request), null, null, null, _cancellationToken)) + .ReturnsAsync(expectedDataSource); + + // Act + var result = await _dataSourcesClient.RetrieveAsync(request, _cancellationToken); + + // Assert + Assert.Equal(expectedDataSource, result); + } + + #endregion RetrieveAsync Tests +} \ No newline at end of file From 315920579d042980dddf76709e7bf7c2db37c63e Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:00:53 +0530 Subject: [PATCH 03/27] Add missing description property in DataSourcePropertyConfigResponse model --- .../Models/PropertyConfig/DataSourcePropertyConfigResponse.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs index b925006b..8f64dfa7 100644 --- a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/DataSourcePropertyConfigResponse.cs @@ -40,6 +40,9 @@ public class DataSourcePropertyConfigResponse [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("description")] + public string Description { get; set; } + [JsonExtensionData] public IDictionary AdditionalData { get; set; } } From bac7842cc299f68b70530bbb89a0cd177027792a Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:03:05 +0530 Subject: [PATCH 04/27] Add support for data source create api --- Src/Notion.Client/Api/ApiEndpoints.cs | 8 +++- .../DataSources/Create/DataSourcesClient.cs | 47 +++++++++++++++++++ .../Create/Request/CreateDataSourceRequest.cs | 12 +++++ .../ICreateDataSourceBodyParameters.cs | 20 ++++++++ .../Response/CreateDataSourceResponse.cs | 6 +++ .../Api/DataSources/IDataSourcesClient.cs | 11 +++++ .../Parents/IParentOfDatabaseResponse.cs | 8 +++- .../PageIcon/CustomEmojiPageIconRequest.cs | 21 +++++++++ .../Request/PageIcon/CustomEmojiRequest.cs | 24 ++++++++++ .../Request/PageIcon/EmojiPageIconRequest.cs | 21 +++++++++ .../PageIcon/ExternalPageIconRequest.cs | 34 ++++++++++++++ .../Request/PageIcon/FileUploadIconRequest.cs | 34 ++++++++++++++ .../Request/PageIcon/IPageIconRequest.cs | 18 +++++++ .../Request/Parents/DatabaseParentRequest.cs | 21 +++++++++ .../Parents/IParentOfDataSourceRequest.cs | 18 +++++++ .../ButtonPropertyConfigurationRequest.cs | 14 ++++++ .../CheckboxPropertyConfigurationRequest.cs | 14 ++++++ .../CreatedByPropertyConfigurationRequest.cs | 14 ++++++ ...CreatedTimePropertyConfigurationRequest.cs | 14 ++++++ .../DatePropertyConfigurationRequest.cs | 14 ++++++ .../DualPropertyRelationDataRequest.cs | 23 +++++++++ .../EmailPropertyConfigurationRequest.cs | 14 ++++++ .../FilesPropertyConfigurationRequest.cs | 14 ++++++ .../FormulaPropertyConfigurationRequest.cs | 27 +++++++++++ .../IRelationDataRequest.cs | 21 +++++++++ ...astEditedByPropertyConfigurationRequest.cs | 14 ++++++ ...tEditedTimePropertyConfigurationRequest.cs | 14 ++++++ ...VisitedTimePropertyConfigurationRequest.cs | 14 ++++++ .../LocationPropertyConfigurationRequest.cs | 14 ++++++ ...MultiSelectPropertyConfigurationRequest.cs | 27 +++++++++++ .../NumberPropertyConfigurationRequest.cs | 27 +++++++++++ .../PeoplePropertyConfigurationRequest.cs | 14 ++++++ ...PhoneNumberPropertyConfigurationRequest.cs | 14 ++++++ .../PlacePropertyConfigurationRequest.cs | 14 ++++++ .../PropertyConfigurationRequest.cs | 21 +++++++++ .../RelationPropertyConfigurationRequest.cs | 13 +++++ .../RichTextPropertyConfigurationRequest.cs | 14 ++++++ .../RollupPropertyConfigurationRequest.cs | 39 +++++++++++++++ .../SelectOptionRequest.cs | 24 ++++++++++ .../SelectPropertyConfigurationRequest.cs | 27 +++++++++++ .../SinglePropertyRelationDataRequest.cs | 23 +++++++++ .../StatusPropertyConfigurationRequest.cs | 14 ++++++ .../TitlePropertyConfigurationRequest.cs | 14 ++++++ .../UniqueIdPropertyConfigurationRequest.cs | 27 +++++++++++ .../UrlPropertyConfigurationRequest.cs | 14 ++++++ ...erificationPropertyConfigurationRequest.cs | 14 ++++++ Src/Notion.Client/Constants.cs | 2 +- 47 files changed, 866 insertions(+), 4 deletions(-) create mode 100644 Src/Notion.Client/Api/DataSources/Create/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/Create/Request/CreateDataSourceRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Create/Request/ICreateDataSourceBodyParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Create/Response/CreateDataSourceResponse.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiPageIconRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/EmojiPageIconRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/ExternalPageIconRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/FileUploadIconRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/IPageIconRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/Parents/IParentOfDataSourceRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/ButtonPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CheckboxPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedByPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedTimePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DatePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/EmailPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FilesPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FormulaPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/IRelationDataRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedByPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedTimePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastVisitedTimePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LocationPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/MultiSelectPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/NumberPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PeoplePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PhoneNumberPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PlacePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RelationPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RichTextPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RollupPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectOptionRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SinglePropertyRelationDataRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/StatusPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/TitlePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UniqueIdPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UrlPropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/VerificationPropertyConfigurationRequest.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 9084781e..c1f30ee7 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -1,4 +1,6 @@ -namespace Notion.Client +using System; + +namespace Notion.Client { public static class ApiEndpoints { @@ -151,7 +153,9 @@ public static class FileUploadsApiUrls public static class DataSourcesApiUrls { - public static string Retrieve(IRetrieveDataSourcePathParameters pathParameters) => $"/v1/data_sources/{pathParameters.DataSourceId}"; + private const string BasePath = "/v1/data_sources"; + public static string Retrieve(IRetrieveDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; + internal static string CreateDataSource() => BasePath; } } } diff --git a/Src/Notion.Client/Api/DataSources/Create/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/Create/DataSourcesClient.cs new file mode 100644 index 00000000..d0c418b9 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Create/DataSourcesClient.cs @@ -0,0 +1,47 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DataSourcesClient + { + public async Task CreateAsync( + CreateDataSourceRequest request, + CancellationToken cancellationToken = default) + { + var endpoint = ApiEndpoints.DataSourcesApiUrls.CreateDataSource(); + + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + ICreateDataSourceBodyParameters body = request; + + if (body.Parent == null) + { + throw new ArgumentNullException(nameof(body.Parent), "Parent property cannot be null."); + } + + if (body.Parent is DatabaseParentRequest dbParentRequest) + { + if (string.IsNullOrWhiteSpace(dbParentRequest.DatabaseId)) + { + throw new ArgumentException("DatabaseId in Parent cannot be null or empty when Parent is of type DatabaseParentRequest.", nameof(request.Parent)); + } + } + + if (body.Properties == null) + { + throw new ArgumentException("Properties cannot be null or empty.", nameof(body.Properties)); + } + + return await _restClient.PostAsync( + endpoint, + body, + cancellationToken: cancellationToken + ); + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Create/Request/CreateDataSourceRequest.cs b/Src/Notion.Client/Api/DataSources/Create/Request/CreateDataSourceRequest.cs new file mode 100644 index 00000000..7ec80efe --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Create/Request/CreateDataSourceRequest.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace Notion.Client +{ + public class CreateDataSourceRequest : ICreateDataSourceBodyParameters + { + public IParentOfDataSourceRequest Parent { get; set; } + public IDictionary Properties { get; set; } + public IEnumerable Title { get; set; } + public IPageIconRequest Icon { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Create/Request/ICreateDataSourceBodyParameters.cs b/Src/Notion.Client/Api/DataSources/Create/Request/ICreateDataSourceBodyParameters.cs new file mode 100644 index 00000000..818b65bd --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Create/Request/ICreateDataSourceBodyParameters.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface ICreateDataSourceBodyParameters + { + [JsonProperty("parent")] + public IParentOfDataSourceRequest Parent { get; set; } + + [JsonProperty("properties")] + public IDictionary Properties { get; set; } + + [JsonProperty("title")] + public IEnumerable Title { get; set; } + + [JsonProperty("icon")] + public IPageIconRequest Icon { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Create/Response/CreateDataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Create/Response/CreateDataSourceResponse.cs new file mode 100644 index 00000000..c9e10d96 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Create/Response/CreateDataSourceResponse.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + public class CreateDataSourceResponse : DataSourceResponse + { + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs index ad3151e7..79fd0cfe 100644 --- a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -15,5 +15,16 @@ Task RetrieveAsync( RetrieveDataSourceRequest request, CancellationToken cancellationToken = default ); + + /// + /// Creates a new data source. + /// + /// + /// + /// + Task CreateAsync( + CreateDataSourceRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs index e28f785e..380ab5ca 100644 --- a/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs +++ b/Src/Notion.Client/Api/DataSources/Models/Parents/IParentOfDatabaseResponse.cs @@ -1,7 +1,13 @@ -using Newtonsoft.Json; +using JsonSubTypes; +using Newtonsoft.Json; namespace Notion.Client { + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DatabaseParentResponse), "database_id")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParentResponse), "page_id")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceParentResponse), "workspace")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParentResponse), "block_id")] public interface IParentOfDatabaseResponse { [JsonProperty("type")] diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiPageIconRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiPageIconRequest.cs new file mode 100644 index 00000000..7764f461 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiPageIconRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmojiPageIconRequest : IPageIconRequest + { + [JsonProperty("type")] + public string Type => "custom_emoji"; + + [JsonProperty("custom_emoji")] + public CustomEmojiRequest CustomEmoji { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiRequest.cs new file mode 100644 index 00000000..d3840836 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/CustomEmojiRequest.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CustomEmojiRequest + { + [JsonProperty("id")] + public string Id { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("url")] + public string Url { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/EmojiPageIconRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/EmojiPageIconRequest.cs new file mode 100644 index 00000000..b343bbd8 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/EmojiPageIconRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EmojiPageIconRequest : IPageIconRequest + { + [JsonProperty("type")] + public string Type => "emoji"; + + [JsonProperty("emoji")] + public string Emoji { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/ExternalPageIconRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/ExternalPageIconRequest.cs new file mode 100644 index 00000000..da7ceded --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/ExternalPageIconRequest.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ExternalPageIconRequest : IPageIconRequest + { + [JsonProperty("type")] + public string Type => "external"; + + [JsonProperty("external")] + public ExternalUrl External { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + + public class ExternalUrl + { + [JsonProperty("url")] + public string Url { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/FileUploadIconRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/FileUploadIconRequest.cs new file mode 100644 index 00000000..bbfd5f74 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/FileUploadIconRequest.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FileUploadIconRequest : IPageIconRequest + { + [JsonProperty("type")] + public string Type => "file_upload"; + + [JsonProperty("file_upload")] + public FileUploadRequest FileUpload { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + + public class FileUploadRequest + { + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/IPageIconRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/IPageIconRequest.cs new file mode 100644 index 00000000..5973a09b --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PageIcon/IPageIconRequest.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IPageIconRequest + { + [JsonProperty("type")] + public string Type { get; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs new file mode 100644 index 00000000..312302d2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DatabaseParentRequest : IParentOfDataSourceRequest + { + [JsonProperty("type")] + public string Type => "database_id"; + + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/Parents/IParentOfDataSourceRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/Parents/IParentOfDataSourceRequest.cs new file mode 100644 index 00000000..48d5378c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/Parents/IParentOfDataSourceRequest.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IParentOfDataSourceRequest + { + [JsonProperty("type")] + public string Type { get; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/ButtonPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/ButtonPropertyConfigurationRequest.cs new file mode 100644 index 00000000..f1797176 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/ButtonPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ButtonPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "button"; + + [JsonProperty("button")] + public IDictionary Button { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CheckboxPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CheckboxPropertyConfigurationRequest.cs new file mode 100644 index 00000000..6702f325 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CheckboxPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CheckboxPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "checkbox"; + + [JsonProperty("checkbox")] + public IDictionary Checkbox { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedByPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedByPropertyConfigurationRequest.cs new file mode 100644 index 00000000..cfbc4271 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedByPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedByPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "created_by"; + + [JsonProperty("created_by")] + public IDictionary CreatedBy { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedTimePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedTimePropertyConfigurationRequest.cs new file mode 100644 index 00000000..420e2676 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/CreatedTimePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedTimePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "created_time"; + + [JsonProperty("created_time")] + public IDictionary CreatedTime { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DatePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DatePropertyConfigurationRequest.cs new file mode 100644 index 00000000..abc347b0 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DatePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DatePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "date"; + + [JsonProperty("date")] + public IDictionary Date { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs new file mode 100644 index 00000000..9a7fb231 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DualPropertyRelationDataRequest : IRelationDataRequest + { + public string DataSourceId { get; set; } + + [JsonProperty("type")] + public string Type => "dual_property"; + + [JsonProperty("dual_property")] + public IDictionary DualProperty { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/EmailPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/EmailPropertyConfigurationRequest.cs new file mode 100644 index 00000000..43017087 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/EmailPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class EmailPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "email"; + + [JsonProperty("email")] + public IDictionary Email { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FilesPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FilesPropertyConfigurationRequest.cs new file mode 100644 index 00000000..6edf4ece --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FilesPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FilesPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "files"; + + [JsonProperty("files")] + public IDictionary Files { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FormulaPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FormulaPropertyConfigurationRequest.cs new file mode 100644 index 00000000..476b2f22 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/FormulaPropertyConfigurationRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class FormulaPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "formula"; + + [JsonProperty("formula")] + public FormulaPropertyConfiguration Formula { get; set; } + + public class FormulaPropertyConfiguration + { + [JsonProperty("expression")] + public string Expression { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/IRelationDataRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/IRelationDataRequest.cs new file mode 100644 index 00000000..aad0407c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/IRelationDataRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IRelationDataRequest + { + [JsonProperty("data_source_id")] + string DataSourceId { get; set; } + + [JsonProperty("type")] + string Type { get; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedByPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedByPropertyConfigurationRequest.cs new file mode 100644 index 00000000..ed685597 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedByPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedByPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "last_edited_by"; + + [JsonProperty("last_edited_by")] + public IDictionary LastEditedBy { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedTimePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedTimePropertyConfigurationRequest.cs new file mode 100644 index 00000000..fcf2ffce --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastEditedTimePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedTimePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "last_edited_time"; + + [JsonProperty("last_edited_time")] + public IDictionary LastEditedTime { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastVisitedTimePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastVisitedTimePropertyConfigurationRequest.cs new file mode 100644 index 00000000..a075a5b3 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LastVisitedTimePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastVisitedTimePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "last_visited_time"; + + [JsonProperty("last_visited_time")] + public IDictionary LastVisitedTime { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LocationPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LocationPropertyConfigurationRequest.cs new file mode 100644 index 00000000..d17e5d5e --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/LocationPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LocationPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "location"; + + [JsonProperty("location")] + public IDictionary Location { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/MultiSelectPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/MultiSelectPropertyConfigurationRequest.cs new file mode 100644 index 00000000..01a7bd84 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/MultiSelectPropertyConfigurationRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class MultiSelectPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "multi_select"; + + [JsonProperty("multi_select")] + public MultiSelectOptions MultiSelect { get; set; } + + public class MultiSelectOptions + { + [JsonProperty("options")] + public IEnumerable Options { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/NumberPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/NumberPropertyConfigurationRequest.cs new file mode 100644 index 00000000..24d78aa2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/NumberPropertyConfigurationRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class NumberPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "number"; + + [JsonProperty("number")] + public NumberFormat Number { get; set; } + + public class NumberFormat + { + [JsonProperty("format")] + public string Format { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PeoplePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PeoplePropertyConfigurationRequest.cs new file mode 100644 index 00000000..2f6f9161 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PeoplePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PeoplePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "people"; + + [JsonProperty("people")] + public IDictionary People { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PhoneNumberPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PhoneNumberPropertyConfigurationRequest.cs new file mode 100644 index 00000000..98622827 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PhoneNumberPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PhoneNumberPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "phone_number"; + + [JsonProperty("phone_number")] + public IDictionary PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PlacePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PlacePropertyConfigurationRequest.cs new file mode 100644 index 00000000..287e6d14 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PlacePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PlacePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "place"; + + [JsonProperty("place")] + public IDictionary Place { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PropertyConfigurationRequest.cs new file mode 100644 index 00000000..e7cab7d2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/PropertyConfigurationRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PropertyConfigurationRequest + { + [JsonProperty("type")] + public virtual string Type { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RelationPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RelationPropertyConfigurationRequest.cs new file mode 100644 index 00000000..4e8524b2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RelationPropertyConfigurationRequest.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RelationPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "relation"; + + [JsonProperty("relation")] + public IRelationDataRequest Relation { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RichTextPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RichTextPropertyConfigurationRequest.cs new file mode 100644 index 00000000..00007987 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RichTextPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RichTextPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "rich_text"; + + [JsonProperty("rich_text")] + public IDictionary RichText { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RollupPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RollupPropertyConfigurationRequest.cs new file mode 100644 index 00000000..fc25d45c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/RollupPropertyConfigurationRequest.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class RollupPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "rollup"; + + [JsonProperty("rollup")] + public RollupOptions Rollup { get; set; } + + public class RollupOptions + { + [JsonProperty("relation_property_name")] + public string RelationPropertyName { get; set; } + + [JsonProperty("relation_property_id")] + public string RelationPropertyId { get; set; } + + [JsonProperty("rollup_property_name")] + public string RollupPropertyName { get; set; } + + [JsonProperty("rollup_property_id")] + public string RollupPropertyId { get; set; } + + [JsonProperty("function")] + public string Function { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectOptionRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectOptionRequest.cs new file mode 100644 index 00000000..b634bd90 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectOptionRequest.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SelectOptionRequest + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("color")] + public string Color { get; set; } + + [JsonProperty("description")] + public string Description { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectPropertyConfigurationRequest.cs new file mode 100644 index 00000000..72e97f82 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SelectPropertyConfigurationRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SelectPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "select"; + + [JsonProperty("select")] + public SelectOptions Select { get; set; } + + public class SelectOptions + { + [JsonProperty("options")] + public IEnumerable Options { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SinglePropertyRelationDataRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SinglePropertyRelationDataRequest.cs new file mode 100644 index 00000000..308730e3 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/SinglePropertyRelationDataRequest.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class SinglePropertyRelationDataRequest : IRelationDataRequest + { + public string DataSourceId { get; set; } + + [JsonProperty("type")] + public string Type => "single_property"; + + [JsonProperty("single_property")] + public IDictionary SingleProperty { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/StatusPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/StatusPropertyConfigurationRequest.cs new file mode 100644 index 00000000..d3070876 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/StatusPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class StatusPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "status"; + + [JsonProperty("status")] + public IDictionary Status { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/TitlePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/TitlePropertyConfigurationRequest.cs new file mode 100644 index 00000000..2da48a11 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/TitlePropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class TitlePropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "title"; + + [JsonProperty("title")] + public IDictionary Title { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UniqueIdPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UniqueIdPropertyConfigurationRequest.cs new file mode 100644 index 00000000..bc2a8c42 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UniqueIdPropertyConfigurationRequest.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UniqueIdPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "unique_id"; + + [JsonProperty("unique_id")] + public UniqueIdConfiguration UniqueId { get; set; } + + public class UniqueIdConfiguration + { + [JsonProperty("prefix")] + public string Prefix { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UrlPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UrlPropertyConfigurationRequest.cs new file mode 100644 index 00000000..cd8746c4 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/UrlPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UrlPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "url"; + + [JsonProperty("url")] + public IDictionary Url { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/VerificationPropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/VerificationPropertyConfigurationRequest.cs new file mode 100644 index 00000000..b6383e2a --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/VerificationPropertyConfigurationRequest.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class VerificationPropertyConfigurationRequest : PropertyConfigurationRequest + { + [JsonProperty("type")] + public override string Type => "verification"; + + [JsonProperty("verification")] + public IDictionary Verification { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Constants.cs b/Src/Notion.Client/Constants.cs index 779bcb47..df7dd906 100644 --- a/Src/Notion.Client/Constants.cs +++ b/Src/Notion.Client/Constants.cs @@ -7,6 +7,6 @@ namespace Notion.Client internal static class Constants { internal const string BaseUrl = "https://api.notion.com/"; - internal const string DefaultNotionVersion = "2022-06-28"; + internal const string DefaultNotionVersion = "2025-09-03"; } } From 7d9d895bf6b69e0d9f242739acd3d1b65d7638ce Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:03:28 +0530 Subject: [PATCH 05/27] Add integration test for data source create api --- .../DataSourcesClientTests.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Test/Notion.IntegrationTests/DataSourcesClientTests.cs diff --git a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs new file mode 100644 index 00000000..8385efa7 --- /dev/null +++ b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Notion.Client; +using Xunit; + +namespace Notion.IntegrationTests +{ + public class DataSourcesClientTests : IntegrationTestBase + { + [Fact] + public async Task CreateDataSource_ShouldReturnSuccess() + { + // Arrange + var request = new CreateDataSourceRequest + { + Parent = new DatabaseParentRequest + { + DatabaseId = "" // TODO: Create a test database and set its ID here + }, + Properties = new Dictionary + { + { + "Name", + new TitlePropertyConfigurationRequest { + Description = "The name of the data source", + Title = new Dictionary() + } + } + }, + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Test Data Source" } } + } + }; + + // Act + var response = await Client.DataSources.CreateAsync(request); + + // Assert + Assert.NotNull(response); + Assert.Equal("Test Data Source", response.Title.OfType().First().Text.Content); + Assert.Single(response.Properties); + Assert.True(response.Properties.ContainsKey("Name")); + Assert.Equal("The name of the data source", response.Properties["Name"].Description); + } + } +} \ No newline at end of file From 2463087f5e2472d482af0dbe57a136ccf49a4436 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 9 Nov 2025 16:00:17 +0530 Subject: [PATCH 06/27] Refactor DualPropertyRelationDataRequest to use Data class for DualProperty --- .../DualPropertyRelationDataRequest.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs index 9a7fb231..d46e6181 100644 --- a/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs +++ b/Src/Notion.Client/Api/DataSources/Models/Request/PropertyConfiguration/DualPropertyRelationDataRequest.cs @@ -11,7 +11,7 @@ public class DualPropertyRelationDataRequest : IRelationDataRequest public string Type => "dual_property"; [JsonProperty("dual_property")] - public IDictionary DualProperty { get; set; } + public Data DualProperty { get; set; } /// /// Additional data for future compatibility @@ -19,5 +19,21 @@ public class DualPropertyRelationDataRequest : IRelationDataRequest /// [JsonExtensionData] public IDictionary AdditionalData { get; set; } + + public class Data + { + [JsonProperty("synced_property_id")] + public string SyncedPropertyId { get; set; } + + [JsonProperty("synced_property_name")] + public string SyncedPropertyName { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } } } \ No newline at end of file From 46f15aaa4ff37f5d9b4fb20d008ada75b1178ec9 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 9 Nov 2025 16:54:19 +0530 Subject: [PATCH 07/27] Add update functionality for data sources with corresponding request and response models - Add unit and integration tests --- Src/Notion.Client/Api/ApiEndpoints.cs | 1 + .../Api/DataSources/IDataSourcesClient.cs | 11 + .../DataSources/Update/DataSourcesClient.cs | 35 +++ .../IUpdateDataSourceBodyParameters.cs | 40 +++ .../IUpdateDataSourcePathParameters.cs | 10 + .../IUpdatePropertyConfigurationRequest.cs | 15 ++ .../Request/UpdateDataSourceBodyRequest.cs | 68 +++++ .../Update/Request/UpdateDataSourceRequest.cs | 15 ++ .../UpdatePropertyConfigurationRequest.cs | 19 ++ ...tePropertyConfigurationRequestConverter.cs | 39 +++ ...rtyConfigurationRequestConverterFactory.cs | 44 ++++ .../Response/UpdateDataSourceResponse.cs | 6 + .../DataSourcesClientTests.cs | 86 +++++++ ...nfigurationRequestConverterFactoryTests.cs | 112 +++++++++ ...yConfigurationRequestSerializationTests.cs | 237 ++++++++++++++++++ 15 files changed, 738 insertions(+) create mode 100644 Src/Notion.Client/Api/DataSources/Update/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourceBodyParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourcePathParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/IUpdatePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceBodyRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverter.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverterFactory.cs create mode 100644 Src/Notion.Client/Api/DataSources/Update/Response/UpdateDataSourceResponse.cs create mode 100644 Test/Notion.UnitTests/UpdatePropertyConfigurationRequestConverterFactoryTests.cs create mode 100644 Test/Notion.UnitTests/UpdatePropertyConfigurationRequestSerializationTests.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index c1f30ee7..555ce1cf 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -156,6 +156,7 @@ public static class DataSourcesApiUrls private const string BasePath = "/v1/data_sources"; public static string Retrieve(IRetrieveDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; internal static string CreateDataSource() => BasePath; + internal static string Update(IUpdateDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; } } } diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs index 79fd0cfe..a0b527a0 100644 --- a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -26,5 +26,16 @@ Task CreateAsync( CreateDataSourceRequest request, CancellationToken cancellationToken = default ); + + /// + /// Updates an existing data source. + /// + /// + /// + /// + Task UpdateAsync( + UpdateDataSourceRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/DataSources/Update/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/Update/DataSourcesClient.cs new file mode 100644 index 00000000..b7485cc3 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/DataSourcesClient.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DataSourcesClient + { + public async Task UpdateAsync( + UpdateDataSourceRequest request, + CancellationToken cancellationToken = default) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (request.DataSourceId == null) + { + throw new ArgumentNullException(nameof(request.DataSourceId)); + } + + var path = ApiEndpoints.DataSourcesApiUrls.Update(request); + + // Create a clean body request with only the properties that should be serialized + var bodyRequest = UpdateDataSourceBodyRequest.FromRequest(request); + + return await _restClient.PatchAsync( + path, + bodyRequest, + cancellationToken: cancellationToken + ); + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourceBodyParameters.cs b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourceBodyParameters.cs new file mode 100644 index 00000000..cced986c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourceBodyParameters.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IUpdateDataSourceBodyParameters + { + /// + /// The title of the data source. + /// + IEnumerable Title { get; set; } + + /// + /// Page icon for data source. + /// + IPageIconRequest Icon { get; set; } + + IDictionary Properties { get; set; } + + /// + /// Whether the database should be moved to or from the trash. If not provided, the trash + /// status will not be updated. + /// + [JsonProperty("in_trash")] + bool InTrash { get; set; } + + /// + /// Whether the database should be moved to or from the trash. If not provided, the trash + /// status will not be updated. Equivalent to `in_trash`. + /// + [JsonProperty("archived")] + bool Archived { get; set; } + + /// + /// The parent of the data source. + /// + [JsonProperty("parent")] + IParentOfDataSourceRequest Parent { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourcePathParameters.cs b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourcePathParameters.cs new file mode 100644 index 00000000..63ecc229 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdateDataSourcePathParameters.cs @@ -0,0 +1,10 @@ +namespace Notion.Client +{ + public interface IUpdateDataSourcePathParameters + { + /// + /// The ID of a Notion data source. + /// + string DataSourceId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/IUpdatePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdatePropertyConfigurationRequest.cs new file mode 100644 index 00000000..d37682bf --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/IUpdatePropertyConfigurationRequest.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// Non-generic base interface for update property configuration requests. + /// This allows different property types to be stored in the same collection. + /// + [JsonConverter(typeof(UpdatePropertyConfigurationRequestConverterFactory))] + public interface IUpdatePropertyConfigurationRequest + { + [JsonProperty("name")] + string Name { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceBodyRequest.cs b/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceBodyRequest.cs new file mode 100644 index 00000000..e44e9371 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceBodyRequest.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// Internal concrete implementation of IUpdateDataSourceBodyParameters used for JSON serialization. + /// This class contains only the properties that should be serialized in the request body. + /// + internal class UpdateDataSourceBodyRequest : IUpdateDataSourceBodyParameters + { + /// + /// The title of the data source. + /// + [JsonProperty("title")] + public IEnumerable Title { get; set; } + + /// + /// Page icon for data source. + /// + [JsonProperty("icon")] + public IPageIconRequest Icon { get; set; } + + /// + /// Properties configuration for the data source. + /// + [JsonProperty("properties")] + public IDictionary Properties { get; set; } + + /// + /// Whether the database should be moved to or from the trash. If not provided, the trash + /// status will not be updated. + /// + [JsonProperty("in_trash")] + public bool InTrash { get; set; } + + /// + /// Whether the database should be moved to or from the trash. If not provided, the trash + /// status will not be updated. Equivalent to `in_trash`. + /// + [JsonProperty("archived")] + public bool Archived { get; set; } + + /// + /// The parent of the data source. + /// + [JsonProperty("parent")] + public IParentOfDataSourceRequest Parent { get; set; } + + /// + /// Creates an UpdateDataSourceBodyRequest from an UpdateDataSourceRequest + /// + /// The source request containing all parameters + /// A new UpdateDataSourceBodyRequest with only body parameters + internal static UpdateDataSourceBodyRequest FromRequest(UpdateDataSourceRequest source) + { + return new UpdateDataSourceBodyRequest + { + Title = source.Title, + Icon = source.Icon, + Properties = source.Properties, + InTrash = source.InTrash, + Archived = source.Archived, + Parent = source.Parent + }; + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceRequest.cs b/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceRequest.cs new file mode 100644 index 00000000..6306e49c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/UpdateDataSourceRequest.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace Notion.Client +{ + public class UpdateDataSourceRequest : IUpdateDataSourcePathParameters, IUpdateDataSourceBodyParameters + { + public string DataSourceId { get; set; } + public IEnumerable Title { get; set; } + public IPageIconRequest Icon { get; set; } + public IDictionary Properties { get; set; } + public bool InTrash { get; set; } + public bool Archived { get; set; } + public IParentOfDataSourceRequest Parent { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequest.cs b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequest.cs new file mode 100644 index 00000000..d2ae2b9d --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequest.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(UpdatePropertyConfigurationRequestConverterFactory))] + public class UpdatePropertyConfigurationRequest : IUpdatePropertyConfigurationRequest where T : PropertyConfigurationRequest + { + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// The property configuration details. + /// + /// This object will get flattened into the parent object when serialized. + /// If null or not provided, the property configuration will remain unchanged. + /// + public T PropertyRequest { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverter.cs b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverter.cs new file mode 100644 index 00000000..bfc666f2 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverter.cs @@ -0,0 +1,39 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Notion.Client +{ + // write custom json convert for UpdatePropertyConfigurationRequest to flatten PropertyRequest into parent object + public class UpdatePropertyConfigurationRequestConverter : JsonConverter> where T : PropertyConfigurationRequest + { + public override bool CanRead => false; + + public override void WriteJson(JsonWriter writer, UpdatePropertyConfigurationRequest value, JsonSerializer serializer) + { + writer.WriteStartObject(); + + if (value.Name != null) + { + writer.WritePropertyName("name"); + writer.WriteValue(value.Name); + } + + if (value.PropertyRequest != null) + { + var propertyRequestJson = JObject.FromObject(value.PropertyRequest, serializer); + foreach (var property in propertyRequestJson.Properties()) + { + property.WriteTo(writer); + } + } + + writer.WriteEndObject(); + } + + public override UpdatePropertyConfigurationRequest ReadJson(JsonReader reader, Type objectType, UpdatePropertyConfigurationRequest existingValue, bool hasExistingValue, JsonSerializer serializer) + { + throw new NotImplementedException("Deserialization is not implemented for UpdatePropertyConfigurationRequest."); + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverterFactory.cs b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverterFactory.cs new file mode 100644 index 00000000..11c56231 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Request/UpdatePropertyConfigurationRequestConverterFactory.cs @@ -0,0 +1,44 @@ +using System; +using Newtonsoft.Json; + +namespace Notion.Client +{ + /// + /// Converter factory that creates the appropriate generic converter for UpdatePropertyConfigurationRequest. + /// This solves the issue with open generic types in JsonConverter attributes. + /// + public class UpdatePropertyConfigurationRequestConverterFactory : JsonConverter + { + public override bool CanRead => false; + + public override bool CanWrite => true; + + public override bool CanConvert(Type objectType) + { + return objectType.IsGenericType && + objectType.GetGenericTypeDefinition() == typeof(UpdatePropertyConfigurationRequest<>) && + typeof(PropertyConfigurationRequest).IsAssignableFrom(objectType.GetGenericArguments()[0]); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + var objectType = value.GetType(); + var genericArgument = objectType.GetGenericArguments()[0]; + var converterType = typeof(UpdatePropertyConfigurationRequestConverter<>).MakeGenericType(genericArgument); + var converter = (JsonConverter)Activator.CreateInstance(converterType); + + converter.WriteJson(writer, value, serializer); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException("Deserialization is not implemented for UpdatePropertyConfigurationRequest."); + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Update/Response/UpdateDataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Update/Response/UpdateDataSourceResponse.cs new file mode 100644 index 00000000..3eb5dd46 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Update/Response/UpdateDataSourceResponse.cs @@ -0,0 +1,6 @@ +namespace Notion.Client +{ + public class UpdateDataSourceResponse : DataSourceResponse + { + } +} diff --git a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs index 8385efa7..fbff65b1 100644 --- a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs +++ b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs @@ -44,5 +44,91 @@ public async Task CreateDataSource_ShouldReturnSuccess() Assert.True(response.Properties.ContainsKey("Name")); Assert.Equal("The name of the data source", response.Properties["Name"].Description); } + + // add tests for update + [Fact] + public async Task UpdateDataSource_ShouldReturnSuccess() + { + // Arrange + var createRequest = new CreateDataSourceRequest + { + Parent = new DatabaseParentRequest + { + DatabaseId = "29ee2842ccb5802397b8fdf6fed5ac93" // TODO: Create a test database and set its ID here + }, + Properties = new Dictionary + { + { + "Name", + new TitlePropertyConfigurationRequest { + Description = "The name of the data source", + Title = new Dictionary() + } + }, + { + "Status", + new SelectPropertyConfigurationRequest { + Description = "The status of the data source", + Select = new SelectPropertyConfigurationRequest.SelectOptions + { + Options = new List + { + new() { Name = "Open", Color = "green" }, + new() { Name = "Closed", Color = "red" } + } + } + } + } + }, + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Initial Data Source" } } + } + }; + + var createResponse = await Client.DataSources.CreateAsync(createRequest); + + var updateRequest = new UpdateDataSourceRequest + { + DataSourceId = createResponse.Id, + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Updated Data Source" } } + }, + Properties = new Dictionary + { + { + "Status", + new UpdatePropertyConfigurationRequest + { + Name = "Item Status", + PropertyRequest = new SelectPropertyConfigurationRequest + { + Description = "Updated status of the data source", + Select = new SelectPropertyConfigurationRequest.SelectOptions + { + Options = new List + { + new() { Name = "In Progress", Color = "yellow" }, + new() { Name = "Completed", Color = "blue" } + } + } + } + } + } + } + }; + + // Act + var updateResponse = await Client.DataSources.UpdateAsync(updateRequest); + + // Assert + Assert.NotNull(updateResponse); + Assert.Equal("Updated Data Source", updateResponse.Title.OfType().First().Text.Content); + Assert.Equal(2, updateResponse.Properties.Count); + Assert.True(updateResponse.Properties.ContainsKey("Item Status")); + Assert.True(updateResponse.Properties.ContainsKey("Name")); + } + } } \ No newline at end of file diff --git a/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestConverterFactoryTests.cs b/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestConverterFactoryTests.cs new file mode 100644 index 00000000..5307bc8e --- /dev/null +++ b/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestConverterFactoryTests.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Notion.Client; +using Xunit; + +namespace Notion.UnitTests +{ + public class UpdatePropertyConfigurationRequestConverterFactoryTests + { + [Fact] + public void ConverterFactory_WithSelectProperty_ShouldSerializeCorrectly() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = "Status", + PropertyRequest = new SelectPropertyConfigurationRequest + { + Description = "Task status", + Select = new SelectPropertyConfigurationRequest.SelectOptions + { + Options = new List + { + new SelectOptionRequest { Name = "Done", Color = "green" } + } + } + } + }; + + // Cast to non-generic interface to simulate real usage + IUpdatePropertyConfigurationRequest nonGenericRequest = request; + + // Act + var json = JsonConvert.SerializeObject(nonGenericRequest); + + // Assert + Assert.Contains("\"name\":\"Status\"", json); + Assert.Contains("\"description\":\"Task status\"", json); + Assert.Contains("\"select\"", json); + Assert.Contains("\"options\"", json); + Assert.Contains("\"Done\"", json); + Assert.Contains("\"green\"", json); + } + + [Fact] + public void ConverterFactory_WithTitleProperty_ShouldSerializeCorrectly() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = "Task Name", + PropertyRequest = new TitlePropertyConfigurationRequest + { + Description = "Name of the task" + } + }; + + // Cast to non-generic interface to simulate real usage + IUpdatePropertyConfigurationRequest nonGenericRequest = request; + + // Act + var json = JsonConvert.SerializeObject(nonGenericRequest); + + // Assert + Assert.Contains("\"name\":\"Task Name\"", json); + Assert.Contains("\"description\":\"Name of the task\"", json); + Assert.Contains("\"title\"", json); + } + + [Fact] + public void ConverterFactory_WithDictionary_ShouldSerializeAllProperties() + { + // Arrange + var properties = new Dictionary + { + { + "Status", + new UpdatePropertyConfigurationRequest + { + Name = "Status", + PropertyRequest = new SelectPropertyConfigurationRequest + { + Description = "Task status" + } + } + }, + { + "Title", + new UpdatePropertyConfigurationRequest + { + Name = "Task Name", + PropertyRequest = new TitlePropertyConfigurationRequest + { + Description = "Name of the task" + } + } + } + }; + + // Act + var json = JsonConvert.SerializeObject(properties); + + // Assert + Assert.Contains("\"Status\"", json); + Assert.Contains("\"Title\"", json); + Assert.Contains("\"Task status\"", json); + Assert.Contains("\"Name of the task\"", json); + Assert.Contains("\"select\"", json); + Assert.Contains("\"title\"", json); + } + } +} \ No newline at end of file diff --git a/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestSerializationTests.cs b/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestSerializationTests.cs new file mode 100644 index 00000000..16d224b5 --- /dev/null +++ b/Test/Notion.UnitTests/UpdatePropertyConfigurationRequestSerializationTests.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Notion.Client; +using Xunit; + +namespace Notion.UnitTests; + +public class UpdatePropertyConfigurationRequestSerializationTests +{ + private string SerializeRequest(UpdatePropertyConfigurationRequest request) where T : PropertyConfigurationRequest + { + // Use JsonConvert.SerializeObject directly - this should now work with our converter factory + return JsonConvert.SerializeObject(request); + } + + [Fact] + public void UpdatePropertyConfigurationRequest_Should_Flatten_PropertyRequest_Into_Parent_Object_Via_JsonConvert() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = "Test Property Name", + PropertyRequest = new TitlePropertyConfigurationRequest + { + Type = "title", + Description = "Test description", + Title = new Dictionary + { + { "some_title_config", "value" } + } + } + }; + + // Act - Using JsonConvert.SerializeObject which automatically uses the JsonConverter attribute + var json = SerializeRequest(request); + + // Assert + Assert.Contains("\"name\":\"Test Property Name\"", json); + Assert.Contains("\"type\":\"title\"", json); + Assert.Contains("\"description\":\"Test description\"", json); + Assert.Contains("\"title\":{\"some_title_config\":\"value\"}", json); + + // Verify that PropertyRequest is not present as a separate property + Assert.DoesNotContain("\"PropertyRequest\"", json); + Assert.DoesNotContain("\"propertyRequest\"", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Serialize_Only_Name_When_PropertyRequest_Is_Null() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = "Test Property Name", + PropertyRequest = null + }; + + // Act + var json = SerializeRequest(request); + + // Assert + Assert.Contains("\"name\":\"Test Property Name\"", json); + Assert.DoesNotContain("\"type\"", json); + Assert.DoesNotContain("\"description\"", json); + Assert.DoesNotContain("\"title\"", json); + Assert.DoesNotContain("\"PropertyRequest\"", json); + Assert.DoesNotContain("\"propertyRequest\"", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Serialize_Only_PropertyRequest_Fields_When_Name_Is_Null() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = null, + PropertyRequest = new TitlePropertyConfigurationRequest + { + Type = "title", + Description = "Test description", + Title = new Dictionary + { + { "some_title_config", "value" } + } + } + }; + + // Act + var json = SerializeRequest(request); + + // Assert + Assert.DoesNotContain("\"name\"", json); + Assert.Contains("\"type\":\"title\"", json); + Assert.Contains("\"description\":\"Test description\"", json); + Assert.Contains("\"title\":{\"some_title_config\":\"value\"}", json); + Assert.DoesNotContain("\"PropertyRequest\"", json); + Assert.DoesNotContain("\"propertyRequest\"", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Serialize_Empty_Object_When_Both_Name_And_PropertyRequest_Are_Null() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = null, + PropertyRequest = null + }; + + // Act + var json = SerializeRequest(request); + + // Assert + Assert.Equal("{}", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Flatten_Different_Property_Types() + { + // Test with CheckboxPropertyConfigurationRequest + var checkboxRequest = new UpdatePropertyConfigurationRequest + { + Name = "Checkbox Property", + PropertyRequest = new CheckboxPropertyConfigurationRequest + { + Type = "checkbox", + Description = "Checkbox description", + Checkbox = new Dictionary + { + { "checkbox_config", true } + } + } + }; + + var checkboxJson = SerializeRequest(checkboxRequest); + + Assert.Contains("\"name\":\"Checkbox Property\"", checkboxJson); + Assert.Contains("\"type\":\"checkbox\"", checkboxJson); + Assert.Contains("\"description\":\"Checkbox description\"", checkboxJson); + Assert.Contains("\"checkbox\":{\"checkbox_config\":true}", checkboxJson); + Assert.DoesNotContain("\"PropertyRequest\"", checkboxJson); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Handle_PropertyRequest_With_AdditionalData() + { + // Arrange + var request = new UpdatePropertyConfigurationRequest + { + Name = "Test Property", + PropertyRequest = new TitlePropertyConfigurationRequest + { + Type = "title", + Description = "Test description", + Title = new Dictionary + { + { "some_title_config", "value" } + }, + AdditionalData = new Dictionary + { + { "custom_field", "custom_value" }, + { "another_field", 42 } + } + } + }; + + // Act + var json = SerializeRequest(request); + + // Assert + Assert.Contains("\"name\":\"Test Property\"", json); + Assert.Contains("\"type\":\"title\"", json); + Assert.Contains("\"description\":\"Test description\"", json); + Assert.Contains("\"title\":{\"some_title_config\":\"value\"}", json); + Assert.Contains("\"custom_field\":\"custom_value\"", json); + Assert.Contains("\"another_field\":42", json); + Assert.DoesNotContain("\"PropertyRequest\"", json); + Assert.DoesNotContain("\"AdditionalData\"", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Handle_Complex_Property_Configuration() + { + // Test with UniqueIdPropertyConfigurationRequest which has nested objects + var request = new UpdatePropertyConfigurationRequest + { + Name = "Unique ID Property", + PropertyRequest = new UniqueIdPropertyConfigurationRequest + { + Type = "unique_id", + Description = "Unique ID description", + UniqueId = new UniqueIdPropertyConfigurationRequest.UniqueIdConfiguration + { + Prefix = "TEST-", + AdditionalData = new Dictionary + { + { "nested_field", "nested_value" } + } + } + } + }; + + // Act + var json = SerializeRequest(request); + + // Assert + Assert.Contains("\"name\":\"Unique ID Property\"", json); + Assert.Contains("\"type\":\"unique_id\"", json); + Assert.Contains("\"description\":\"Unique ID description\"", json); + Assert.Contains("\"unique_id\":", json); + Assert.Contains("\"prefix\":\"TEST-\"", json); + Assert.Contains("\"nested_field\":\"nested_value\"", json); + Assert.DoesNotContain("\"PropertyRequest\"", json); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_Should_Not_Support_Reading() + { + // Arrange + var converter = new UpdatePropertyConfigurationRequestConverter(); + + // Act & Assert + Assert.False(converter.CanRead); + } + + [Fact] + public void UpdatePropertyConfigurationRequestConverter_ReadJson_Should_Throw_NotImplementedException() + { + // Arrange + var converter = new UpdatePropertyConfigurationRequestConverter(); + + // Act & Assert + Assert.Throws(() => + converter.ReadJson(null, typeof(UpdatePropertyConfigurationRequest), null, false, new JsonSerializer())); + } +} From e5e7d6ad3a46b5f37d7ffa0f7fca6f2165089f60 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 9 Nov 2025 17:21:29 +0530 Subject: [PATCH 08/27] Add ListDataSourceTemplates api support --- Src/Notion.Client/Api/ApiEndpoints.cs | 1 + .../Api/DataSources/IDataSourcesClient.cs | 11 + .../ListTemplates/DataSourcesClient.cs | 44 +++ .../IListDataSourceTemplatesPathParameters.cs | 10 + ...IListDataSourceTemplatesQueryParameters.cs | 13 + .../Request/ListDataSourceTemplatesRequest.cs | 10 + .../Response/DataSourceTemplate.cs | 25 ++ .../ListDataSourceTemplatesResponse.cs | 26 ++ .../DataSourcesClientTests.cs | 292 +++++++++++++++++- 9 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesPathParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesQueryParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/Request/ListDataSourceTemplatesRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/Response/DataSourceTemplate.cs create mode 100644 Src/Notion.Client/Api/DataSources/ListTemplates/Response/ListDataSourceTemplatesResponse.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 555ce1cf..43e23a81 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -157,6 +157,7 @@ public static class DataSourcesApiUrls public static string Retrieve(IRetrieveDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; internal static string CreateDataSource() => BasePath; internal static string Update(IUpdateDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; + internal static string ListDataSourceTemplates(IListDataSourceTemplatesPathParameters pathParameters) => $"/v1/data-sources/{pathParameters.DataSourceId}/templates"; } } } diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs index a0b527a0..66cc3209 100644 --- a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -37,5 +37,16 @@ Task UpdateAsync( UpdateDataSourceRequest request, CancellationToken cancellationToken = default ); + + /// + /// Lists the templates for a data source. + /// + /// + /// + /// + Task ListDataSourceTemplatesAsync( + ListDataSourceTemplatesRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/DataSourcesClient.cs new file mode 100644 index 00000000..0f1f0e63 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/DataSourcesClient.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DataSourcesClient + { + public async Task ListDataSourceTemplatesAsync( + ListDataSourceTemplatesRequest request, + CancellationToken cancellationToken = default) + { + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } + + if (string.IsNullOrWhiteSpace(request.DataSourceId)) + { + throw new ArgumentException("DataSourceId cannot be null or empty.", nameof(request.DataSourceId)); + } + + IListDataSourceTemplatesPathParameters pathParameters = request; + + var endpoint = ApiEndpoints.DataSourcesApiUrls.ListDataSourceTemplates(pathParameters); + + IListDataSourceTemplatesQueryParameters queryParameters = request; + + var queryParams = new Dictionary() + { + { "name", queryParameters.Name }, + { "start_cursor", queryParameters.StartCursor }, + { "page_size", queryParameters.PageSize?.ToString() } + }; + + return await _restClient.GetAsync( + endpoint, + queryParams: queryParams, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesPathParameters.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesPathParameters.cs new file mode 100644 index 00000000..bc3d8c93 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesPathParameters.cs @@ -0,0 +1,10 @@ +namespace Notion.Client +{ + public interface IListDataSourceTemplatesPathParameters + { + /// + /// The ID of the data source. + /// + public string DataSourceId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesQueryParameters.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesQueryParameters.cs new file mode 100644 index 00000000..b2ceb565 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/IListDataSourceTemplatesQueryParameters.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IListDataSourceTemplatesQueryParameters : IPaginationParameters + { + /// + /// Filter templates by name (case-insensitive substring match). + /// + [JsonProperty("name")] + string Name { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/Request/ListDataSourceTemplatesRequest.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/ListDataSourceTemplatesRequest.cs new file mode 100644 index 00000000..8e6f9315 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/Request/ListDataSourceTemplatesRequest.cs @@ -0,0 +1,10 @@ +namespace Notion.Client +{ + public class ListDataSourceTemplatesRequest : IListDataSourceTemplatesPathParameters, IListDataSourceTemplatesQueryParameters + { + public string DataSourceId { get; set; } + public string Name { get; set; } + public string StartCursor { get; set; } + public int? PageSize { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/Response/DataSourceTemplate.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/Response/DataSourceTemplate.cs new file mode 100644 index 00000000..6470549d --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/Response/DataSourceTemplate.cs @@ -0,0 +1,25 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceTemplate + { + /// + /// The unique identifier of the data source template. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// The name of the data source template. + /// + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Indicates whether the template is the default template for the data source. + /// + [JsonProperty("is_default")] + public bool IsDefault { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/ListTemplates/Response/ListDataSourceTemplatesResponse.cs b/Src/Notion.Client/Api/DataSources/ListTemplates/Response/ListDataSourceTemplatesResponse.cs new file mode 100644 index 00000000..18b579b8 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/ListTemplates/Response/ListDataSourceTemplatesResponse.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class ListDataSourceTemplatesResponse + { + /// + /// A collection of data source templates. + /// + [JsonProperty("templates")] + public IEnumerable Templates { get; set; } + + /// + /// Indicates whether there are more templates to retrieve. + /// + [JsonProperty("has_more")] + public bool HasMore { get; set; } + + /// + /// The cursor to use for fetching the next page of templates. + /// + [JsonProperty("next_cursor")] + public string NextCursor { get; set; } + } +} diff --git a/Test/Notion.UnitTests/DataSourcesClientTests.cs b/Test/Notion.UnitTests/DataSourcesClientTests.cs index 90b818ed..222be014 100644 --- a/Test/Notion.UnitTests/DataSourcesClientTests.cs +++ b/Test/Notion.UnitTests/DataSourcesClientTests.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Moq; @@ -46,7 +48,7 @@ public async Task RetrieveAsync_ShouldThrowArgumentException_WhenDataSourceIdIsI }; // Act & Assert - var exception = await Assert.ThrowsAsync(() => _dataSourcesClient.RetrieveAsync(request, _cancellationToken)); + var exception = await Assert.ThrowsAsync(() => _dataSourcesClient.RetrieveAsync(request, _cancellationToken)); Assert.Equal("DataSourceId cannot be null or empty. (Parameter 'DataSourceId')", exception.Message); } @@ -87,4 +89,292 @@ public async Task RetrieveAsync_ShouldReturnDataSource() } #endregion RetrieveAsync Tests + + #region ListDataSourceTemplatesAsync Tests + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldThrowArgumentNullException_WhenRequestIsNull() + { + // Arrange + ListDataSourceTemplatesRequest request = null; + + // Act & Assert + await Assert.ThrowsAsync(() => _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken)); + } + + [Theory] + [InlineData("")] + [InlineData(" ")] + [InlineData(null)] + public async Task ListDataSourceTemplatesAsync_ShouldThrowArgumentException_WhenDataSourceIdIsInvalid(string dataSourceId) + { + // Arrange + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken)); + Assert.Equal("DataSourceId cannot be null or empty. (Parameter 'DataSourceId')", exception.Message); + } + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldReturnTemplates_WithValidRequest() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var expectedResponse = new ListDataSourceTemplatesResponse + { + Templates = new[] + { + new DataSourceTemplate + { + Id = "template-1", + Name = "Default Template", + IsDefault = true + }, + new DataSourceTemplate + { + Id = "template-2", + Name = "Custom Template", + IsDefault = false + } + }, + HasMore = false, + NextCursor = null + }; + + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId + }; + + var expectedEndpoint = $"/v1/data-sources/{dataSourceId}/templates"; + var expectedQueryParams = new Dictionary + { + { "name", null }, + { "start_cursor", null }, + { "page_size", null } + }; + + _restClient + .Setup(client => client.GetAsync( + expectedEndpoint, + expectedQueryParams, + null, + null, + _cancellationToken)) + .ReturnsAsync(expectedResponse); + + // Act + var result = await _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken); + + // Assert + Assert.Equal(expectedResponse, result); + Assert.Equal(2, result.Templates.Count()); + Assert.False(result.HasMore); + Assert.Null(result.NextCursor); + } + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldPassAllQueryParameters_WhenProvided() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var templateName = "Custom Template"; + var startCursor = "cursor123"; + var pageSize = 50; + + var expectedResponse = new ListDataSourceTemplatesResponse + { + Templates = new[] + { + new DataSourceTemplate + { + Id = "template-1", + Name = templateName, + IsDefault = false + } + }, + HasMore = true, + NextCursor = "next-cursor456" + }; + + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId, + Name = templateName, + StartCursor = startCursor, + PageSize = pageSize + }; + + var expectedEndpoint = $"/v1/data-sources/{dataSourceId}/templates"; + var expectedQueryParams = new Dictionary + { + { "name", templateName }, + { "start_cursor", startCursor }, + { "page_size", pageSize.ToString() } + }; + + _restClient + .Setup(client => client.GetAsync( + expectedEndpoint, + expectedQueryParams, + null, + null, + _cancellationToken)) + .ReturnsAsync(expectedResponse); + + // Act + var result = await _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken); + + // Assert + Assert.Equal(expectedResponse, result); + Assert.Single(result.Templates); + Assert.True(result.HasMore); + Assert.Equal("next-cursor456", result.NextCursor); + + // Verify the REST client was called with correct parameters + _restClient.Verify(client => client.GetAsync( + expectedEndpoint, + expectedQueryParams, + null, + null, + _cancellationToken), Times.Once); + } + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldReturnEmptyTemplates_WhenNoTemplatesFound() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var expectedResponse = new ListDataSourceTemplatesResponse + { + Templates = new DataSourceTemplate[0], + HasMore = false, + NextCursor = null + }; + + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId + }; + + var expectedEndpoint = $"/v1/data-sources/{dataSourceId}/templates"; + + _restClient + .Setup(client => client.GetAsync( + expectedEndpoint, + It.IsAny>(), + null, + null, + _cancellationToken)) + .ReturnsAsync(expectedResponse); + + // Act + var result = await _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken); + + // Assert + Assert.Equal(expectedResponse, result); + Assert.Empty(result.Templates); + Assert.False(result.HasMore); + Assert.Null(result.NextCursor); + } + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldHandleNullPageSize_InQueryParameters() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId, + Name = "Test Template", + StartCursor = "cursor123", + PageSize = null // Explicitly null + }; + + var expectedResponse = new ListDataSourceTemplatesResponse + { + Templates = new DataSourceTemplate[0], + HasMore = false, + NextCursor = null + }; + + var expectedEndpoint = $"/v1/data-sources/{dataSourceId}/templates"; + var expectedQueryParams = new Dictionary + { + { "name", "Test Template" }, + { "start_cursor", "cursor123" }, + { "page_size", null } // Should be null when PageSize is null + }; + + _restClient + .Setup(client => client.GetAsync( + expectedEndpoint, + expectedQueryParams, + null, + null, + _cancellationToken)) + .ReturnsAsync(expectedResponse); + + // Act + var result = await _dataSourcesClient.ListDataSourceTemplatesAsync(request, _cancellationToken); + + // Assert + Assert.Equal(expectedResponse, result); + + // Verify the REST client was called with correct parameters + _restClient.Verify(client => client.GetAsync( + expectedEndpoint, + expectedQueryParams, + null, + null, + _cancellationToken), Times.Once); + } + + [Fact] + public async Task ListDataSourceTemplatesAsync_ShouldUseCancellationToken() + { + // Arrange + var dataSourceId = "test-data-source-id"; + var customCancellationToken = new CancellationTokenSource().Token; + var request = new ListDataSourceTemplatesRequest + { + DataSourceId = dataSourceId + }; + + var expectedResponse = new ListDataSourceTemplatesResponse + { + Templates = new DataSourceTemplate[0], + HasMore = false, + NextCursor = null + }; + + _restClient + .Setup(client => client.GetAsync( + It.IsAny(), + It.IsAny>(), + null, + null, + customCancellationToken)) + .ReturnsAsync(expectedResponse); + + // Act + var result = await _dataSourcesClient.ListDataSourceTemplatesAsync(request, customCancellationToken); + + // Assert + Assert.Equal(expectedResponse, result); + + // Verify the custom cancellation token was used + _restClient.Verify(client => client.GetAsync( + It.IsAny(), + It.IsAny>(), + null, + null, + customCancellationToken), Times.Once); + } + + #endregion ListDataSourceTemplatesAsync Tests } \ No newline at end of file From e83ee15880e4873969260b3c1062354d28aaf619 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 00:13:10 +0530 Subject: [PATCH 09/27] add support for query data sources api endpoint --- Src/Notion.Client/Api/ApiEndpoints.cs | 1 + .../Api/DataSources/IDataSourcesClient.cs | 11 +++ .../DataSources/Models/DataSourceResponse.cs | 2 +- .../DataSources/Query/DataSourcesClient.cs | 54 +++++++++++++ .../Request/IQueryDataSourceBodyParameters.cs | 40 ++++++++++ .../Request/IQueryDataSourcePathParameters.cs | 10 +++ .../IQueryDataSourceQueryParameters.cs | 14 ++++ .../Request/QueryDataSourceBodyRequest.cs | 75 +++++++++++++++++++ .../Query/Request/QueryDataSourceRequest.cs | 61 +++++++++++++++ .../Query/Request/QueryResultType.cs | 16 ++++ .../IQueryDataSourceResponseObject.cs | 12 +++ .../Query/Response/QueryDataSourceResponse.cs | 14 ++++ Src/Notion.Client/Models/Page/Page.cs | 2 +- .../DataSourcesClientTests.cs | 47 ++++++++++++ 14 files changed, 357 insertions(+), 2 deletions(-) create mode 100644 Src/Notion.Client/Api/DataSources/Query/DataSourcesClient.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceBodyParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourcePathParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceQueryParameters.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceBodyRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceRequest.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Request/QueryResultType.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Response/IQueryDataSourceResponseObject.cs create mode 100644 Src/Notion.Client/Api/DataSources/Query/Response/QueryDataSourceResponse.cs diff --git a/Src/Notion.Client/Api/ApiEndpoints.cs b/Src/Notion.Client/Api/ApiEndpoints.cs index 43e23a81..f3d060df 100644 --- a/Src/Notion.Client/Api/ApiEndpoints.cs +++ b/Src/Notion.Client/Api/ApiEndpoints.cs @@ -158,6 +158,7 @@ public static class DataSourcesApiUrls internal static string CreateDataSource() => BasePath; internal static string Update(IUpdateDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}"; internal static string ListDataSourceTemplates(IListDataSourceTemplatesPathParameters pathParameters) => $"/v1/data-sources/{pathParameters.DataSourceId}/templates"; + internal static string Query(IQueryDataSourcePathParameters pathParameters) => $"{BasePath}/{pathParameters.DataSourceId}/query"; } } } diff --git a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs index 66cc3209..57832b7f 100644 --- a/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs +++ b/Src/Notion.Client/Api/DataSources/IDataSourcesClient.cs @@ -48,5 +48,16 @@ Task ListDataSourceTemplatesAsync( ListDataSourceTemplatesRequest request, CancellationToken cancellationToken = default ); + + /// + /// Queries a data source. + /// + /// + /// + /// + Task QueryAsync( + QueryDataSourceRequest request, + CancellationToken cancellationToken = default + ); } } diff --git a/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs index 0271a30e..e88bf5ac 100644 --- a/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs +++ b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class DataSourceResponse : IObject, IObjectModificationData + public class DataSourceResponse : IObject, IObjectModificationData, IQueryDataSourceResponseObject { public string Id { get; set; } diff --git a/Src/Notion.Client/Api/DataSources/Query/DataSourcesClient.cs b/Src/Notion.Client/Api/DataSources/Query/DataSourcesClient.cs new file mode 100644 index 00000000..fd43821d --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/DataSourcesClient.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Notion.Client +{ + public sealed partial class DataSourcesClient + { + public async Task QueryAsync( + QueryDataSourceRequest request, + CancellationToken cancellationToken = default) + { + IQueryDataSourcePathParameters pathParameters = request; + + if (pathParameters == null) + { + throw new ArgumentNullException(nameof(request), "Request cannot be null and must implement IQueryDataSourcePathParameters."); + } + + if (pathParameters.DataSourceId == null) + { + throw new ArgumentNullException( + nameof(pathParameters.DataSourceId), + "DataSourceId cannot be null. Ensure the request implements IQueryDataSourcePathParameters and has DataSourceId set." + ); + } + + IQueryDataSourceBodyParameters body = request; + + if (body == null) + { + throw new ArgumentNullException(nameof(request), "Request must implement IQueryDataSourceBodyParameters."); + } + + var path = ApiEndpoints.DataSourcesApiUrls.Query(pathParameters); + + var queryParameters = request as IQueryDataSourceQueryParameters; + var queryParams = queryParameters.FilterProperties? + .Select(x => new KeyValuePair("filter_properties", x)); + + // Create a clean body request with only the properties that should be serialized + var bodyRequest = QueryDataSourceBodyRequest.FromRequest(request); + + return await _restClient.PostAsync( + path, + bodyRequest, + queryParams, + cancellationToken: cancellationToken + ); + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceBodyParameters.cs b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceBodyParameters.cs new file mode 100644 index 00000000..50f22b9c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceBodyParameters.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public interface IQueryDataSourceBodyParameters : IPaginationParameters + { + /// + /// A list of sort objects to apply to the query results. + /// + [JsonProperty("sorts")] + IEnumerable Sorts { get; set; } + + /// + /// A filter object to apply to the query results. + /// + [JsonProperty("filter")] + Filter Filter { get; set; } + + /// + /// Whether to include archived results. + /// + [JsonProperty("archived")] + bool? Archived { get; set; } + + /// + /// Whether to include results in trash. + /// + [JsonProperty("in_trash")] + bool? InTrash { get; set; } + + /// + /// Optionally filter the results to only include pages or data sources. + /// + [JsonProperty("result_type")] + [JsonConverter(typeof(StringEnumConverter))] + QueryResultType? ResultType { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourcePathParameters.cs b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourcePathParameters.cs new file mode 100644 index 00000000..6fca48f5 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourcePathParameters.cs @@ -0,0 +1,10 @@ +namespace Notion.Client +{ + public interface IQueryDataSourcePathParameters + { + /// + /// The ID of the data source to query. + /// + string DataSourceId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceQueryParameters.cs b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceQueryParameters.cs new file mode 100644 index 00000000..d937d546 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/IQueryDataSourceQueryParameters.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IQueryDataSourceQueryParameters + { + /// + /// List of properties to filter the results by. + /// + [JsonProperty("filter_properties")] + IEnumerable FilterProperties { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceBodyRequest.cs b/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceBodyRequest.cs new file mode 100644 index 00000000..80bc9beb --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceBodyRequest.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + /// + /// Internal concrete implementation of IQueryDataSourceBodyParameters used for JSON serialization. + /// This class contains only the properties that should be serialized in the request body. + /// + internal class QueryDataSourceBodyRequest : IQueryDataSourceBodyParameters + { + /// + /// A list of sort objects to apply to the query results. + /// + [JsonProperty("sorts")] + public IEnumerable Sorts { get; set; } + + /// + /// A filter object to apply to the query results. + /// + [JsonProperty("filter")] + public Filter Filter { get; set; } + + /// + /// When supplied, returns a page of results starting after the cursor provided. + /// + [JsonProperty("start_cursor")] + public string StartCursor { get; set; } + + /// + /// The number of items from the full list desired in the response. Maximum: 100. + /// + [JsonProperty("page_size")] + public int? PageSize { get; set; } + + /// + /// Whether to include archived results. + /// + [JsonProperty("archived")] + public bool? Archived { get; set; } + + /// + /// Whether to include results in trash. + /// + [JsonProperty("in_trash")] + public bool? InTrash { get; set; } + + /// + /// Optionally filter the results to only include pages or data sources. + /// + [JsonProperty("result_type")] + [JsonConverter(typeof(StringEnumConverter))] + public QueryResultType? ResultType { get; set; } + + /// + /// Creates a QueryDataSourceBodyRequest from a QueryDataSourceRequest + /// + /// The source request containing all parameters + /// A new QueryDataSourceBodyRequest with only body parameters + internal static QueryDataSourceBodyRequest FromRequest(QueryDataSourceRequest source) + { + return new QueryDataSourceBodyRequest + { + Sorts = source.Sorts, + Filter = source.Filter, + StartCursor = source.StartCursor, + PageSize = source.PageSize, + Archived = source.Archived, + InTrash = source.InTrash, + ResultType = source.ResultType + }; + } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceRequest.cs b/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceRequest.cs new file mode 100644 index 00000000..0445aa45 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/QueryDataSourceRequest.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Notion.Client +{ + public class QueryDataSourceRequest : IQueryDataSourcePathParameters, IQueryDataSourceQueryParameters, IQueryDataSourceBodyParameters + { + /// + /// The ID of the data source to query. + /// + public string DataSourceId { get; set; } + + public IEnumerable FilterProperties { get; set; } + + /// + /// A list of sort objects to apply to the query results. + /// + [JsonProperty("sorts")] + public IEnumerable Sorts { get; set; } + + /// + /// A filter object to apply to the query results. + /// + [JsonProperty("filter")] + public Filter Filter { get; set; } + + /// + /// When supplied, returns a page of results starting after the cursor provided. + /// + [JsonProperty("start_cursor")] + public string StartCursor { get; set; } + + /// + /// The number of items from the full list desired in the response. Maximum: 100. + /// + [JsonProperty("page_size")] + public int? PageSize { get; set; } + + /// + /// Whether to include archived results. + /// + [JsonProperty("archived")] + public bool? Archived { get; set; } + + /// + /// Whether to include results in trash. + /// + [JsonProperty("in_trash")] + public bool? InTrash { get; set; } + + /// + /// Optionally filter the results to only include pages or data sources. + /// Regular, non-wiki databases only support page children. The default behavior + /// is no result type filtering, returning both pages and data sources for wikis. + /// + [JsonProperty("result_type")] + [JsonConverter(typeof(StringEnumConverter))] + public QueryResultType? ResultType { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Query/Request/QueryResultType.cs b/Src/Notion.Client/Api/DataSources/Query/Request/QueryResultType.cs new file mode 100644 index 00000000..744eb47c --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Request/QueryResultType.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; + +namespace Notion.Client +{ + public enum QueryResultType + { + [EnumMember(Value = null)] + Unknown, + + [EnumMember(Value = "page")] + Page, + + [EnumMember(Value = "data_source")] + DataSource + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Api/DataSources/Query/Response/IQueryDataSourceResponseObject.cs b/Src/Notion.Client/Api/DataSources/Query/Response/IQueryDataSourceResponseObject.cs new file mode 100644 index 00000000..3c7a4349 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Response/IQueryDataSourceResponseObject.cs @@ -0,0 +1,12 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubTypeAttribute(typeof(Page), ObjectType.Page)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DataSourceResponse), ObjectType.Database)] + public interface IQueryDataSourceResponseObject : IObject + { + } +} diff --git a/Src/Notion.Client/Api/DataSources/Query/Response/QueryDataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Query/Response/QueryDataSourceResponse.cs new file mode 100644 index 00000000..f2253237 --- /dev/null +++ b/Src/Notion.Client/Api/DataSources/Query/Response/QueryDataSourceResponse.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class QueryDataSourceResponse : PaginatedList + { + [JsonProperty("page_or_data_source")] + public Dictionary PageOrDataSource { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index fe4eb0de..554d2a7e 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Page : IObject, IObjectModificationData, IWikiDatabase + public class Page : IObject, IObjectModificationData, IWikiDatabase, IQueryDataSourceResponseObject { /// /// The parent of this page. Can be a database, page, or workspace. diff --git a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs index fbff65b1..e748cd43 100644 --- a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs +++ b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs @@ -130,5 +130,52 @@ public async Task UpdateDataSource_ShouldReturnSuccess() Assert.True(updateResponse.Properties.ContainsKey("Name")); } + // write test for query + [Fact] + public async Task QueryDataSourceAsync_ShouldReturnResults() + { + // Arrange + var databaseId = "29ee2842ccb5802397b8fdf6fed5ac93"; // TODO: Create a test database and set its ID here + var dataSourceId = await CreateAndGetDatasourceIdAsync(databaseId); + var queryRequest = new QueryDataSourceRequest + { + DataSourceId = dataSourceId, + }; + + // Act + var queryResponse = await Client.DataSources.QueryAsync(queryRequest); + + // Assert + Assert.NotNull(queryResponse); + Assert.NotNull(queryResponse.Results); + } + + private async Task CreateAndGetDatasourceIdAsync(string databaseId) + { + var request = new CreateDataSourceRequest + { + Parent = new DatabaseParentRequest + { + DatabaseId = databaseId + }, + Properties = new Dictionary + { + { + "Name", + new TitlePropertyConfigurationRequest { + Description = "The name of the data source", + Title = new Dictionary() + } + } + }, + Title = new List + { + new RichTextTextInput { Text = new Text { Content = "Test Data Source" } } + } + }; + + var response = await Client.DataSources.CreateAsync(request); + return response.Id; + } } } \ No newline at end of file From 73193beb79acff3aadfb734657c539f8d1dc0fd6 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 00:47:56 +0530 Subject: [PATCH 10/27] Add filters for created by, created time, last edited by, last edited time, unique id, and verification status --- .../Models/Filters/CreatedByFilter.cs | 21 +++++++++++ .../Models/Filters/CreatedTimeFilter.cs | 21 +++++++++++ .../Models/Filters/LastEditedByFilter.cs | 21 +++++++++++ .../Models/Filters/LastEditedTimeFilter.cs | 21 +++++++++++ .../Models/Filters/UniqueIdFilter.cs | 21 +++++++++++ .../VerificationPropertyStatusFilter.cs | 35 +++++++++++++++++++ .../Models/Filters/VerificationStatus.cs | 19 ++++++++++ 7 files changed, 159 insertions(+) create mode 100644 Src/Notion.Client/Models/Filters/CreatedByFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/CreatedTimeFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/LastEditedByFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/LastEditedTimeFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/UniqueIdFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/VerificationPropertyStatusFilter.cs create mode 100644 Src/Notion.Client/Models/Filters/VerificationStatus.cs diff --git a/Src/Notion.Client/Models/Filters/CreatedByFilter.cs b/Src/Notion.Client/Models/Filters/CreatedByFilter.cs new file mode 100644 index 00000000..4859e36f --- /dev/null +++ b/Src/Notion.Client/Models/Filters/CreatedByFilter.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedByFilter : SinglePropertyFilter + { + public CreatedByFilter( + string propertyName, + PeopleFilter.Condition createdBy) + { + Property = propertyName; + CreatedBy = createdBy; + } + + /// + /// Gets or sets the created by condition. + /// + [JsonProperty("created_by")] + public PeopleFilter.Condition CreatedBy { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Filters/CreatedTimeFilter.cs b/Src/Notion.Client/Models/Filters/CreatedTimeFilter.cs new file mode 100644 index 00000000..ae5223a2 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/CreatedTimeFilter.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class CreatedTimeFilter : SinglePropertyFilter + { + public CreatedTimeFilter( + string propertyName, + DateFilter.Condition createdTime) + { + Property = propertyName; + CreatedTime = createdTime; + } + + /// + /// Gets or sets the created time condition. + /// + [JsonProperty("created_time")] + public DateFilter.Condition CreatedTime { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Filters/LastEditedByFilter.cs b/Src/Notion.Client/Models/Filters/LastEditedByFilter.cs new file mode 100644 index 00000000..0e2f4d52 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/LastEditedByFilter.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedByFilter : SinglePropertyFilter + { + public LastEditedByFilter( + string propertyName, + PeopleFilter.Condition lastEditedBy) + { + Property = propertyName; + LastEditedBy = lastEditedBy; + } + + /// + /// Gets or sets the last edited by condition. + /// + [JsonProperty("last_edited_by")] + public PeopleFilter.Condition LastEditedBy { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Filters/LastEditedTimeFilter.cs b/Src/Notion.Client/Models/Filters/LastEditedTimeFilter.cs new file mode 100644 index 00000000..1cdba4a5 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/LastEditedTimeFilter.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LastEditedTimeFilter : SinglePropertyFilter + { + public LastEditedTimeFilter( + string propertyName, + DateFilter.Condition lastEditedTime) + { + Property = propertyName; + LastEditedTime = lastEditedTime; + } + + /// + /// Gets or sets the last edited time condition. + /// + [JsonProperty("last_edited_time")] + public DateFilter.Condition LastEditedTime { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Filters/UniqueIdFilter.cs b/Src/Notion.Client/Models/Filters/UniqueIdFilter.cs new file mode 100644 index 00000000..bf3ebb10 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/UniqueIdFilter.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class UniqueIdFilter : SinglePropertyFilter + { + public UniqueIdFilter( + string propertyName, + NumberFilter.Condition uniqueId) + { + Property = propertyName; + UniqueId = uniqueId; + } + + /// + /// Gets or sets the unique id condition. + /// + [JsonProperty("unique_id")] + public NumberFilter.Condition UniqueId { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Filters/VerificationPropertyStatusFilter.cs b/Src/Notion.Client/Models/Filters/VerificationPropertyStatusFilter.cs new file mode 100644 index 00000000..cccca843 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/VerificationPropertyStatusFilter.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class VerificationPropertyStatusFilter : SinglePropertyFilter + { + public VerificationPropertyStatusFilter( + string propertyName, + Condition verificationStatus) + { + Property = propertyName; + VerificationStatus = verificationStatus; + } + + /// + /// Gets or sets the verification status condition. + /// + [JsonProperty("verification_status")] + public Condition VerificationStatus { get; set; } + + public class Condition + { + public Condition(VerificationStatus status) + { + Status = status; + } + + /// + /// Gets or sets the verification status. + /// + [JsonProperty("status")] + public VerificationStatus Status { get; set; } + } + } +} diff --git a/Src/Notion.Client/Models/Filters/VerificationStatus.cs b/Src/Notion.Client/Models/Filters/VerificationStatus.cs new file mode 100644 index 00000000..9dc86f70 --- /dev/null +++ b/Src/Notion.Client/Models/Filters/VerificationStatus.cs @@ -0,0 +1,19 @@ +using System.Runtime.Serialization; + +namespace Notion.Client +{ + /// + /// Verification status values. + /// + public enum VerificationStatus + { + [EnumMember(Value = "verified")] + Verified, + + [EnumMember(Value = "expired")] + Expired, + + [EnumMember(Value = "none")] + None + } +} From f8e200a26b05bc132c1cba9ecb97528ffa1b7bdf Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 02:39:17 +0530 Subject: [PATCH 11/27] Add support for creating databases with new request and response models --- .../Api/Databases/Create/DatabasesClient.cs | 28 +++++++++ .../Create/Request/DatabasesCreateRequest.cs | 28 +++++++++ .../Request/IDatabasesCreateBodyParameters.cs | 50 +++++++++++++++ .../Request}/MentionInput.cs | 0 .../Request}/ParentPageInput.cs | 0 .../Request}/RichTextBaseInput.cs | 0 .../Request}/RichTextEquationInput.cs | 0 .../Request}/RichTextMentionInput.cs | 0 .../Request}/RichTextTextInput.cs | 0 .../Api/Databases/DatabasesClient.cs | 7 --- .../Api/Databases/IDatabasesClient.cs | 2 +- .../Request/IParentOfDatabaseRequest.cs | 10 +++ .../Request/PageParentOfDatabaseRequest.cs | 13 ++++ .../WorkspaceParentOfDatabaseRequest.cs | 13 ++++ .../Database/DataSourceReferenceResponse.cs | 13 ++++ Src/Notion.Client/Models/Database/Database.cs | 61 ++++++++++++------- 16 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 Src/Notion.Client/Api/Databases/Create/DatabasesClient.cs create mode 100644 Src/Notion.Client/Api/Databases/Create/Request/DatabasesCreateRequest.cs create mode 100644 Src/Notion.Client/Api/Databases/Create/Request/IDatabasesCreateBodyParameters.cs rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/MentionInput.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/ParentPageInput.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/RichTextBaseInput.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/RichTextEquationInput.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/RichTextMentionInput.cs (100%) rename Src/Notion.Client/Api/Databases/{RequestParams/DatabasesCreateParameters => Create/Request}/RichTextTextInput.cs (100%) create mode 100644 Src/Notion.Client/Api/Databases/Models/Request/IParentOfDatabaseRequest.cs create mode 100644 Src/Notion.Client/Api/Databases/Models/Request/PageParentOfDatabaseRequest.cs create mode 100644 Src/Notion.Client/Api/Databases/Models/Request/WorkspaceParentOfDatabaseRequest.cs create mode 100644 Src/Notion.Client/Models/Database/DataSourceReferenceResponse.cs diff --git a/Src/Notion.Client/Api/Databases/Create/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/Create/DatabasesClient.cs new file mode 100644 index 00000000..a37b15a3 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Create/DatabasesClient.cs @@ -0,0 +1,28 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using static Notion.Client.ApiEndpoints; + +namespace Notion.Client +{ + public sealed partial class DatabasesClient : IDatabasesClient + { + public async Task CreateAsync( + DatabasesCreateRequest databasesCreateParameters, + CancellationToken cancellationToken = default) + { + var body = (IDatabasesCreateBodyParameters)databasesCreateParameters; + + if (body.Parent == null) + { + throw new ArgumentNullException(nameof(body.Parent), "Parent cannot be null."); + } + + return await _client.PostAsync( + DatabasesApiUrls.Create, + body, + cancellationToken: cancellationToken + ); + } + } +} diff --git a/Src/Notion.Client/Api/Databases/Create/Request/DatabasesCreateRequest.cs b/Src/Notion.Client/Api/Databases/Create/Request/DatabasesCreateRequest.cs new file mode 100644 index 00000000..6ef138fd --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Create/Request/DatabasesCreateRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DatabasesCreateRequest : IDatabasesCreateBodyParameters + { + public IParentOfDatabaseRequest Parent { get; set; } + + public List Title { get; set; } + + public List Description { get; set; } + + public bool? IsInline { get; set; } + + public InitialDataSourceRequest InitialDataSource { get; set; } + + public IPageIconRequest Icon { get; set; } + + public FileObject Cover { get; set; } + } + + public class InitialDataSourceRequest + { + [JsonProperty("properties")] + public Dictionary Properties { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Databases/Create/Request/IDatabasesCreateBodyParameters.cs b/Src/Notion.Client/Api/Databases/Create/Request/IDatabasesCreateBodyParameters.cs new file mode 100644 index 00000000..b693eed3 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Create/Request/IDatabasesCreateBodyParameters.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IDatabasesCreateBodyParameters + { + /// + /// Specifies the parent page or workspace where the database will be created. + /// + [JsonProperty("parent")] + IParentOfDatabaseRequest Parent { get; set; } + + /// + /// The title of the database. + /// + [JsonProperty("title")] + List Title { get; set; } + + /// + /// The description of the database. + /// + [JsonProperty("description")] + List Description { get; set; } + + /// + /// Indicates whether the database is inline. + /// + [JsonProperty("is_inline")] + bool? IsInline { get; set; } + + /// + /// Initial data source configuration for the database. + /// + [JsonProperty("initial_data_source")] + InitialDataSourceRequest InitialDataSource { get; set; } + + /// + /// Page icon for the database. + /// + [JsonProperty("icon")] + public IPageIconRequest Icon { get; set; } + + /// + /// Cover image for the database. + /// + [JsonProperty("cover")] + public FileObject Cover { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/MentionInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/MentionInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/MentionInput.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/ParentPageInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/ParentPageInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextBaseInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/RichTextBaseInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextBaseInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/RichTextBaseInput.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextEquationInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/RichTextEquationInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextEquationInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/RichTextEquationInput.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextMentionInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/RichTextMentionInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextMentionInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/RichTextMentionInput.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextTextInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/RichTextTextInput.cs similarity index 100% rename from Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/RichTextTextInput.cs rename to Src/Notion.Client/Api/Databases/Create/Request/RichTextTextInput.cs diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index a3dc9a8c..567fec52 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -24,13 +24,6 @@ public async Task RetrieveAsync(string databaseId, CancellationToken c return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), cancellationToken: cancellationToken); } - public async Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default) - { - var body = (IDatabasesCreateBodyParameters)databasesCreateParameters; - - return await _client.PostAsync(DatabasesApiUrls.Create, body, cancellationToken: cancellationToken); - } - public async Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default) { var body = (IDatabasesUpdateBodyParameters)databasesUpdateParameters; diff --git a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs index 98df1273..a21b8571 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -33,7 +33,7 @@ public interface IDatabasesClient /// /// /// - Task CreateAsync(DatabasesCreateParameters databasesCreateParameters, CancellationToken cancellationToken = default); + Task CreateAsync(DatabasesCreateRequest databasesCreateParameters, CancellationToken cancellationToken = default); /// /// Updates an existing database as specified by the parameters. diff --git a/Src/Notion.Client/Api/Databases/Models/Request/IParentOfDatabaseRequest.cs b/Src/Notion.Client/Api/Databases/Models/Request/IParentOfDatabaseRequest.cs new file mode 100644 index 00000000..ed6d33ed --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Models/Request/IParentOfDatabaseRequest.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IParentOfDatabaseRequest + { + [JsonProperty("type")] + string Type { get; } + } +} diff --git a/Src/Notion.Client/Api/Databases/Models/Request/PageParentOfDatabaseRequest.cs b/Src/Notion.Client/Api/Databases/Models/Request/PageParentOfDatabaseRequest.cs new file mode 100644 index 00000000..c25262b8 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Models/Request/PageParentOfDatabaseRequest.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PageParentOfDatabaseRequest : IParentOfDatabaseRequest + { + [JsonProperty("type")] + public string Type => "page_id"; + + [JsonProperty("page_id")] + public string PageId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Databases/Models/Request/WorkspaceParentOfDatabaseRequest.cs b/Src/Notion.Client/Api/Databases/Models/Request/WorkspaceParentOfDatabaseRequest.cs new file mode 100644 index 00000000..b6689038 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Models/Request/WorkspaceParentOfDatabaseRequest.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class WorkspaceParentOfDatabaseRequest : IParentOfDatabaseRequest + { + [JsonProperty("type")] + public string Type => "workspace"; + + [JsonProperty("workspace")] + public bool Workspace => true; + } +} diff --git a/Src/Notion.Client/Models/Database/DataSourceReferenceResponse.cs b/Src/Notion.Client/Models/Database/DataSourceReferenceResponse.cs new file mode 100644 index 00000000..c6871641 --- /dev/null +++ b/Src/Notion.Client/Models/Database/DataSourceReferenceResponse.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceReferenceResponse + { + [JsonProperty("id")] + public string DataSourceId { get; set; } + + [JsonProperty("name")] + public string Name { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index be288ea0..9abf7e19 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -6,39 +6,36 @@ namespace Notion.Client { public class Database : IObject, IObjectModificationData, IWikiDatabase { - [JsonProperty("title")] - public List Title { get; set; } - - [JsonProperty("properties")] - public Dictionary Properties { get; set; } - - [JsonProperty("parent")] - public IDatabaseParent Parent { get; set; } + public ObjectType Object => ObjectType.Database; - [JsonProperty("icon")] - public IPageIcon Icon { get; set; } + public string Id { get; set; } - [JsonProperty("cover")] - public FileObject Cover { get; set; } + /// + /// The title of the database. + /// + [JsonProperty("title")] + public List Title { get; set; } /// - /// The URL of the Notion database. + /// The description of the database. /// - [JsonProperty("url")] - public string Url { get; set; } + [JsonProperty("description")] + public IEnumerable Description { get; set; } - [JsonProperty("in_trash")] - public bool InTrash { get; set; } + /// + /// Parent of the database. + /// + [JsonProperty("parent")] + public IDatabaseParent Parent { get; set; } [JsonProperty("is_inline")] public bool IsInline { get; set; } - [JsonProperty("description")] - public IEnumerable Description { get; set; } - - public ObjectType Object => ObjectType.Database; + [JsonProperty("in_trash")] + public bool InTrash { get; set; } - public string Id { get; set; } + [JsonProperty("is_locked")] + public bool IsLocked { get; set; } [JsonProperty("created_time")] public DateTime CreatedTime { get; set; } @@ -51,7 +48,25 @@ public class Database : IObject, IObjectModificationData, IWikiDatabase public PartialUser LastEditedBy { get; set; } /// - /// The public page URL if the page has been published to the web. Otherwise, null. + /// The data sources associated with the database. + /// + [JsonProperty("data_sources")] + public IEnumerable DataSources { get; set; } + + [JsonProperty("icon")] + public IPageIconResponse Icon { get; set; } + + [JsonProperty("cover")] + public FileObject Cover { get; set; } + + /// + /// The URL of the Notion database. + /// + [JsonProperty("url")] + public string Url { get; set; } + + /// + /// The public page URL if the page has been published to the web. Otherwise, null. /// [JsonProperty("public_url")] public string PublicUrl { get; set; } From fab9995e44094f13d0e359f1d51fe9f69ab15ed4 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 04:35:48 +0530 Subject: [PATCH 12/27] Delete obsolete database response JSON files to clean up test data --- Test/Notion.UnitTests/DatabasesClientTests.cs | 521 ------------------ .../databases/CreateDatabaseResponse.json | 75 --- ...basePropertyObjectContainNameProperty.json | 92 ---- ...sePropertyObjectContainParentProperty.json | 92 ---- ...DatabasePropertyObjectContainRelation.json | 92 ---- .../databases/DatabaseRetrieveResponse.json | 110 ---- .../data/databases/DatabasesListResponse.json | 228 -------- .../databases/DatabasesQueryResponse.json | 59 -- ...ncDateFormulaValueReturnsNullResponse.json | 134 ----- ...yCanBeSetWhenCreatingDatabaseResponse.json | 47 -- .../databases/UpdateDatabaseResponse.json | 75 --- 11 files changed, 1525 deletions(-) delete mode 100644 Test/Notion.UnitTests/DatabasesClientTests.cs delete mode 100644 Test/Notion.UnitTests/data/databases/CreateDatabaseResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabasesListResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/DatabasesQueryResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/FormulaPropertyCanBeSetWhenCreatingDatabaseResponse.json delete mode 100644 Test/Notion.UnitTests/data/databases/UpdateDatabaseResponse.json diff --git a/Test/Notion.UnitTests/DatabasesClientTests.cs b/Test/Notion.UnitTests/DatabasesClientTests.cs deleted file mode 100644 index 30deae75..00000000 --- a/Test/Notion.UnitTests/DatabasesClientTests.cs +++ /dev/null @@ -1,521 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading.Tasks; -using FluentAssertions; -using Notion.Client; -using WireMock.ResponseBuilders; -using Xunit; - -namespace Notion.UnitTests; - -public class DatabasesClientTests : ApiTestBase -{ - private readonly IDatabasesClient _client; - private readonly IPagesClient _pagesClient; - - public DatabasesClientTests() - { - _client = new DatabasesClient(new RestClient(ClientOptions)); - _pagesClient = new PagesClient(new RestClient(ClientOptions)); - } - - [Fact] - public async Task QueryAsync() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasesQueryResponse.json"); - - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var databasesQueryParams = new DatabasesQueryParameters - { - Filter = new CompoundFilter - { - Or = new List - { - new CheckboxFilter( - "In stock", - true - ), - new NumberFilter( - "Cost of next trip", - greaterThanOrEqualTo: 2 - ) - } - }, - Sorts = new List - { - new() - { - Property = "Last ordered", - Direction = Direction.Ascending - } - } - }; - - var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); - - pagesPaginatedList.Results.Should().ContainSingle(); - - foreach (var iWikiDatabase in pagesPaginatedList.Results) - { - var page = (Page)iWikiDatabase; - page.Parent.Should().BeAssignableTo(); - page.Object.Should().Be(ObjectType.Page); - } - } - - [Fact] - public async Task RetrieveDatabaseAsync() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabaseRetrieveResponse.json"); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var database = await _client.RetrieveAsync(databaseId); - - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); - - foreach (var property in database.Properties) - { - property.Key.Should().Be(property.Value.Name); - } - - HelperAsserts.IPageIconAsserts(database.Icon); - HelperAsserts.FileObjectAsserts(database.Cover); - } - - [Fact] - public async Task DatabasePropertyObjectContainNameProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainNameProperty.json"); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var database = await _client.RetrieveAsync(databaseId); - - foreach (var property in database.Properties) - { - property.Key.Should().Be(property.Value.Name); - } - } - - [Fact] - public async Task DatabasePropertyObjectContainRelationProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainRelation.json"); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var database = await _client.RetrieveAsync(databaseId); - - database.Properties.Should().ContainKey("Property").WhichValue.Should().BeEquivalentTo( - new RelationProperty - { - Id = "zDGa", - Name = "Property", - Relation = new DualPropertyRelation - { - DatabaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - DualProperty = new DualPropertyRelation.Data - { - SyncedPropertyName = "Related to sample table (Property)", - SyncedPropertyId = "VQ}{" - } - } - }); - } - - [Fact] - public async Task DatabasePropertyObjectContainParentProperty() - { - var databaseId = "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1"; - var path = ApiEndpoints.DatabasesApiUrls.Retrieve(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/DatabasePropertyObjectContainParentProperty.json"); - - Server.Given(CreateGetRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var database = await _client.RetrieveAsync(databaseId); - - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("649089db-8984-4051-98fb-a03593b852d8"); - } - - [Fact] - public async Task CreateDatabaseAsync() - { - var pageId = "533578e3-edf1-4c0a-91a9-da6b09bac3ee"; - var path = ApiEndpoints.DatabasesApiUrls.Create; - var jsonData = await File.ReadAllTextAsync("data/databases/CreateDatabaseResponse.json"); - - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var createDatabaseParameters = new DatabasesCreateParameters - { - Parent = new ParentPageInput { PageId = pageId }, - Title = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Grocery List", - Link = null - } - } - }, - Properties = new Dictionary - { - { "Name", new TitlePropertySchema { Title = new Dictionary() } }, - { "Price", new NumberPropertySchema { Number = new Number { Format = "dollar" } } }, - { - "Food group", - new SelectPropertySchema - { - Select = new OptionWrapper - { - Options = new List - { - new() - { - Color = Color.Green, - Name = "🥦Vegetable" - }, - new() - { - Color = Color.Red, - Name = "🍎Fruit" - }, - new() - { - Color = Color.Yellow, - Name = "💪Protein" - } - } - } - } - }, - { "Last ordered", new DatePropertySchema { Date = new Dictionary() } } - } - }; - - var database = await _client.CreateAsync(createDatabaseParameters); - - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be(pageId); - - database.Properties.Should().HaveCount(4); - - var selectOptions = (SelectProperty)database.Properties["Food group"]; - selectOptions.Name.Should().Be("Food group"); - - selectOptions.Select.Options.Should().SatisfyRespectively( - option => - { - option.Name.Should().Be("🥦Vegetable"); - option.Color.Should().Be(Color.Green); - }, - option => - { - option.Name.Should().Be("🍎Fruit"); - option.Color.Should().Be(Color.Red); - }, - option => - { - option.Name.Should().Be("💪Protein"); - option.Color.Should().Be(Color.Yellow); - } - ); - } - - [Fact] - public async Task UpdateDatabaseAsync() - { - var databaseId = "1e9eee34-9c5c-4fe6-a4e1-8244eb141ed8"; - var path = ApiEndpoints.DatabasesApiUrls.Update(databaseId); - var jsonData = await File.ReadAllTextAsync("data/databases/UpdateDatabaseResponse.json"); - - Server.Given(CreatePatchRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var updateDatabaseParameters = new DatabasesUpdateParameters - { - Title = - new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Grocery List New", - Link = null - } - } - }, - Properties = new Dictionary - { - { "Name", new TitleUpdatePropertySchema { Title = new Dictionary() } }, - { "Price", new NumberUpdatePropertySchema { Number = new Number { Format = "yen" } } }, - { - "Food group", - new SelectUpdatePropertySchema - { - Select = new OptionWrapper - { - Options = new List - { - new() - { - Color = Color.Green, - Name = "🥦Vegetables" - }, - new() - { - Color = Color.Red, - Name = "🍎Fruit" - }, - new() - { - Color = Color.Yellow, - Name = "💪Protein" - } - } - } - } - }, - { "Last ordered", new DateUpdatePropertySchema { Date = new Dictionary() } } - } - }; - - var database = await _client.UpdateAsync(databaseId, updateDatabaseParameters); - - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be("533578e3-edf1-4c0a-91a9-da6b09bac3ee"); - - database.Properties.Should().HaveCount(4); - - database.Title.Should().ContainSingle(); - - database.Title.Should().SatisfyRespectively( - title => - { - title.Should().BeAssignableTo(); - ((RichTextText)title).Text.Content.Should().Be("Grocery List New"); - } - ); - - var selectOptions = (SelectProperty)database.Properties["Food group"]; - selectOptions.Name.Should().Be("Food group"); - - selectOptions.Select.Options.Should().SatisfyRespectively( - option => - { - option.Name.Should().Be("🥦Vegetables"); - option.Color.Should().Be(Color.Green); - }, - option => - { - option.Name.Should().Be("🍎Fruit"); - option.Color.Should().Be(Color.Red); - }, - option => - { - option.Name.Should().Be("💪Protein"); - option.Color.Should().Be(Color.Yellow); - } - ); - - var price = (NumberProperty)database.Properties["Price"]; - price.Number.Format.Should().Be("yen"); - } - - [Fact] - public async Task FormulaPropertyCanBeSetWhenCreatingDatabase() - { - var pageId = "98ad959b-2b6a-4774-80ee-00246fb0ea9b"; - var path = ApiEndpoints.DatabasesApiUrls.Create; - - var jsonData - = await File.ReadAllTextAsync("data/databases/FormulaPropertyCanBeSetWhenCreatingDatabaseResponse.json"); - - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var createDatabaseParameters = new DatabasesCreateParameters - { - Parent = new ParentPageInput { PageId = pageId }, - Title = new List - { - new RichTextTextInput - { - Text = new Text - { - Content = "Grocery List", - Link = null - } - } - }, - Properties = new Dictionary - { - { - "Cost of next trip", - new FormulaPropertySchema - { - Formula = new Formula { Expression = "if(prop(\"In stock\"), 0, prop(\"Price\"))" } - } - }, - { "Price", new NumberPropertySchema { Number = new Number { Format = "dollar" } } } - } - }; - - var database = await _client.CreateAsync(createDatabaseParameters); - - database.Parent.Type.Should().Be(ParentType.PageId); - database.Parent.Should().BeOfType(); - ((PageParent)database.Parent).PageId.Should().Be(pageId); - - database.Properties.Should().HaveCount(2); - - var formulaProperty = (FormulaProperty)database.Properties["Cost of next trip"]; - formulaProperty.Formula.Expression.Should().Be("if(prop(\"In stock\"), 0, prop(\"Price\"))"); - } - - [Fact] - public async Task Fix123_QueryAsync_DateFormulaValue_Returns_Null() - { - var databaseId = "f86f2262-0751-40f2-8f63-e3f7a3c39fcb"; - var path = ApiEndpoints.DatabasesApiUrls.Query(databaseId); - - var jsonData - = await File.ReadAllTextAsync("data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json"); - - Server.Given(CreatePostRequestBuilder(path)) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody(jsonData) - ); - - var databasesQueryParams = new DatabasesQueryParameters - { - Filter = new CompoundFilter - { - Or = new List - { - new CheckboxFilter( - "In stock", - true - ), - new NumberFilter( - "Cost of next trip", - greaterThanOrEqualTo: 2 - ) - } - }, - Sorts = new List - { - new() - { - Property = "Last ordered", - Direction = Direction.Ascending - } - } - }; - - var pagesPaginatedList = await _client.QueryAsync(databaseId, databasesQueryParams); - - pagesPaginatedList.Results.Should().ContainSingle(); - - foreach (var iWikiDatabase in pagesPaginatedList.Results) - { - var page = (Page)iWikiDatabase; - page.Parent.Should().BeAssignableTo(); - page.Object.Should().Be(ObjectType.Page); - - Server.Given(CreateGetRequestBuilder( - ApiEndpoints.PagesApiUrls.RetrievePropertyItem(page.Id, page.Properties["FormulaProp"].Id))) - .RespondWith( - Response.Create() - .WithStatusCode(200) - .WithBody( - "{\"object\":\"property_item\",\"id\":\"JwY^\",\"type\":\"formula\",\"formula\":{\"type\":\"date\",\"date\":{\"start\":\"2021-06-28\",\"end\":null}}}") - ); - - var formulaPropertyValue = (FormulaPropertyItem)await _pagesClient.RetrievePagePropertyItemAsync( - new RetrievePropertyItemParameters - { - PageId = page.Id, - PropertyId = page.Properties["FormulaProp"].Id - }); - - //var formulaPropertyValue = (FormulaPropertyValue)page.Properties["FormulaProp"]; - formulaPropertyValue.Formula.Date.Start.Should().Be(DateTimeOffset.Parse("2021-06-28", null, System.Globalization.DateTimeStyles.AssumeUniversal).UtcDateTime); - formulaPropertyValue.Formula.Date.End.Should().BeNull(); - } - } - - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData(" ")] - public async Task RetrieveAsync_throws_argument_null_exception_if_database_id_is_null_or_empty(string databaseId) - { - // Arrange && Act - async Task Act() => await _client.RetrieveAsync(databaseId); - - // Assert - var exception = await Assert.ThrowsAsync(Act); - Assert.Equal("databaseId", exception.ParamName); - } -} diff --git a/Test/Notion.UnitTests/data/databases/CreateDatabaseResponse.json b/Test/Notion.UnitTests/data/databases/CreateDatabaseResponse.json deleted file mode 100644 index 62450560..00000000 --- a/Test/Notion.UnitTests/data/databases/CreateDatabaseResponse.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "object": "database", - "id": "1e9eee34-9c5c-4fe6-a4e1-8244eb141ed8", - "created_time": "2021-08-18T17:39:00.000Z", - "last_edited_time": "2021-08-18T17:39:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "Grocery List", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "Grocery List", - "href": null - } - ], - "properties": { - "Price": { - "id": "@xZm", - "name": "Price", - "type": "number", - "number": { - "format": "dollar" - } - }, - "Last ordered": { - "id": "SN;?", - "name": "Last ordered", - "type": "date", - "date": {} - }, - "Food group": { - "id": "zIZQ", - "name": "Food group", - "type": "select", - "select": { - "options": [ - { - "id": "49ca815e-c37a-4dce-9033-32a62233f483", - "name": "🥦Vegetable", - "color": "green" - }, - { - "id": "9fa8d118-59fb-47c7-b4c7-a8523609e37f", - "name": "🍎Fruit", - "color": "red" - }, - { - "id": "ef3c69d2-0cd1-4540-82fd-03ff9650fc44", - "name": "💪Protein", - "color": "yellow" - } - ] - } - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "533578e3-edf1-4c0a-91a9-da6b09bac3ee" - } -} \ No newline at end of file diff --git a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json deleted file mode 100644 index 2951f5f3..00000000 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainNameProperty.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "object": "database", - "id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "created_time": "2021-05-22T18:44:00.000Z", - "last_edited_time": "2021-05-23T12:29:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "sample table", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "sample table", - "href": null - } - ], - "properties": { - "Tags": { - "id": "YG~h", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "SimpleText": { - "id": "_Dfp", - "name": "SimpleText", - "type": "rich_text", - "rich_text": {} - }, - "Column": { - "id": "bxhl", - "name": "Column", - "type": "multi_select", - "multi_select": { - "options": [ - { - "id": "5a44a233-33be-435e-b358-2c0ed1799dcf", - "name": "what", - "color": "gray" - } - ] - } - }, - "SelectProp": { - "id": "eZ[y", - "name": "SelectProp", - "type": "select", - "select": { - "options": [ - { - "id": "362dc255-c867-4543-b3ea-7bd988638228", - "name": "Female", - "color": "green" - } - ] - } - }, - "Property": { - "id": "zDGa", - "name": "Property", - "type": "relation", - "relation": { - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "type": "dual_property", - "dual_property": { - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" - } - } - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } -} diff --git a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json deleted file mode 100644 index 2951f5f3..00000000 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainParentProperty.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "object": "database", - "id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "created_time": "2021-05-22T18:44:00.000Z", - "last_edited_time": "2021-05-23T12:29:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "sample table", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "sample table", - "href": null - } - ], - "properties": { - "Tags": { - "id": "YG~h", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "SimpleText": { - "id": "_Dfp", - "name": "SimpleText", - "type": "rich_text", - "rich_text": {} - }, - "Column": { - "id": "bxhl", - "name": "Column", - "type": "multi_select", - "multi_select": { - "options": [ - { - "id": "5a44a233-33be-435e-b358-2c0ed1799dcf", - "name": "what", - "color": "gray" - } - ] - } - }, - "SelectProp": { - "id": "eZ[y", - "name": "SelectProp", - "type": "select", - "select": { - "options": [ - { - "id": "362dc255-c867-4543-b3ea-7bd988638228", - "name": "Female", - "color": "green" - } - ] - } - }, - "Property": { - "id": "zDGa", - "name": "Property", - "type": "relation", - "relation": { - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "type": "dual_property", - "dual_property": { - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" - } - } - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } -} diff --git a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json b/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json deleted file mode 100644 index 2951f5f3..00000000 --- a/Test/Notion.UnitTests/data/databases/DatabasePropertyObjectContainRelation.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "object": "database", - "id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "created_time": "2021-05-22T18:44:00.000Z", - "last_edited_time": "2021-05-23T12:29:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "sample table", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "sample table", - "href": null - } - ], - "properties": { - "Tags": { - "id": "YG~h", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "SimpleText": { - "id": "_Dfp", - "name": "SimpleText", - "type": "rich_text", - "rich_text": {} - }, - "Column": { - "id": "bxhl", - "name": "Column", - "type": "multi_select", - "multi_select": { - "options": [ - { - "id": "5a44a233-33be-435e-b358-2c0ed1799dcf", - "name": "what", - "color": "gray" - } - ] - } - }, - "SelectProp": { - "id": "eZ[y", - "name": "SelectProp", - "type": "select", - "select": { - "options": [ - { - "id": "362dc255-c867-4543-b3ea-7bd988638228", - "name": "Female", - "color": "green" - } - ] - } - }, - "Property": { - "id": "zDGa", - "name": "Property", - "type": "relation", - "relation": { - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "type": "dual_property", - "dual_property": { - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" - } - } - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } -} diff --git a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json b/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json deleted file mode 100644 index 9e1acfb0..00000000 --- a/Test/Notion.UnitTests/data/databases/DatabaseRetrieveResponse.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "object": "database", - "id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "created_time": "2021-05-22T18:44:00.000Z", - "last_edited_time": "2021-05-23T12:29:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "sample table", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "sample table", - "href": null - } - ], - "icon": { - "type": "emoji", - "emoji": "🎉" - }, - "cover": { - "type": "external", - "external": { - "url": "https://website.domain/images/image.png" - } - }, - "url": "https://www.notion.so/668d797c76fa49349b05ad288df2d136", - "in_trash" : false, - "properties": { - "Tags": { - "id": "YG~h", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "SimpleText": { - "id": "_Dfp", - "name": "SimpleText", - "type": "rich_text", - "rich_text": {} - }, - "Column": { - "id": "bxhl", - "name": "Column", - "type": "multi_select", - "multi_select": { - "options": [ - { - "id": "5a44a233-33be-435e-b358-2c0ed1799dcf", - "name": "what", - "color": "gray" - } - ] - } - }, - "SelectProp": { - "id": "eZ[y", - "name": "SelectProp", - "type": "select", - "select": { - "options": [ - { - "id": "362dc255-c867-4543-b3ea-7bd988638228", - "name": "Female", - "color": "green" - } - ] - } - }, - "Property": { - "id": "zDGa", - "name": "Property", - "type": "relation", - "relation": { - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "type": "dual_property", - "dual_property": { - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" - } - } - }, - "SimpleButton": { - "id":"_ri%7C", - "name":"SimpleButton", - "type":"button", - "button": {} - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } -} diff --git a/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json b/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json deleted file mode 100644 index ad0e5497..00000000 --- a/Test/Notion.UnitTests/data/databases/DatabasesListResponse.json +++ /dev/null @@ -1,228 +0,0 @@ -{ - "object": "list", - "results": [ - { - "object": "database", - "id": "f0212efc-caf6-4afc-87f6-1c06f1dfc8a1", - "created_time": "2021-05-22T18:44:00.000Z", - "last_edited_time": "2021-05-23T12:29:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "sample table", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "sample table", - "href": null - } - ], - "properties": { - "Tags": { - "id": "YG~h", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "SimpleText": { - "id": "_Dfp", - "name": "SimpleText", - "type": "rich_text", - "rich_text": {} - }, - "Column": { - "id": "bxhl", - "name": "Column", - "type": "multi_select", - "multi_select": { - "options": [ - { - "id": "5a44a233-33be-435e-b358-2c0ed1799dcf", - "name": "what", - "color": "gray" - } - ] - } - }, - "SelectProp": { - "id": "eZ[y", - "name": "SelectProp", - "type": "select", - "select": { - "options": [ - { - "id": "362dc255-c867-4543-b3ea-7bd988638228", - "name": "Female", - "color": "green" - } - ] - } - }, - "Property": { - "id": "zDGa", - "name": "Property", - "type": "relation", - "relation": { - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "type": "dual_property", - "dual_property": { - "synced_property_name": "Related to sample table (Property)", - "synced_property_id": "VQ}{" - } - } - }, - "SimpleButton": { - "id":"_ri%7C", - "name":"SimpleButton", - "type":"button", - "button": {} - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } - }, - { - "object": "database", - "id": "b38b2eed-282c-40f2-b454-cae5d882fef5", - "created_time": "2021-05-22T18:43:00.000Z", - "last_edited_time": "2021-05-22T18:43:00.000Z", - "title": [], - "properties": { - "Created": { - "id": "?uvZ", - "name": "Created", - "type": "created_time", - "created_time": {} - }, - "Tags": { - "id": "{>_o", - "name": "Tags", - "type": "multi_select", - "multi_select": { - "options": [] - } - }, - "Name": { - "id": "title", - "name": "Name", - "type": "title", - "title": {} - } - }, - "parent": { - "type": "page_id", - "page_id": "649089db-8984-4051-98fb-a03593b852d8" - } - }, - { - "object": "database", - "id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb", - "created_time": "2021-05-22T18:30:00.000Z", - "last_edited_time": "2021-06-02T18:32:00.000Z", - "title": [ - { - "type": "text", - "text": { - "content": "SampleDB", - "link": null - }, - "annotations": { - "bold": false, - "italic": false, - "strikethrough": false, - "underline": false, - "code": false, - "color": "default" - }, - "plain_text": "SampleDB", - "href": null - } - ], - "properties": { - "Property": { - "id": "CfU;", - "type": "checkbox", - "checkbox": false - }, - "Add Page Button": { - "id":"_ri%7C", - "type":"button", - "button": {} - } - } - } - ], - "has_more": false, - "next_cursor": null -} diff --git a/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json b/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json deleted file mode 100644 index 00159d76..00000000 --- a/Test/Notion.UnitTests/data/databases/Fix123QueryAsyncDateFormulaValueReturnsNullResponse.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "object": "list", - "results": [ - { - "object": "page", - "id": "50b4321c-afc1-4468-b278-5a578643989c", - "created_time": "2021-05-22T18:30:00.000Z", - "last_edited_time": "2021-09-09T05:49:00.000Z", - "cover": null, - "icon": null, - "parent": { - "type": "database_id", - "database_id": "f86f2262-0751-40f2-8f63-e3f7a3c39fcb" - }, - "in_trash": false, - "properties": { - "Column": { - "id": "B[\\E", - "type": "rollup", - "rollup": { - "type": "array", - "array": [] - } - }, - "Property": { - "id": "Cf Date: Mon, 1 Dec 2025 04:46:09 +0530 Subject: [PATCH 13/27] Remove obsolete database creation parameter classes and property schemas --- .../DatabasesCreateParameters.cs | 27 ------------------- .../IDatabasesCreateBodyParameters.cs | 23 ---------------- .../IDatabasesCreateQueryParameters.cs | 6 ----- .../PropertySchema/CheckboxPropertySchema.cs | 11 -------- .../PropertySchema/CreatedByPropertySchema.cs | 11 -------- .../CreatedTimePropertySchema.cs | 11 -------- .../PropertySchema/DatePropertySchema.cs | 11 -------- .../PropertySchema/EmailPropertySchema.cs | 11 -------- .../PropertySchema/FilePropertySchema.cs | 11 -------- .../PropertySchema/FormulaPropertySchema.cs | 10 ------- .../PropertySchema/IPropertySchema.cs | 6 ----- .../LastEditedByPropertySchema.cs | 11 -------- .../LastEditedTimePropertySchema.cs | 11 -------- .../PropertySchema/MultiSelectOptionSchema.cs | 9 ------- .../MultiSelectPropertySchema.cs | 10 ------- .../PropertySchema/NumberPropertySchema.cs | 10 ------- .../PropertySchema/PeoplePropertySchema.cs | 11 -------- .../PhoneNumberPropertySchema.cs | 11 -------- .../PropertySchema/RelationPropertySchema.cs | 10 ------- .../PropertySchema/RichTextPropertySchema.cs | 11 -------- .../RollupConfigPropertySchema.cs | 22 --------------- .../PropertySchema/SelectOptionSchema.cs | 15 ----------- .../PropertySchema/SelectPropertySchema.cs | 10 ------- .../PropertySchema/TitlePropertySchema.cs | 11 -------- .../PropertySchema/UrlPropertySchema.cs | 11 -------- 25 files changed, 301 deletions(-) delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateBodyParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateQueryParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CheckboxPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedByPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedTimePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/DatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/EmailPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FilePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FormulaPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/IPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedByPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedTimePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/NumberPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PeoplePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PhoneNumberPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RichTextPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RollupConfigPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectOptionSchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectPropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/TitlePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/UrlPropertySchema.cs diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs deleted file mode 100644 index 9cb7086b..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/DatabasesCreateParameters.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class DatabasesCreateParameters : IDatabasesCreateBodyParameters, IDatabasesCreateQueryParameters - { - [JsonProperty("icon")] - public IPageIcon Icon { get; set; } - - [JsonProperty("cover")] - public FileObject Cover { get; set; } - - [JsonProperty("parent")] - public ParentPageInput Parent { get; set; } - - [JsonProperty("properties")] - public Dictionary Properties { get; set; } - - [JsonProperty("title")] - public List Title { get; set; } - - public bool? IsInline { get; set; } - - public List Description { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateBodyParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateBodyParameters.cs deleted file mode 100644 index 7eb252f2..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateBodyParameters.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public interface IDatabasesCreateBodyParameters - { - [JsonProperty("parent")] - ParentPageInput Parent { get; set; } - - [JsonProperty("properties")] - Dictionary Properties { get; set; } - - [JsonProperty("title")] - List Title { get; set; } - - [JsonProperty("is_inline")] - bool? IsInline { get; set; } - - [JsonProperty("description")] - List Description { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateQueryParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateQueryParameters.cs deleted file mode 100644 index 309b5dba..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/IDatabasesCreateQueryParameters.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Notion.Client -{ - public interface IDatabasesCreateQueryParameters - { - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CheckboxPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CheckboxPropertySchema.cs deleted file mode 100644 index fb955a3e..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CheckboxPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CheckboxPropertySchema : IPropertySchema - { - [JsonProperty("checkbox")] - public Dictionary Checkbox { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedByPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedByPropertySchema.cs deleted file mode 100644 index 1a2d8423..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedByPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CreatedByPropertySchema : IPropertySchema - { - [JsonProperty("created_by")] - public Dictionary CreatedBy { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedTimePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedTimePropertySchema.cs deleted file mode 100644 index 5e64ea2e..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/CreatedTimePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CreatedTimePropertySchema : IPropertySchema - { - [JsonProperty("created_time")] - public Dictionary CreatedTime { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/DatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/DatePropertySchema.cs deleted file mode 100644 index 1dc37c20..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/DatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class DatePropertySchema : IPropertySchema - { - [JsonProperty("date")] - public Dictionary Date { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/EmailPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/EmailPropertySchema.cs deleted file mode 100644 index 6a680c2b..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/EmailPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class EmailPropertySchema : IPropertySchema - { - [JsonProperty("email")] - public Dictionary Email { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FilePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FilePropertySchema.cs deleted file mode 100644 index 4591a3fc..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FilePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class FilePropertySchema : IPropertySchema - { - [JsonProperty("files")] - public Dictionary Files { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FormulaPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FormulaPropertySchema.cs deleted file mode 100644 index 97e7cb33..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/FormulaPropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class FormulaPropertySchema : IPropertySchema - { - [JsonProperty("formula")] - public Formula Formula { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/IPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/IPropertySchema.cs deleted file mode 100644 index f8b8ebf8..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/IPropertySchema.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Notion.Client -{ - public interface IPropertySchema - { - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedByPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedByPropertySchema.cs deleted file mode 100644 index c5e797e7..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedByPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class LastEditedByPropertySchema : IPropertySchema - { - [JsonProperty("last_edited_by")] - public Dictionary LastEditedBy { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedTimePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedTimePropertySchema.cs deleted file mode 100644 index 47662e88..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/LastEditedTimePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class LastEditedTimePropertySchema : IPropertySchema - { - [JsonProperty("last_edited_time")] - public Dictionary LastEditedTime { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs deleted file mode 100644 index a13d0930..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectOptionSchema.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace Notion.Client -{ - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] - public class MultiSelectOptionSchema : SelectOptionSchema - { - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectPropertySchema.cs deleted file mode 100644 index 1417d3f5..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/MultiSelectPropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class MultiSelectPropertySchema : IPropertySchema - { - [JsonProperty("multi_select")] - public OptionWrapper MultiSelect { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/NumberPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/NumberPropertySchema.cs deleted file mode 100644 index dbb7fa28..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/NumberPropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class NumberPropertySchema : IPropertySchema - { - [JsonProperty("number")] - public Number Number { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PeoplePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PeoplePropertySchema.cs deleted file mode 100644 index 5293746c..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PeoplePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class PeoplePropertySchema : IPropertySchema - { - [JsonProperty("people")] - public Dictionary People { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PhoneNumberPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PhoneNumberPropertySchema.cs deleted file mode 100644 index b4b6d363..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/PhoneNumberPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class PhoneNumberPropertySchema : IPropertySchema - { - [JsonProperty("phone_number")] - public Dictionary PhoneNumber { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs deleted file mode 100644 index 4c278ac2..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RelationPropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RelationPropertySchema : IPropertySchema - { - [JsonProperty("relation")] - public RelationData Relation { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RichTextPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RichTextPropertySchema.cs deleted file mode 100644 index f3c7e1e8..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RichTextPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RichTextPropertySchema : IPropertySchema - { - [JsonProperty("rich_text")] - public Dictionary RichText { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RollupConfigPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RollupConfigPropertySchema.cs deleted file mode 100644 index ac3c5220..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/RollupConfigPropertySchema.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RollupConfigPropertySchema : IPropertySchema - { - [JsonProperty("relation_property_name")] - public string RelationPropertyName { get; set; } - - [JsonProperty("relation_property_id")] - public string RelationPropertyId { get; set; } - - [JsonProperty("rollup_property_name")] - public string RollupPropertyName { get; set; } - - [JsonProperty("rollup_property_id")] - public string RollupPropertyId { get; set; } - - [JsonProperty("function")] - public string Function { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectOptionSchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectOptionSchema.cs deleted file mode 100644 index b7fd8d82..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectOptionSchema.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace Notion.Client -{ - public class SelectOptionSchema - { - [JsonProperty("name")] - public string Name { get; set; } - - [JsonProperty("color")] - [JsonConverter(typeof(StringEnumConverter))] - public Color? Color { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectPropertySchema.cs deleted file mode 100644 index 6e764bf3..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/SelectPropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class SelectPropertySchema : IPropertySchema - { - [JsonProperty("select")] - public OptionWrapper Select { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/TitlePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/TitlePropertySchema.cs deleted file mode 100644 index b7fb2f72..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/TitlePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class TitlePropertySchema : IPropertySchema - { - [JsonProperty("title")] - public Dictionary Title { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/UrlPropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/UrlPropertySchema.cs deleted file mode 100644 index 0860fa97..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesCreateParameters/PropertySchema/UrlPropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class UrlPropertySchema : IPropertySchema - { - [JsonProperty("url")] - public Dictionary Url { get; set; } - } -} From 1727850603e251cf7bfe5a77f25dfbfab943fd5c Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 04:46:42 +0530 Subject: [PATCH 14/27] Enhance DateCustomConverter to handle timezone offsets and improve serialization/deserialization tests --- .../PropertyValue/DateCustomConverter.cs | 14 +- .../DateCustomConverterTests.cs | 194 ++++++++++++++++++ 2 files changed, 201 insertions(+), 7 deletions(-) diff --git a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs index 37b84bc5..2cd62779 100644 --- a/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs +++ b/Src/Notion.Client/Models/PropertyValue/DateCustomConverter.cs @@ -21,10 +21,10 @@ public override Date ReadJson(JsonReader reader, Type objectType, Date existingV var date = new Date { - Start = ParseDateTime(jsonObject.Start, out bool includeTime), - End = ParseDateTime(jsonObject.End, out _), + Start = ParseDateTime(jsonObject.Start, out bool startIncludeTime), + End = ParseDateTime(jsonObject.End, out bool endIncludeTime), TimeZone = jsonObject.TimeZone, - IncludeTime = includeTime, + IncludeTime = startIncludeTime || endIncludeTime, }; return date; @@ -45,14 +45,14 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser { string startFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("start"); - writer.WriteValue(value.Start.Value.ToString(startFormat, CultureInfo.InvariantCulture)); + writer.WriteValue(value.Start.Value.ToUniversalTime().ToString(startFormat, CultureInfo.InvariantCulture)); } if (value.End.HasValue) { string endFormat = value.IncludeTime ? DateTimeFormat : DateFormat; writer.WritePropertyName("end"); - writer.WriteValue(value.End.Value.ToString(endFormat, CultureInfo.InvariantCulture)); + writer.WriteValue(value.End.Value.ToUniversalTime().ToString(endFormat, CultureInfo.InvariantCulture)); } if (!string.IsNullOrEmpty(value.TimeZone)) @@ -64,7 +64,7 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser writer.WriteEndObject(); } - private static DateTime? ParseDateTime(string dateTimeString, out bool includeTime) + private static DateTimeOffset? ParseDateTime(string dateTimeString, out bool includeTime) { includeTime = false; @@ -75,7 +75,7 @@ public override void WriteJson(JsonWriter writer, Date value, JsonSerializer ser includeTime = dateTimeString.Contains("T") || dateTimeString.Contains(" "); - return DateTimeOffset.Parse(dateTimeString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal).UtcDateTime; + return DateTimeOffset.Parse(dateTimeString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); } } } diff --git a/Test/Notion.UnitTests/DateCustomConverterTests.cs b/Test/Notion.UnitTests/DateCustomConverterTests.cs index 81c33f57..b31833c6 100644 --- a/Test/Notion.UnitTests/DateCustomConverterTests.cs +++ b/Test/Notion.UnitTests/DateCustomConverterTests.cs @@ -216,4 +216,198 @@ public void Round_trip_preserves_data() Assert.Equal(originalDate.TimeZone, deserializedDate.TimeZone); Assert.True(deserializedDate.IncludeTime); } + + [Fact] + public void Serialize_with_timezone_offset_converts_to_utc() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.FromHours(2)), // +02:00 offset + End = new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.FromHours(-5)), // -05:00 offset + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert - dates should be converted to UTC + Assert.Contains("\"start\":\"2023-05-15T12:30:45Z\"", json); // 14:30:45 +02:00 -> 12:30:45 UTC + Assert.Contains("\"end\":\"2023-05-20T21:45:00Z\"", json); // 16:45:00 -05:00 -> 21:45:00 UTC + } + + [Fact] + public void Deserialize_with_timezone_offset_preserves_utc() + { + // Arrange - API returns UTC dates + const string Json = "{\"start\":\"2023-05-15T12:30:45Z\",\"end\":\"2023-05-20T21:45:00Z\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 12, 30, 45, TimeSpan.Zero), result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 21, 45, 0, TimeSpan.Zero), result.End); + Assert.True(result.IncludeTime); + } + + [Fact] + public void Round_trip_with_timezone_offsets_preserves_utc_equivalent() + { + // Arrange - date with timezone offset + var originalDate = new Date + { + Start = new DateTimeOffset(2024, 6, 26, 0, 0, 0, TimeSpan.FromHours(1)), // +01:00 offset + End = new DateTimeOffset(2025, 12, 8, 0, 0, 0, TimeSpan.Zero), // UTC + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(originalDate); + var deserializedDate = JsonConvert.DeserializeObject(json); + + // Assert - should preserve the UTC equivalent times + Assert.NotNull(deserializedDate); + // Start: 2024-06-26T00:00:00+01:00 -> 2024-06-25T23:00:00Z + Assert.Equal(new DateTimeOffset(2024, 6, 25, 23, 0, 0, TimeSpan.Zero), deserializedDate.Start); + Assert.Equal(new DateTimeOffset(2025, 12, 8, 0, 0, 0, TimeSpan.Zero), deserializedDate.End); + Assert.True(deserializedDate.IncludeTime); + } + + [Fact] + public void Serialize_date_only_without_time_uses_date_format() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.FromHours(2)), + End = new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.FromHours(-3)), + IncludeTime = false + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert - should use date format (yyyy-MM-dd) regardless of timezone + Assert.Contains("\"start\":\"2023-05-15\"", json); + Assert.Contains("\"end\":\"2023-05-20\"", json); + } + + [Fact] + public void Deserialize_empty_start_string_returns_null_start() + { + // Arrange + const string Json = "{\"start\":\"\",\"end\":\"2023-05-20\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Null(result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 0, 0, 0, TimeSpan.Zero), result.End); + Assert.False(result.IncludeTime); // Should be false since Start is null + } + + [Fact] + public void Deserialize_with_space_separator_sets_include_time_flag() + { + // Arrange - some systems might use space instead of T + const string Json = "{\"start\":\"2023-05-15 14:30:45\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), result.Start); + Assert.True(result.IncludeTime); + } + + [Fact] + public void Serialize_only_start_date_omits_end_property() + { + // Arrange + var date = new Date + { + Start = new DateTimeOffset(2023, 5, 15, 14, 30, 45, TimeSpan.Zero), + End = null, + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.Contains("\"start\":\"2023-05-15T14:30:45Z\"", json); + Assert.DoesNotContain("\"end\":", json); + } + + [Fact] + public void Serialize_only_end_date_omits_start_property() + { + // Arrange + var date = new Date + { + Start = null, + End = new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.Zero), + IncludeTime = true + }; + + // Act + var json = JsonConvert.SerializeObject(date); + + // Assert + Assert.DoesNotContain("\"start\":", json); + Assert.Contains("\"end\":\"2023-05-20T16:45:00Z\"", json); + } + + [Fact] + public void Deserialize_with_only_end_time_sets_include_time_flag() + { + // Arrange - Only end date has time, start is date-only + const string Json = "{\"start\":\"2023-05-15\",\"end\":\"2023-05-20T16:45:00\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 0, 0, 0, TimeSpan.Zero), result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 16, 45, 0, TimeSpan.Zero), result.End); + Assert.True(result.IncludeTime); // Should be true because End has time + } + + [Fact] + public void Deserialize_with_only_start_time_sets_include_time_flag() + { + // Arrange - Only start date has time, end is date-only + const string Json = "{\"start\":\"2023-05-15T14:30:00\",\"end\":\"2023-05-20\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 14, 30, 0, TimeSpan.Zero), result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 0, 0, 0, TimeSpan.Zero), result.End); + Assert.True(result.IncludeTime); // Should be true because Start has time + } + + [Fact] + public void Deserialize_with_neither_start_nor_end_time_clears_include_time_flag() + { + // Arrange - Both dates are date-only + const string Json = "{\"start\":\"2023-05-15\",\"end\":\"2023-05-20\"}"; + + // Act + var result = JsonConvert.DeserializeObject(Json); + + // Assert + Assert.NotNull(result); + Assert.Equal(new DateTimeOffset(2023, 5, 15, 0, 0, 0, TimeSpan.Zero), result.Start); + Assert.Equal(new DateTimeOffset(2023, 5, 20, 0, 0, 0, TimeSpan.Zero), result.End); + Assert.False(result.IncludeTime); // Should be false because neither has time + } } From 2c0714af054c951ff7047f00749d6202f9430e5f Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 04:50:48 +0530 Subject: [PATCH 15/27] Refactor PagesCreateParameters to use updated request models and clean up SearchClientTest assertions --- Test/Notion.UnitTests/PagesClientTests.cs | 4 ++-- Test/Notion.UnitTests/SearchClientTest.cs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Test/Notion.UnitTests/PagesClientTests.cs b/Test/Notion.UnitTests/PagesClientTests.cs index 4dc75380..4141d8a6 100644 --- a/Test/Notion.UnitTests/PagesClientTests.cs +++ b/Test/Notion.UnitTests/PagesClientTests.cs @@ -57,7 +57,7 @@ public async Task CreateAsync() ); var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = "3c357473-a281-49a4-88c0-10d2b245a589" }) + .Create(new DatabaseParentRequest { DatabaseId = "3c357473-a281-49a4-88c0-10d2b245a589" }) .AddProperty( "Name", new TitlePropertyValue @@ -258,7 +258,7 @@ public async Task CreateAsync_Throws_ArgumentNullException_When_Properties_Is_Mi { var pagesCreateParameters = new PagesCreateParameters { - Parent = new ParentPageInput { PageId = "3c357473-a281-49a4-88c0-10d2b245a589" }, + Parent = new PageParentRequest { PageId = "3c357473-a281-49a4-88c0-10d2b245a589" }, Properties = null }; diff --git a/Test/Notion.UnitTests/SearchClientTest.cs b/Test/Notion.UnitTests/SearchClientTest.cs index a5a477cb..df547059 100644 --- a/Test/Notion.UnitTests/SearchClientTest.cs +++ b/Test/Notion.UnitTests/SearchClientTest.cs @@ -50,9 +50,6 @@ public async Task Search() obj => { obj.Object.Should().Be(ObjectType.Database); - - var database = (Database)obj; - database.Properties.Should().HaveCount(2); }, obj => { From 0d387b0639a6e1d1516944a9d936555ca2ba010a Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:16:03 +0530 Subject: [PATCH 16/27] Refactor LinkToPage handling to use new ILinkToPage interface and update related classes --- .../UpdateBlocks/LinkToPageUpdateBlock.cs | 2 +- .../Models/Blocks/LinkToPageBlock.cs | 2 +- .../Blocks/Request/LinkToPageBlock/ILinkToPage.cs | 15 +++++++++++++++ .../Request/LinkToPageBlock/LinkCommentToPage.cs | 13 +++++++++++++ .../Request/LinkToPageBlock/LinkDatabaseToPage.cs | 13 +++++++++++++ .../Request/LinkToPageBlock/LinkPageToPage.cs | 13 +++++++++++++ .../LinkToPageBlockRequest.cs | 2 +- Test/Notion.IntegrationTests/BlocksClientTests.cs | 9 ++++----- 8 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/ILinkToPage.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkCommentToPage.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkDatabaseToPage.cs create mode 100644 Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkPageToPage.cs rename Src/Notion.Client/Models/Blocks/Request/{ => LinkToPageBlock}/LinkToPageBlockRequest.cs (84%) diff --git a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs index 69e088c5..4a62224a 100644 --- a/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs +++ b/Src/Notion.Client/Api/Blocks/RequestParams/BlocksUpdateParameters/UpdateBlocks/LinkToPageUpdateBlock.cs @@ -5,6 +5,6 @@ namespace Notion.Client public class LinkToPageUpdateBlock : UpdateBlock { [JsonProperty("link_to_page")] - public IPageParentInput LinkToPage { get; set; } + public ILinkToPage LinkToPage { get; set; } } } diff --git a/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs b/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs index ad688ca2..bfba462d 100644 --- a/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs +++ b/Src/Notion.Client/Models/Blocks/LinkToPageBlock.cs @@ -5,7 +5,7 @@ namespace Notion.Client public class LinkToPageBlock : Block, IColumnChildrenBlock, INonColumnBlock { [JsonProperty("link_to_page")] - public IPageParent LinkToPage { get; set; } + public ILinkToPage LinkToPage { get; set; } public override BlockType Type => BlockType.LinkToPage; } diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/ILinkToPage.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/ILinkToPage.cs new file mode 100644 index 00000000..04b24273 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/ILinkToPage.cs @@ -0,0 +1,15 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "type")] + [JsonSubtypes.KnownSubType(typeof(LinkPageToPage), "page_id")] + [JsonSubtypes.KnownSubType(typeof(LinkDatabaseToPage), "database_id")] + [JsonSubtypes.KnownSubType(typeof(LinkCommentToPage), "comment_id")] + public interface ILinkToPage + { + [JsonProperty("type")] + string Type { get; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkCommentToPage.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkCommentToPage.cs new file mode 100644 index 00000000..c3f5e30a --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkCommentToPage.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkCommentToPage : ILinkToPage + { + [JsonProperty("type")] + public string Type => "comment_id"; + + [JsonProperty("comment_id")] + public string CommentId { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkDatabaseToPage.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkDatabaseToPage.cs new file mode 100644 index 00000000..6985e4f8 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkDatabaseToPage.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkDatabaseToPage : ILinkToPage + { + [JsonProperty("type")] + public string Type => "database_id"; + + [JsonProperty("database_id")] + public string DatabaseId { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkPageToPage.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkPageToPage.cs new file mode 100644 index 00000000..3fc0f794 --- /dev/null +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkPageToPage.cs @@ -0,0 +1,13 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class LinkPageToPage : ILinkToPage + { + [JsonProperty("type")] + public string Type => "page_id"; + + [JsonProperty("page_id")] + public string PageId { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkToPageBlockRequest.cs similarity index 84% rename from Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs rename to Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkToPageBlockRequest.cs index ec182df5..d80a3f65 100644 --- a/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlockRequest.cs +++ b/Src/Notion.Client/Models/Blocks/Request/LinkToPageBlock/LinkToPageBlockRequest.cs @@ -5,7 +5,7 @@ namespace Notion.Client public class LinkToPageBlockRequest : BlockObjectRequest, IColumnChildrenBlockRequest, INonColumnBlockRequest { [JsonProperty("link_to_page")] - public IPageParent LinkToPage { get; set; } + public ILinkToPage LinkToPage { get; set; } public override BlockType Type => BlockType.LinkToPage; } diff --git a/Test/Notion.IntegrationTests/BlocksClientTests.cs b/Test/Notion.IntegrationTests/BlocksClientTests.cs index 5f1ca25b..81d6e0b6 100644 --- a/Test/Notion.IntegrationTests/BlocksClientTests.cs +++ b/Test/Notion.IntegrationTests/BlocksClientTests.cs @@ -16,7 +16,7 @@ public async Task InitializeAsync() { _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } + new PageParentRequest { PageId = ParentPageId } ).Build() ); } @@ -338,22 +338,21 @@ private static IEnumerable BlockData() { new LinkToPageBlockRequest { - LinkToPage = new PageParent + LinkToPage = new LinkPageToPage { - Type = ParentType.PageId, PageId = "533578e3edf14c0a91a9da6b09bac3ee" } }, new LinkToPageUpdateBlock { - LinkToPage = new ParentPageInput { PageId = "3c357473a28149a488c010d2b245a589" } + LinkToPage = new LinkPageToPage { PageId = "3c357473a28149a488c010d2b245a589" } }, new Action((block, _) => { Assert.NotNull(block); var linkToPageBlock = Assert.IsType(block); - var pageParent = Assert.IsType(linkToPageBlock.LinkToPage); + var pageParent = Assert.IsType(linkToPageBlock.LinkToPage); // TODO: Currently the api doesn't allow to update the link_to_page block type // This will change to updated ID once api start to support From 568d8b04773bf7f57e4e1a5b26c06ebdffa61ac5 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:17:27 +0530 Subject: [PATCH 17/27] Add DataSourceParent class and update ParentType enum to include DataSourceId --- Src/Notion.Client/Models/Page/IPageParent.cs | 1 + Src/Notion.Client/Models/Parents/DataSourceParent.cs | 12 ++++++++++++ Src/Notion.Client/Models/Parents/ParentType.cs | 5 ++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Src/Notion.Client/Models/Parents/DataSourceParent.cs diff --git a/Src/Notion.Client/Models/Page/IPageParent.cs b/Src/Notion.Client/Models/Page/IPageParent.cs index b9111d91..f2f4499f 100644 --- a/Src/Notion.Client/Models/Page/IPageParent.cs +++ b/Src/Notion.Client/Models/Page/IPageParent.cs @@ -8,6 +8,7 @@ namespace Notion.Client [JsonSubtypes.KnownSubTypeAttribute(typeof(PageParent), ParentType.PageId)] [JsonSubtypes.KnownSubTypeAttribute(typeof(WorkspaceParent), ParentType.Workspace)] [JsonSubtypes.KnownSubTypeAttribute(typeof(BlockParent), ParentType.BlockId)] + [JsonSubtypes.KnownSubTypeAttribute(typeof(DataSourceParent), ParentType.DataSourceId)] public interface IPageParent : IParent { } diff --git a/Src/Notion.Client/Models/Parents/DataSourceParent.cs b/Src/Notion.Client/Models/Parents/DataSourceParent.cs new file mode 100644 index 00000000..3571f4d4 --- /dev/null +++ b/Src/Notion.Client/Models/Parents/DataSourceParent.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceParent : IPageParent + { + public ParentType Type { get; set; } + + [JsonProperty("data_source_id")] + public string DataSourceId { get; set; } + } +} \ No newline at end of file diff --git a/Src/Notion.Client/Models/Parents/ParentType.cs b/Src/Notion.Client/Models/Parents/ParentType.cs index 347414f9..fa037ab5 100644 --- a/Src/Notion.Client/Models/Parents/ParentType.cs +++ b/Src/Notion.Client/Models/Parents/ParentType.cs @@ -19,6 +19,9 @@ public enum ParentType Workspace, [EnumMember(Value = "block_id")] - BlockId + BlockId, + + [EnumMember(Value = "data_source_id")] + DataSourceId } } From 7645fb272d8e657b73d56af2ff41558fc4ec0b58 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:18:22 +0530 Subject: [PATCH 18/27] Refactor parent input handling by removing obsolete classes and introducing new request models for page and database parents --- .../Create/Request/ParentPageInput.cs | 2 +- .../DatabaseParentInput.cs | 10 --------- .../PagesCreateParameters/IPageParentInput.cs | 6 ------ .../IPagesCreateBodyParameters.cs | 2 +- .../PagesCreateParameters.cs | 3 ++- .../PagesCreateParametersBuilder.cs | 4 ++-- .../Parents/DataSourceParentRequest.cs | 21 +++++++++++++++++++ .../Request/Parents/DatabaseParentRequest.cs | 2 +- .../Parents/IParentOfDatabaseRequest.cs | 10 +++++++++ .../Request/Parents/PageParentRequest.cs | 21 +++++++++++++++++++ .../Request/Parents/WorkspaceParentRequest.cs | 21 +++++++++++++++++++ 11 files changed, 80 insertions(+), 22 deletions(-) delete mode 100644 Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/DatabaseParentInput.cs delete mode 100644 Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPageParentInput.cs create mode 100644 Src/Notion.Client/Models/Request/Parents/DataSourceParentRequest.cs rename Src/Notion.Client/{Api/DataSources => }/Models/Request/Parents/DatabaseParentRequest.cs (95%) create mode 100644 Src/Notion.Client/Models/Request/Parents/IParentOfDatabaseRequest.cs create mode 100644 Src/Notion.Client/Models/Request/Parents/PageParentRequest.cs create mode 100644 Src/Notion.Client/Models/Request/Parents/WorkspaceParentRequest.cs diff --git a/Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs b/Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs index f931de63..fcd7cbc8 100644 --- a/Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs +++ b/Src/Notion.Client/Api/Databases/Create/Request/ParentPageInput.cs @@ -2,7 +2,7 @@ namespace Notion.Client { - public class ParentPageInput : IPageParentInput + public class ParentPageInput { [JsonProperty("page_id")] public string PageId { get; set; } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/DatabaseParentInput.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/DatabaseParentInput.cs deleted file mode 100644 index 285a63fa..00000000 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/DatabaseParentInput.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class DatabaseParentInput : IPageParentInput - { - [JsonProperty("database_id")] - public string DatabaseId { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPageParentInput.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPageParentInput.cs deleted file mode 100644 index f355b3ea..00000000 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPageParentInput.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Notion.Client -{ - public interface IPageParentInput - { - } -} diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPagesCreateBodyParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPagesCreateBodyParameters.cs index 9b9f0631..c59dc8d5 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPagesCreateBodyParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/IPagesCreateBodyParameters.cs @@ -6,7 +6,7 @@ namespace Notion.Client public interface IPagesCreateBodyParameters { [JsonProperty("parent")] - IPageParentInput Parent { get; set; } + IParentOfPageRequest Parent { get; set; } [JsonProperty("properties")] IDictionary Properties { get; set; } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs index 08572811..c41722c6 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParameters.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using Newtonsoft.Json; namespace Notion.Client { public class PagesCreateParameters : IPagesCreateBodyParameters, IPagesCreateQueryParameters { - public IPageParentInput Parent { get; set; } + public IParentOfPageRequest Parent { get; set; } public IDictionary Properties { get; set; } diff --git a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs index ed85117d..46980175 100644 --- a/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs +++ b/Src/Notion.Client/Api/Pages/RequestParams/PagesCreateParameters/PagesCreateParametersBuilder.cs @@ -10,13 +10,13 @@ public class PagesCreateParametersBuilder private readonly Dictionary _properties = new(); private FileObject _cover; private IPageIcon _icon; - private IPageParentInput _parent; + private IParentOfPageRequest _parent; private PagesCreateParametersBuilder() { } - public static PagesCreateParametersBuilder Create(IPageParentInput parent) + public static PagesCreateParametersBuilder Create(IParentOfPageRequest parent) { return new PagesCreateParametersBuilder { _parent = parent }; } diff --git a/Src/Notion.Client/Models/Request/Parents/DataSourceParentRequest.cs b/Src/Notion.Client/Models/Request/Parents/DataSourceParentRequest.cs new file mode 100644 index 00000000..e97c3e10 --- /dev/null +++ b/Src/Notion.Client/Models/Request/Parents/DataSourceParentRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DataSourceParentRequest : IParentOfPageRequest + { + [JsonProperty("type")] + public string Type => "data_source_id"; + + [JsonProperty("data_source_id")] + public string DataSourceId { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs b/Src/Notion.Client/Models/Request/Parents/DatabaseParentRequest.cs similarity index 95% rename from Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs rename to Src/Notion.Client/Models/Request/Parents/DatabaseParentRequest.cs index 312302d2..4903f762 100644 --- a/Src/Notion.Client/Api/DataSources/Models/Request/Parents/DatabaseParentRequest.cs +++ b/Src/Notion.Client/Models/Request/Parents/DatabaseParentRequest.cs @@ -3,7 +3,7 @@ namespace Notion.Client { - public class DatabaseParentRequest : IParentOfDataSourceRequest + public class DatabaseParentRequest : IParentOfDataSourceRequest, IParentOfPageRequest { [JsonProperty("type")] public string Type => "database_id"; diff --git a/Src/Notion.Client/Models/Request/Parents/IParentOfDatabaseRequest.cs b/Src/Notion.Client/Models/Request/Parents/IParentOfDatabaseRequest.cs new file mode 100644 index 00000000..1fe47961 --- /dev/null +++ b/Src/Notion.Client/Models/Request/Parents/IParentOfDatabaseRequest.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json; + +namespace Notion.Client +{ + public interface IParentOfPageRequest + { + [JsonProperty("type")] + string Type { get; } + } +} diff --git a/Src/Notion.Client/Models/Request/Parents/PageParentRequest.cs b/Src/Notion.Client/Models/Request/Parents/PageParentRequest.cs new file mode 100644 index 00000000..49c2a1f3 --- /dev/null +++ b/Src/Notion.Client/Models/Request/Parents/PageParentRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class PageParentRequest : IParentOfPageRequest + { + [JsonProperty("type")] + public string Type => "page_id"; + + [JsonProperty("page_id")] + public string PageId { get; set; } + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} diff --git a/Src/Notion.Client/Models/Request/Parents/WorkspaceParentRequest.cs b/Src/Notion.Client/Models/Request/Parents/WorkspaceParentRequest.cs new file mode 100644 index 00000000..44e92fc5 --- /dev/null +++ b/Src/Notion.Client/Models/Request/Parents/WorkspaceParentRequest.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class WorkspaceParentRequest : IParentOfPageRequest + { + [JsonProperty("type")] + public string Type => "workspace"; + + [JsonProperty("workspace")] + public bool Workspace => true; + + /// + /// Additional data for future compatibility + /// If you encounter properties that are not yet supported, please open an issue on GitHub. + /// + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } + } +} From 75c74e0e6a55520fabca4ba77e6246bfcc393ec5 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:18:37 +0530 Subject: [PATCH 19/27] Refactor page parent handling in tests to use new PageParentRequest class --- .../PageClientTests.cs | 144 ++++++++++-------- .../PageWithPageParentTests.cs | 2 +- 2 files changed, 84 insertions(+), 62 deletions(-) diff --git a/Test/Notion.IntegrationTests/PageClientTests.cs b/Test/Notion.IntegrationTests/PageClientTests.cs index 4938bcfa..b52d6b9a 100644 --- a/Test/Notion.IntegrationTests/PageClientTests.cs +++ b/Test/Notion.IntegrationTests/PageClientTests.cs @@ -18,12 +18,12 @@ public async Task InitializeAsync() // Create a page _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } + new PageParentRequest { PageId = ParentPageId } ).Build() ); // Create a database - var createDbRequest = new DatabasesCreateParameters + var createDbRequest = new DatabasesCreateRequest { Title = new List { @@ -36,26 +36,29 @@ public async Task InitializeAsync() } } }, - Properties = new Dictionary + InitialDataSource = new InitialDataSourceRequest { - { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + Properties = new Dictionary { - "TestSelect", - new SelectPropertySchema + { "Name", new TitlePropertyConfigurationRequest { Title = new Dictionary() } }, { - Select = new OptionWrapper + "TestSelect", + new SelectPropertyConfigurationRequest { - Options = new List + Select = new SelectPropertyConfigurationRequest.SelectOptions { - new() { Name = "Red" }, - new() { Name = "Blue" } + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Blue" } + } } } - } - }, - { "Number", new NumberPropertySchema { Number = new Number { Format = "number" } } } + }, + { "Number", new NumberPropertyConfigurationRequest { Number = new NumberPropertyConfigurationRequest.NumberFormat { Format = "number" } } } + } }, - Parent = new ParentPageInput { PageId = _page.Id } + Parent = new PageParentOfDatabaseRequest { PageId = _page.Id } }; _database = await Client.Databases.CreateAsync(createDbRequest); @@ -70,7 +73,7 @@ public async Task DisposeAsync() public async Task CreateAsync_CreatesANewPage() { var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -85,8 +88,8 @@ public async Task CreateAsync_CreatesANewPage() page.Should().NotBeNull(); - page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(_database.Id); + page.Parent.Should().BeOfType().Which + .DataSourceId.Should().Be(_database.DataSources.First().DataSourceId); page.Properties.Should().ContainKey("Name"); var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; @@ -107,7 +110,7 @@ public async Task Bug_unable_to_create_page_with_select_property() { // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -126,8 +129,8 @@ public async Task Bug_unable_to_create_page_with_select_property() // Asserts page.Should().NotBeNull(); - page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(_database.Id); + page.Parent.Should().BeOfType().Which + .DataSourceId.Should().Be(_database.DataSources.First().DataSourceId); page.Properties.Should().ContainKey("Name"); var titlePropertyValue = page.Properties["Name"].Should().BeOfType().Subject; @@ -143,7 +146,7 @@ public async Task Test_RetrievePagePropertyItemAsync() { // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -188,21 +191,34 @@ public async Task Test_UpdatePageProperty_with_date_as_null() // Add property Date property to database const string DatePropertyName = "Test Date Property"; - var updateDatabaseParameters = new DatabasesUpdateParameters + var updateDatabaseParameters = new UpdateDataSourceRequest { - Properties = new Dictionary + DataSourceId = _database.DataSources.First().DataSourceId, + Properties = new Dictionary { - { "Name", new TitleUpdatePropertySchema { Title = new Dictionary() } }, + { + "Name", + new UpdatePropertyConfigurationRequest { + PropertyRequest = new TitlePropertyConfigurationRequest { Title = new Dictionary() } + } + }, { "Test Date Property", - new DateUpdatePropertySchema { Date = new Dictionary() } + new UpdatePropertyConfigurationRequest + { + Name = DatePropertyName, + PropertyRequest = new DatePropertyConfigurationRequest + { + Date = new Dictionary() + } + } } } }; // Create a page with the property having a date var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -217,12 +233,13 @@ public async Task Test_UpdatePageProperty_with_date_as_null() Date = new Date { Start = DateTimeOffset.Parse("2024-06-26T00:00:00.000+01:00"), - End = DateTimeOffset.Parse("2025-12-08").Date + End = DateTimeOffset.Parse("2025-12-08").Date, + IncludeTime = true } }) .Build(); - await Client.Databases.UpdateAsync(_database.Id, updateDatabaseParameters); + await Client.DataSources.UpdateAsync(updateDatabaseParameters); var page = await Client.Pages.CreateAsync(pagesCreateParameters); @@ -237,7 +254,7 @@ public async Task Test_UpdatePageProperty_with_date_as_null() // Assert setDate?.Date?.Start.Should().Be(DateTimeOffset.Parse("2024-06-26T00:00:00.000+01:00")); - setDate?.Date?.End.Should().Be(DateTimeOffset.Parse("2025-12-08T00:00:00.000+01:00")); + setDate?.Date?.End.Should().Be(DateTimeOffset.Parse("2025-12-08").Date); var pageUpdateParameters = new PagesUpdateParameters { @@ -265,7 +282,7 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() { // Arrange var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -281,8 +298,8 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() // Assert Assert.NotNull(page); - var pageParent = Assert.IsType(page.Parent); - Assert.Equal(_database.Id, pageParent.DatabaseId); + var pageParent = Assert.IsType(page.Parent); + Assert.Equal(_database.DataSources.First().DataSourceId, pageParent.DataSourceId); var titleProperty = (ListPropertyItem)await Client.Pages.RetrievePagePropertyItemAsync( new RetrievePropertyItemParameters @@ -307,51 +324,56 @@ public async Task Bug_Unable_To_Parse_NumberPropertyItem() public async Task Bug_exception_when_attempting_to_set_select_property_to_nothing() { // Arrange - var databaseCreateRequest = new DatabasesCreateParameters + var databaseCreateRequest = new DatabasesCreateRequest { - Title = - new List { new RichTextTextInput { Text = new Text { Content = "Test Database" } } }, - Parent = new ParentPageInput() { PageId = _page.Id }, - Properties = new Dictionary + Title = new List { - { "title", new TitlePropertySchema { Title = new Dictionary() } }, + new RichTextTextInput { Text = new Text { Content = "Test Database" } } + }, + Parent = new PageParentOfDatabaseRequest() { PageId = _page.Id }, + InitialDataSource = new InitialDataSourceRequest + { + Properties = new Dictionary { - "Colors1", - new SelectPropertySchema + { "title", new TitlePropertyConfigurationRequest { Title = new Dictionary() } }, { - Select = new OptionWrapper + "Colors1", + new SelectPropertyConfigurationRequest { - Options = new List + Select = new SelectPropertyConfigurationRequest.SelectOptions { - new() { Name = "Red" }, - new() { Name = "Green" }, - new() { Name = "Blue" } + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Green" }, + new() { Name = "Blue" } + } } } - } - }, - { - "Colors2", - new SelectPropertySchema + }, { - Select = new OptionWrapper + "Colors2", + new SelectPropertyConfigurationRequest { - Options = new List + Select = new SelectPropertyConfigurationRequest.SelectOptions { - new() { Name = "Red" }, - new() { Name = "Green" }, - new() { Name = "Blue" } + Options = new List + { + new() { Name = "Red" }, + new() { Name = "Green" }, + new() { Name = "Blue" } + } } } - } - }, + }, + } } }; var database = await Client.Databases.CreateAsync(databaseCreateRequest); var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = database.DataSources.First().DataSourceId }) .AddProperty("title", new TitlePropertyValue { @@ -390,7 +412,7 @@ public async Task Bug_exception_when_attempting_to_set_select_property_to_nothin public async Task Verify_date_property_is_parsed_correctly_in_mention_object() { var pageRequest = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = _database.Id }) + .Create(new DataSourceParentRequest { DataSourceId = _database.DataSources.First().DataSourceId }) .AddProperty("Name", new TitlePropertyValue { @@ -414,8 +436,8 @@ public async Task Verify_date_property_is_parsed_correctly_in_mention_object() page.Should().NotBeNull(); - page.Parent.Should().BeOfType().Which - .DatabaseId.Should().Be(_database.Id); + page.Parent.Should().BeOfType().Which + .DataSourceId.Should().Be(_database.DataSources.First().DataSourceId); page.Properties.Should().ContainKey("Name"); var pageProperty = page.Properties["Name"].Should().BeOfType().Subject; diff --git a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs index 3c6d3c6c..12aa81f3 100644 --- a/Test/Notion.IntegrationTests/PageWithPageParentTests.cs +++ b/Test/Notion.IntegrationTests/PageWithPageParentTests.cs @@ -14,7 +14,7 @@ public class PageWithPageParentTests : IntegrationTestBase, IAsyncLifetime public async Task InitializeAsync() { var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new ParentPageInput() { PageId = ParentPageId }) + .Create(new PageParentRequest() { PageId = ParentPageId }) .AddProperty("title", new TitlePropertyValue { From 94e45419c88240861b6f8a1414f4498ffb2e2239 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Mon, 1 Dec 2025 05:18:49 +0530 Subject: [PATCH 20/27] Refactor Comments and Databases client tests to use PageParentRequest and DatabaseParentRequest classes --- .../CommentsClientTests.cs | 2 +- .../DatabasesClientTests.cs | 38 +++++++++++++------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Test/Notion.IntegrationTests/CommentsClientTests.cs b/Test/Notion.IntegrationTests/CommentsClientTests.cs index fac1fce1..0a8ff417 100644 --- a/Test/Notion.IntegrationTests/CommentsClientTests.cs +++ b/Test/Notion.IntegrationTests/CommentsClientTests.cs @@ -14,7 +14,7 @@ public async Task InitializeAsync() { _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } + new PageParentRequest { PageId = ParentPageId } ).Build() ); } diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index 7abd7b4e..ce8b11e2 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -16,7 +16,7 @@ public async Task InitializeAsync() { _page = await Client.Pages.CreateAsync( PagesCreateParametersBuilder.Create( - new ParentPageInput { PageId = ParentPageId } + new PageParentRequest { PageId = ParentPageId } ).Build() ); } @@ -83,6 +83,14 @@ public async Task UpdateDatabaseRelationProperties() }); // Assert + response.DataSources.Should().ContainSingle(); + await ValidateDatasourceProperties(response.DataSources.Single().DataSourceId, createdSourceDatabase.Id); + } + + private async Task ValidateDatasourceProperties(string dataSourceId, string sourceDatabaseId) + { + var response = await Client.DataSources.RetrieveAsync(new RetrieveDataSourceRequest { DataSourceId = dataSourceId }); + response.Properties.Should().NotBeNull(); response.Properties.Should().ContainKey("Single Relation"); @@ -90,20 +98,20 @@ public async Task UpdateDatabaseRelationProperties() singleRelation.Should().BeEquivalentTo( new SinglePropertyRelation { - DatabaseId = createdSourceDatabase.Id, + DatabaseId = sourceDatabaseId, SingleProperty = new Dictionary() }); response.Properties.Should().ContainKey("Dual Relation"); var dualRelation = response.Properties["Dual Relation"].As().Relation; - dualRelation.DatabaseId.Should().Be(createdSourceDatabase.Id); + dualRelation.DatabaseId.Should().Be(sourceDatabaseId); dualRelation.Type.Should().Be(RelationType.Dual); dualRelation.Should().BeOfType(); } private async Task CreateDatabaseWithAPageAsync(string databaseName) { - var createDbRequest = new DatabasesCreateParameters + var createDbRequest = new DatabasesCreateRequest { Title = new List { @@ -116,17 +124,20 @@ private async Task CreateDatabaseWithAPageAsync(string databaseName) } } }, - Properties = new Dictionary + InitialDataSource = new InitialDataSourceRequest { - { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + Properties = new Dictionary + { + { "Name", new TitlePropertyConfigurationRequest { Title = new Dictionary() } }, + } }, - Parent = new ParentPageInput { PageId = _page.Id } + Parent = new PageParentOfDatabaseRequest { PageId = _page.Id } }; var createdDatabase = await Client.Databases.CreateAsync(createDbRequest); var pagesCreateParameters = PagesCreateParametersBuilder - .Create(new DatabaseParentInput { DatabaseId = createdDatabase.Id }) + .Create(new DatabaseParentRequest { DatabaseId = createdDatabase.Id }) .AddProperty("Name", new TitlePropertyValue { @@ -146,7 +157,7 @@ private async Task CreateDatabaseWithAPageAsync(string databaseName) public async Task Verify_mention_date_property_parsed_properly() { // Arrange - var createDbRequest = new DatabasesCreateParameters + var createDbRequest = new DatabasesCreateRequest { Title = new List { @@ -170,11 +181,14 @@ public async Task Verify_mention_date_property_parsed_properly() } } }, - Properties = new Dictionary + InitialDataSource = new InitialDataSourceRequest { - { "Name", new TitlePropertySchema { Title = new Dictionary() } }, + Properties = new Dictionary + { + { "Name", new TitlePropertyConfigurationRequest { Title = new Dictionary() } }, + } }, - Parent = new ParentPageInput { PageId = _page.Id } + Parent = new PageParentOfDatabaseRequest { PageId = _page.Id } }; // Act From 99e27bbf7222e0dc0a97a8356f2e1c959cc50746 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:00:19 +0530 Subject: [PATCH 21/27] Add support for updating databases with new request model and properties --- .../RelationProperty/RelationDataResponse.cs | 3 + .../Api/Databases/DatabasesClient.cs | 7 - .../Api/Databases/IDatabasesClient.cs | 5 +- .../DatabasesUpdateParameters.cs | 21 --- .../DatabasesUpdateRequest.cs | 36 +++++ .../IDatabasesUpdateBodyParameters.cs | 9 +- .../CheckboxUpdatePropertySchema.cs | 11 -- .../CreatedByUpdatePropertySchema.cs | 11 -- .../CreatedTimeUpdatePropertySchema.cs | 11 -- .../DateUpdatePropertySchema.cs | 11 -- .../EmailUpdatePropertySchema.cs | 11 -- .../FilesUpdatePropertySchema.cs | 11 -- .../FormulaUpdatePropertySchema.cs | 10 -- .../PropertySchema/IUpdatePropertySchema.cs | 22 --- .../LastEditedByUpdatePropertySchema.cs | 11 -- .../LastEditedTimeUpdatePropertySchema.cs | 11 -- .../MultiSelectUpdatePropertySchema.cs | 10 -- .../NumberUpdatePropertySchema.cs | 10 -- .../PeopleUpdatePropertySchema.cs | 11 -- .../PhoneNumberUpdatePropertySchema.cs | 11 -- .../RelationUpdatePropertySchema.cs | 10 -- .../RichTextUpdatePropertySchema.cs | 11 -- .../RollupConfigUpdatePropertySchema.cs | 22 --- .../SelectUpdatePropertySchema.cs | 10 -- .../TitleUpdatePropertySchema.cs | 11 -- .../PropertySchema/URLUpdatePropertySchema.cs | 11 -- .../Api/Databases/Update/DatabasesClient.cs | 33 +++++ .../DataSourcesClientTests.cs | 133 +++++++++++++++++- .../DatabasesClientTests.cs | 94 ++++--------- 29 files changed, 241 insertions(+), 337 deletions(-) delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs create mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateRequest.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/IUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs delete mode 100644 Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs create mode 100644 Src/Notion.Client/Api/Databases/Update/DatabasesClient.cs diff --git a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs index 19d8877f..74c8c3ef 100644 --- a/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs +++ b/Src/Notion.Client/Api/DataSources/Models/PropertyConfig/RelationProperty/RelationDataResponse.cs @@ -13,6 +13,9 @@ public abstract class RelationDataResponse [JsonProperty("database_id")] public string DatabaseId { get; set; } + [JsonProperty("data_source_id")] + public string DataSourceId { get; set; } + [JsonProperty("type")] [JsonConverter(typeof(StringEnumConverter))] public virtual string Type { get; set; } diff --git a/Src/Notion.Client/Api/Databases/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/DatabasesClient.cs index 567fec52..8bb428f4 100644 --- a/Src/Notion.Client/Api/Databases/DatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/DatabasesClient.cs @@ -23,12 +23,5 @@ public async Task RetrieveAsync(string databaseId, CancellationToken c return await _client.GetAsync(DatabasesApiUrls.Retrieve(databaseId), cancellationToken: cancellationToken); } - - public async Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default) - { - var body = (IDatabasesUpdateBodyParameters)databasesUpdateParameters; - - return await _client.PatchAsync(DatabasesApiUrls.Update(databaseId), body, cancellationToken: cancellationToken); - } } } diff --git a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs index a21b8571..9fb1c233 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -38,11 +38,10 @@ public interface IDatabasesClient /// /// Updates an existing database as specified by the parameters. /// - /// - /// + /// /// /// /// - Task UpdateAsync(string databaseId, DatabasesUpdateParameters databasesUpdateParameters, CancellationToken cancellationToken = default); + Task UpdateAsync(DatabasesUpdateRequest databasesUpdateRequest, CancellationToken cancellationToken = default); } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs deleted file mode 100644 index 5147a6b0..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateParameters.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Collections.Generic; - -namespace Notion.Client -{ - public class DatabasesUpdateParameters : IDatabasesUpdateBodyParameters - { - public Dictionary Properties { get; set; } - - public List Title { get; set; } - - public IPageIcon Icon { get; set; } - - public FileObject Cover { get; set; } - - public bool InTrash { get; set; } - - public bool? IsInline { get; set; } - - public List Description { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateRequest.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateRequest.cs new file mode 100644 index 00000000..3a3c5fae --- /dev/null +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/DatabasesUpdateRequest.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Notion.Client +{ + public class DatabasesUpdateRequest : IDatabasesUpdatePathParameters, IDatabasesUpdateBodyParameters + { + public string DatabaseId { get; set; } + + public List Title { get; set; } + + public IPageIcon Icon { get; set; } + + public FileObject Cover { get; set; } + + public bool? InTrash { get; set; } + + public bool? IsInline { get; set; } + + public List Description { get; set; } + + public bool? IsLocked { get; set; } + + public IParentOfDatabaseRequest Parent { get; set; } + } + + public interface IDatabasesUpdatePathParameters + { + /// + /// The ID of the database to update. + /// + [JsonIgnore] + [JsonProperty("database_id")] + string DatabaseId { get; set; } + } +} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs index f37df431..d4499bb5 100644 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs +++ b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/IDatabasesUpdateBodyParameters.cs @@ -5,8 +5,8 @@ namespace Notion.Client { public interface IDatabasesUpdateBodyParameters { - [JsonProperty("properties")] - Dictionary Properties { get; set; } + [JsonProperty("parent")] + IParentOfDatabaseRequest Parent { get; set; } [JsonProperty("title")] List Title { get; set; } @@ -18,12 +18,15 @@ public interface IDatabasesUpdateBodyParameters FileObject Cover { get; set; } [JsonProperty("in_trash")] - bool InTrash { get; set; } + bool? InTrash { get; set; } [JsonProperty("is_inline")] bool? IsInline { get; set; } [JsonProperty("description")] List Description { get; set; } + + [JsonProperty("is_locked")] + bool? IsLocked { get; set; } } } diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs deleted file mode 100644 index a6890d6e..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CheckboxUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CheckboxUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("checkbox")] - public Dictionary Checkbox { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs deleted file mode 100644 index 08a5cf74..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedByUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CreatedByUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("created_by")] - public Dictionary CreatedBy { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs deleted file mode 100644 index 8089ecbb..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/CreatedTimeUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class CreatedTimeUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("created_time")] - public Dictionary CreatedTime { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs deleted file mode 100644 index 65487dd7..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/DateUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class DateUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("date")] - public Dictionary Date { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs deleted file mode 100644 index 5905e68e..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/EmailUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class EmailUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("email")] - public Dictionary Email { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs deleted file mode 100644 index 9fb3b531..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FilesUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class FilesUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("files")] - public Dictionary Files { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs deleted file mode 100644 index 40cc398a..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/FormulaUpdatePropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class FormulaUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("formula")] - public Formula Formula { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/IUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/IUpdatePropertySchema.cs deleted file mode 100644 index d0232472..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/IUpdatePropertySchema.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; - -namespace Notion.Client -{ - public interface IUpdatePropertySchema - { - [JsonProperty("name")] - string Name { get; set; } - - [JsonProperty("type")] - [JsonConverter(typeof(StringEnumConverter))] - PropertyType? Type { get; set; } - } - - public abstract class UpdatePropertySchema : IUpdatePropertySchema - { - public string Name { get; set; } - - public PropertyType? Type { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs deleted file mode 100644 index c547538a..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedByUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class LastEditedByUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("last_edited_by")] - public Dictionary LastEditedBy { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs deleted file mode 100644 index 28c9e55b..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/LastEditedTimeUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class LastEditedTimeUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("last_edited_time")] - public Dictionary LastEditedTime { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs deleted file mode 100644 index 0b7b1c0c..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/MultiSelectUpdatePropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class MultiSelectUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("multi_select")] - public OptionWrapper MultiSelect { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs deleted file mode 100644 index 23f3ea3a..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/NumberUpdatePropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class NumberUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("number")] - public Number Number { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs deleted file mode 100644 index 41a8892d..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PeopleUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class PeopleUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("people")] - public Dictionary People { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs deleted file mode 100644 index 7d01f506..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/PhoneNumberUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class PhoneNumberUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("phone_number")] - public Dictionary PhoneNumber { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs deleted file mode 100644 index 25f65cd4..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RelationUpdatePropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RelationUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("relation")] - public RelationData Relation { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs deleted file mode 100644 index a20ca0ea..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RichTextUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RichTextUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("rich_text")] - public Dictionary RichText { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs deleted file mode 100644 index 8ee2d908..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/RollupConfigUpdatePropertySchema.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class RollupConfigUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("relation_property_name")] - public string RelationPropertyName { get; set; } - - [JsonProperty("relation_property_id")] - public string RelationPropertyId { get; set; } - - [JsonProperty("rollup_property_name")] - public string RollupPropertyName { get; set; } - - [JsonProperty("rollup_property_id")] - public string RollupPropertyId { get; set; } - - [JsonProperty("function")] - public string Function { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs deleted file mode 100644 index 678e452d..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/SelectUpdatePropertySchema.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class SelectUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("select")] - public OptionWrapper Select { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs deleted file mode 100644 index 54052dfc..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/TitleUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class TitleUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("title")] - public Dictionary Title { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs b/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs deleted file mode 100644 index f56d6507..00000000 --- a/Src/Notion.Client/Api/Databases/RequestParams/DatabasesUpdateParameters/PropertySchema/URLUpdatePropertySchema.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class UrlUpdatePropertySchema : UpdatePropertySchema - { - [JsonProperty("url")] - public Dictionary Url { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/Update/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/Update/DatabasesClient.cs new file mode 100644 index 00000000..7f3d17e3 --- /dev/null +++ b/Src/Notion.Client/Api/Databases/Update/DatabasesClient.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using static Notion.Client.ApiEndpoints; + +namespace Notion.Client +{ + public sealed partial class DatabasesClient + { + public async Task UpdateAsync(DatabasesUpdateRequest databasesUpdateRequest, CancellationToken cancellationToken = default) + { + IDatabasesUpdateBodyParameters body = databasesUpdateRequest; + + if (body == null) + { + throw new ArgumentNullException(nameof(databasesUpdateRequest)); + } + + if (string.IsNullOrEmpty(databasesUpdateRequest.DatabaseId)) + { + throw new ArgumentNullException(nameof(databasesUpdateRequest.DatabaseId)); + } + + var path = DatabasesApiUrls.Update(databasesUpdateRequest.DatabaseId); + + return await _client.PatchAsync( + path, + body, + cancellationToken: cancellationToken + ); + } + } +} \ No newline at end of file diff --git a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs index e748cd43..2fa49bbd 100644 --- a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs +++ b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs @@ -1,13 +1,30 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using FluentAssertions; using Notion.Client; using Xunit; namespace Notion.IntegrationTests { - public class DataSourcesClientTests : IntegrationTestBase + public class DataSourcesClientTests : IntegrationTestBase, IAsyncLifetime { + private Page _page = null!; + + public async Task InitializeAsync() + { + _page = await Client.Pages.CreateAsync( + PagesCreateParametersBuilder.Create( + new PageParentRequest { PageId = ParentPageId } + ).Build() + ); + } + + public async Task DisposeAsync() + { + await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); + } + [Fact] public async Task CreateDataSource_ShouldReturnSuccess() { @@ -177,5 +194,119 @@ private async Task CreateAndGetDatasourceIdAsync(string databaseId) var response = await Client.DataSources.CreateAsync(request); return response.Id; } + + [Fact] + public async Task UpdateDatabaseRelationProperties() + { + // Arrange + var createdSourceDatabase = await CreateDatabaseWithAPageAsync("Test Relation Source"); + var createdDestinationDatabase = await CreateDatabaseWithAPageAsync("Test Relation Destination"); + + // Act + var response = await Client.DataSources.UpdateAsync( + new UpdateDataSourceRequest + { + DataSourceId = createdDestinationDatabase.DataSources.First().DataSourceId, + Properties = new Dictionary + { + { + "Single Relation", + new UpdatePropertyConfigurationRequest + { + Name = "Single Relation", + PropertyRequest = new RelationPropertyConfigurationRequest + { + Relation = new SinglePropertyRelationDataRequest + { + DataSourceId = createdSourceDatabase.DataSources.First().DataSourceId, + SingleProperty = new Dictionary() + } + } + } + }, + { + "Dual Relation", + new UpdatePropertyConfigurationRequest + { + Name = "Dual Relation", + PropertyRequest = new RelationPropertyConfigurationRequest + { + Relation = new DualPropertyRelationDataRequest + { + DataSourceId = createdSourceDatabase.DataSources.First().DataSourceId, + DualProperty = new DualPropertyRelationDataRequest.Data() + } + } + } + } + } + }); + + // Assert + await ValidateDatasourceProperties(createdDestinationDatabase.DataSources.First().DataSourceId, createdSourceDatabase.DataSources.First().DataSourceId); + } + + private async Task ValidateDatasourceProperties(string dataSourceId, string sourceDataSourceId) + { + var response = await Client.DataSources.RetrieveAsync(new RetrieveDataSourceRequest { DataSourceId = dataSourceId }); + + response.Properties.Should().NotBeNull(); + + response.Properties.Should().ContainKey("Single Relation"); + var singleRelation = response.Properties["Single Relation"].As().Relation; + singleRelation.Type.Should().Be("single_property"); + var singleRelationData = singleRelation.Should().BeOfType().Subject; + singleRelationData.DataSourceId.Should().Be(sourceDataSourceId); + + response.Properties.Should().ContainKey("Dual Relation"); + var dualRelation = response.Properties["Dual Relation"].As().Relation; + dualRelation.DataSourceId.Should().Be(sourceDataSourceId); + dualRelation.Type.Should().Be("dual_property"); + dualRelation.Should().BeOfType(); + } + + private async Task CreateDatabaseWithAPageAsync(string databaseName) + { + var createDbRequest = new DatabasesCreateRequest + { + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = databaseName, + Link = null + } + } + }, + InitialDataSource = new InitialDataSourceRequest + { + Properties = new Dictionary + { + { "Name", new TitlePropertyConfigurationRequest { Title = new Dictionary() } }, + } + }, + Parent = new PageParentOfDatabaseRequest { PageId = _page.Id } + }; + + var createdDatabase = await Client.Databases.CreateAsync(createDbRequest); + + var pagesCreateParameters = PagesCreateParametersBuilder + .Create(new DatabaseParentRequest { DatabaseId = createdDatabase.Id }) + .AddProperty("Name", + new TitlePropertyValue + { + Title = new List + { + new RichTextText { Text = new Text { Content = "Test Title" } } + } + }) + .Build(); + + await Client.Pages.CreateAsync(pagesCreateParameters); + + return createdDatabase; + } } } \ No newline at end of file diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index ce8b11e2..da322983 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -44,71 +44,6 @@ public async Task QueryDatabase() .Text.Content.Should().Be("Test Title"); } - [Fact] - public async Task UpdateDatabaseRelationProperties() - { - // Arrange - var createdSourceDatabase = await CreateDatabaseWithAPageAsync("Test Relation Source"); - var createdDestinationDatabase = await CreateDatabaseWithAPageAsync("Test Relation Destination"); - - // Act - var response = await Client.Databases.UpdateAsync(createdDestinationDatabase.Id, - new DatabasesUpdateParameters - { - Properties = new Dictionary - { - { - "Single Relation", - new RelationUpdatePropertySchema - { - Relation = new SinglePropertyRelation - { - DatabaseId = createdSourceDatabase.Id, - SingleProperty = new Dictionary() - } - } - }, - { - "Dual Relation", - new RelationUpdatePropertySchema - { - Relation = new DualPropertyRelation - { - DatabaseId = createdSourceDatabase.Id, - DualProperty = new DualPropertyRelation.Data() - } - } - } - } - }); - - // Assert - response.DataSources.Should().ContainSingle(); - await ValidateDatasourceProperties(response.DataSources.Single().DataSourceId, createdSourceDatabase.Id); - } - - private async Task ValidateDatasourceProperties(string dataSourceId, string sourceDatabaseId) - { - var response = await Client.DataSources.RetrieveAsync(new RetrieveDataSourceRequest { DataSourceId = dataSourceId }); - - response.Properties.Should().NotBeNull(); - - response.Properties.Should().ContainKey("Single Relation"); - var singleRelation = response.Properties["Single Relation"].As().Relation; - singleRelation.Should().BeEquivalentTo( - new SinglePropertyRelation - { - DatabaseId = sourceDatabaseId, - SingleProperty = new Dictionary() - }); - - response.Properties.Should().ContainKey("Dual Relation"); - var dualRelation = response.Properties["Dual Relation"].As().Relation; - dualRelation.DatabaseId.Should().Be(sourceDatabaseId); - dualRelation.Type.Should().Be(RelationType.Dual); - dualRelation.Should().BeOfType(); - } - private async Task CreateDatabaseWithAPageAsync(string databaseName) { var createDbRequest = new DatabasesCreateRequest @@ -199,4 +134,33 @@ public async Task Verify_mention_date_property_parsed_properly() mention.Date.Start.Should().NotBeNull(); mention.Date.End.Should().NotBeNull(); } + + // add test for UpdateAsync method + [Fact] + public async Task UpdateDatabase() + { + // Arrange + var createdDatabase = await CreateDatabaseWithAPageAsync("Initial DB Name"); + var updateRequest = new DatabasesUpdateRequest + { + DatabaseId = createdDatabase.Id, + Title = new List + { + new RichTextTextInput + { + Text = new Text + { + Content = "Updated DB Name", + Link = null + } + } + } + }; + + // Act + var updatedDatabase = await Client.Databases.UpdateAsync(updateRequest); + + // Assert + updatedDatabase.Title.OfType().First().Text.Content.Should().Be("Updated DB Name"); + } } From c95db961c6282a5e998d6cb48181579a81de93bd Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 6 Dec 2025 19:03:39 +0530 Subject: [PATCH 22/27] Update DataSource tests to use dynamically created database IDs --- Test/Notion.IntegrationTests/DataSourcesClientTests.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs index 2fa49bbd..b1696bcf 100644 --- a/Test/Notion.IntegrationTests/DataSourcesClientTests.cs +++ b/Test/Notion.IntegrationTests/DataSourcesClientTests.cs @@ -29,11 +29,12 @@ public async Task DisposeAsync() public async Task CreateDataSource_ShouldReturnSuccess() { // Arrange + var database = await CreateDatabaseWithAPageAsync("Test Data Source DB"); var request = new CreateDataSourceRequest { Parent = new DatabaseParentRequest { - DatabaseId = "" // TODO: Create a test database and set its ID here + DatabaseId = database.Id }, Properties = new Dictionary { @@ -67,11 +68,12 @@ public async Task CreateDataSource_ShouldReturnSuccess() public async Task UpdateDataSource_ShouldReturnSuccess() { // Arrange + var database = await CreateDatabaseWithAPageAsync("Test Data Source DB"); var createRequest = new CreateDataSourceRequest { Parent = new DatabaseParentRequest { - DatabaseId = "29ee2842ccb5802397b8fdf6fed5ac93" // TODO: Create a test database and set its ID here + DatabaseId = database.Id }, Properties = new Dictionary { From f023c26c6f3dd9163b568d54ca8841f85aeb9af5 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:44:03 +0530 Subject: [PATCH 23/27] Add test for retrieving a database in DatabasesClientTests --- .../DatabasesClientTests.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index da322983..539757c8 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -135,7 +135,6 @@ public async Task Verify_mention_date_property_parsed_properly() mention.Date.End.Should().NotBeNull(); } - // add test for UpdateAsync method [Fact] public async Task UpdateDatabase() { @@ -163,4 +162,19 @@ public async Task UpdateDatabase() // Assert updatedDatabase.Title.OfType().First().Text.Content.Should().Be("Updated DB Name"); } -} + + [Fact] + public async Task RetrieveDatabase() + { + // Arrange + var createdDatabase = await CreateDatabaseWithAPageAsync("Retrieve Test DB"); + + // Act + var retrievedDatabase = await Client.Databases.RetrieveAsync(createdDatabase.Id); + + // Assert + retrievedDatabase.Id.Should().Be(createdDatabase.Id); + retrievedDatabase.Title.OfType().First().Text.Content.Should().Be("Retrieve Test DB"); + retrievedDatabase.DataSources.Should().ContainSingle(); + } +} \ No newline at end of file From 0a5d6c68d12c2f7a099b970687be30cabef0934b Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sat, 6 Dec 2025 20:46:21 +0530 Subject: [PATCH 24/27] Remove QueryAsync method and related classes from DatabasesClient --- .../Api/Databases/IDatabasesClient.cs | 12 -------- .../Api/Databases/Query/DatabasesClient.cs | 28 ------------------- .../Query/Request/DatabasesQueryParameters.cs | 17 ----------- .../Request/IDatabaseQueryBodyParameters.cs | 14 ---------- .../Request/IDatabaseQueryQueryParameters.cs | 11 -------- .../Query/Response/DatabaseQueryResponse.cs | 12 -------- .../DatabasesClientTests.cs | 18 ------------ 7 files changed, 112 deletions(-) delete mode 100644 Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs delete mode 100644 Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs delete mode 100644 Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs diff --git a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs index 9fb1c233..34f7113d 100644 --- a/Src/Notion.Client/Api/Databases/IDatabasesClient.cs +++ b/Src/Notion.Client/Api/Databases/IDatabasesClient.cs @@ -14,18 +14,6 @@ public interface IDatabasesClient /// Task RetrieveAsync(string databaseId, CancellationToken cancellationToken = default); - /// - /// Gets a list of Pages contained in the database, filtered and ordered according to the - /// filter conditions and sort criteria provided in the request. The response may contain - /// fewer than page_size of results. - /// - /// - /// - /// - /// - /// - Task QueryAsync(string databaseId, DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default); - /// /// Creates a database as a subpage in the specified parent page, with the specified properties schema. /// diff --git a/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs b/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs deleted file mode 100644 index 2d0c62be..00000000 --- a/Src/Notion.Client/Api/Databases/Query/DatabasesClient.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace Notion.Client -{ - public sealed partial class DatabasesClient - { - public async Task QueryAsync( - string databaseId, - DatabasesQueryParameters databasesQueryParameters, CancellationToken cancellationToken = default) - { - var body = (IDatabaseQueryBodyParameters)databasesQueryParameters; - var queryParameters = (IDatabaseQueryQueryParameters)databasesQueryParameters; - - var queryParams = queryParameters.FilterProperties? - .Select(x => new KeyValuePair("filter_properties", x)); - - return await _client.PostAsync( - ApiEndpoints.DatabasesApiUrls.Query(databaseId), - body, - queryParams, - cancellationToken: cancellationToken - ); - } - } -} diff --git a/Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs deleted file mode 100644 index 2c2bb030..00000000 --- a/Src/Notion.Client/Api/Databases/Query/Request/DatabasesQueryParameters.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace Notion.Client -{ - public class DatabasesQueryParameters : IDatabaseQueryBodyParameters, IDatabaseQueryQueryParameters - { - public Filter Filter { get; set; } - - public List Sorts { get; set; } - - public string StartCursor { get; set; } - - public int? PageSize { get; set; } - - public List FilterProperties { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs deleted file mode 100644 index 4ac46860..00000000 --- a/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryBodyParameters.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public interface IDatabaseQueryBodyParameters : IPaginationParameters - { - [JsonProperty("filter")] - Filter Filter { get; set; } - - [JsonProperty("sorts")] - List Sorts { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs b/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs deleted file mode 100644 index f8ba1f41..00000000 --- a/Src/Notion.Client/Api/Databases/Query/Request/IDatabaseQueryQueryParameters.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - public interface IDatabaseQueryQueryParameters - { - [JsonProperty("filter_properties")] - List FilterProperties { get; set; } - } -} diff --git a/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs b/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs deleted file mode 100644 index 5b7c9ec6..00000000 --- a/Src/Notion.Client/Api/Databases/Query/Response/DatabaseQueryResponse.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace Notion.Client -{ - // ReSharper disable once ClassNeverInstantiated.Global - public class DatabaseQueryResponse : PaginatedList - { - [JsonProperty("database")] - public Dictionary Database { get; set; } - } -} diff --git a/Test/Notion.IntegrationTests/DatabasesClientTests.cs b/Test/Notion.IntegrationTests/DatabasesClientTests.cs index 539757c8..aeebee7f 100644 --- a/Test/Notion.IntegrationTests/DatabasesClientTests.cs +++ b/Test/Notion.IntegrationTests/DatabasesClientTests.cs @@ -26,24 +26,6 @@ public async Task DisposeAsync() await Client.Pages.UpdateAsync(_page.Id, new PagesUpdateParameters { InTrash = true }); } - [Fact] - public async Task QueryDatabase() - { - // Arrange - var createdDatabase = await CreateDatabaseWithAPageAsync("Test List"); - - // Act - var response = await Client.Databases.QueryAsync(createdDatabase.Id, new DatabasesQueryParameters()); - - // Assert - response.Results.Should().NotBeNull(); - var page = response.Results.Should().ContainSingle().Subject.As(); - - page.Properties["Name"].As() - .Title.Cast().First() - .Text.Content.Should().Be("Test Title"); - } - private async Task CreateDatabaseWithAPageAsync(string databaseName) { var createDbRequest = new DatabasesCreateRequest From 97b997266016ac10d47a7f35ec5cfc68e07feacb Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 7 Dec 2025 00:58:43 +0530 Subject: [PATCH 25/27] Remove unused IWikiDatabase interface and update Database and Page classes accordingly --- Src/Notion.Client/Models/Database/Database.cs | 2 +- Src/Notion.Client/Models/Database/IWikiDatabase.cs | 12 ------------ Src/Notion.Client/Models/Page/Page.cs | 2 +- 3 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 Src/Notion.Client/Models/Database/IWikiDatabase.cs diff --git a/Src/Notion.Client/Models/Database/Database.cs b/Src/Notion.Client/Models/Database/Database.cs index 9abf7e19..b30d308e 100644 --- a/Src/Notion.Client/Models/Database/Database.cs +++ b/Src/Notion.Client/Models/Database/Database.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Database : IObject, IObjectModificationData, IWikiDatabase + public class Database : IObject, IObjectModificationData { public ObjectType Object => ObjectType.Database; diff --git a/Src/Notion.Client/Models/Database/IWikiDatabase.cs b/Src/Notion.Client/Models/Database/IWikiDatabase.cs deleted file mode 100644 index 59969175..00000000 --- a/Src/Notion.Client/Models/Database/IWikiDatabase.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JsonSubTypes; -using Newtonsoft.Json; - -namespace Notion.Client -{ - [JsonConverter(typeof(JsonSubtypes), "object")] - [JsonSubtypes.KnownSubTypeAttribute(typeof(Page), ObjectType.Page)] - [JsonSubtypes.KnownSubTypeAttribute(typeof(Database), ObjectType.Database)] - public interface IWikiDatabase : IObject - { - } -} diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index 554d2a7e..c6f7c786 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Page : IObject, IObjectModificationData, IWikiDatabase, IQueryDataSourceResponseObject + public class Page : IObject, IObjectModificationData, IQueryDataSourceResponseObject { /// /// The parent of this page. Can be a database, page, or workspace. From bf4e5185eafdb2e14f3f1a787bfc744b905cb2e3 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 7 Dec 2025 01:04:58 +0530 Subject: [PATCH 26/27] Remove PagePropertyOnId class as it is no longer needed --- Src/Notion.Client/Models/Page/PagePropertyOnId.cs | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 Src/Notion.Client/Models/Page/PagePropertyOnId.cs diff --git a/Src/Notion.Client/Models/Page/PagePropertyOnId.cs b/Src/Notion.Client/Models/Page/PagePropertyOnId.cs deleted file mode 100644 index 00005986..00000000 --- a/Src/Notion.Client/Models/Page/PagePropertyOnId.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Newtonsoft.Json; - -namespace Notion.Client -{ - public class PagePropertyOnId - { - [JsonProperty("id")] - public string Id { get; set; } - } -} From 9e7121c378999b4a83ced59158185c087939e530 Mon Sep 17 00:00:00 2001 From: Vedant Koditkar <18693839+KoditkarVedant@users.noreply.github.com> Date: Sun, 7 Dec 2025 01:57:05 +0530 Subject: [PATCH 27/27] Enhance search functionality by adding support for data sources and updating related models and interfaces --- .../Api/DataSources/Models/DataSourceResponse.cs | 2 +- Src/Notion.Client/Api/Search/ISearchClient.cs | 13 +++++++------ .../Api/Search/Request/ISearchBodyParameters.cs | 12 ++++++++++++ .../Api/Search/Request/SearchFilter.cs | 5 +---- .../Api/Search/Request/SearchObjectType.cs | 8 +++----- Src/Notion.Client/Api/Search/Request/SearchSort.cs | 6 ++++++ .../Api/Search/Response/ISearchResponseObject.cs | 12 ++++++++++++ .../Api/Search/Response/SearchResponse.cs | 5 ++++- Src/Notion.Client/Models/Page/Page.cs | 2 +- Src/Notion.Client/Models/PaginatedList.cs | 7 +++++++ Test/Notion.UnitTests/SearchClientTest.cs | 2 +- .../data/search/SearchResponse.json | 2 +- 12 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 Src/Notion.Client/Api/Search/Response/ISearchResponseObject.cs diff --git a/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs index e88bf5ac..14332f86 100644 --- a/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs +++ b/Src/Notion.Client/Api/DataSources/Models/DataSourceResponse.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class DataSourceResponse : IObject, IObjectModificationData, IQueryDataSourceResponseObject + public class DataSourceResponse : IObject, IObjectModificationData, IQueryDataSourceResponseObject, ISearchResponseObject { public string Id { get; set; } diff --git a/Src/Notion.Client/Api/Search/ISearchClient.cs b/Src/Notion.Client/Api/Search/ISearchClient.cs index accee1e1..552d61a3 100644 --- a/Src/Notion.Client/Api/Search/ISearchClient.cs +++ b/Src/Notion.Client/Api/Search/ISearchClient.cs @@ -1,20 +1,21 @@ -using System.Diagnostics.CodeAnalysis; -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Notion.Client { - [SuppressMessage("ReSharper", "UnusedMemberInSuper.Global")] public interface ISearchClient { /// - /// Searches all original pages, databases, and child pages/databases that are shared with the integration. - /// It will not return linked databases, since these duplicate their source databases. + /// Searches all parent or child pages and data_sources that have been shared with an integration. + /// + /// Returns all pages or data_sources , excluding duplicated linked databases, that have titles that include the query param. + /// If no query param is provided, then the response contains all pages or data_sources that have been shared with the integration. + /// The results adhere to any limitations related to an integration’s capabilities. /// /// Search filters and body parameters /// /// - /// + /// /// Task SearchAsync( SearchRequest request, diff --git a/Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs b/Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs index 18965000..bedc813b 100644 --- a/Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs +++ b/Src/Notion.Client/Api/Search/Request/ISearchBodyParameters.cs @@ -4,12 +4,24 @@ namespace Notion.Client { public interface ISearchBodyParameters : IPaginationParameters { + /// + /// The text that the API compares page and data_source titles against. + /// [JsonProperty("query")] string Query { get; set; } + /// + /// A set of criteria, direction and timestamp keys, that orders the results. + /// The only supported timestamp value is "last_edited_time". Supported direction values are "ascending" and "descending". + /// If sort is not provided, then the most recently edited results are returned first. + /// [JsonProperty("sort")] SearchSort Sort { get; set; } + /// + /// A set of criteria, value and property keys, that limits the results to either only pages or only data_sources. + /// Possible value values are "page" or "data_source". The only supported property value is "object". + /// [JsonProperty("filter")] SearchFilter Filter { get; set; } } diff --git a/Src/Notion.Client/Api/Search/Request/SearchFilter.cs b/Src/Notion.Client/Api/Search/Request/SearchFilter.cs index b36ca873..dbd5cf5f 100644 --- a/Src/Notion.Client/Api/Search/Request/SearchFilter.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchFilter.cs @@ -1,11 +1,8 @@ -using System.Diagnostics.CodeAnalysis; -using Newtonsoft.Json; +using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace Notion.Client { - [SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")] - [SuppressMessage("ReSharper", "UnusedMember.Global")] public class SearchFilter { [JsonConverter(typeof(StringEnumConverter))] diff --git a/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs b/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs index e3e6181b..ee6e053c 100644 --- a/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchObjectType.cs @@ -1,15 +1,13 @@ -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization; +using System.Runtime.Serialization; namespace Notion.Client { - [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum SearchObjectType { [EnumMember(Value = "page")] Page, - [EnumMember(Value = "database")] - Database + [EnumMember(Value = "data_source")] + DataSource } } diff --git a/Src/Notion.Client/Api/Search/Request/SearchSort.cs b/Src/Notion.Client/Api/Search/Request/SearchSort.cs index fed3f205..fa0cbd63 100644 --- a/Src/Notion.Client/Api/Search/Request/SearchSort.cs +++ b/Src/Notion.Client/Api/Search/Request/SearchSort.cs @@ -5,10 +5,16 @@ namespace Notion.Client { public class SearchSort { + /// + /// Supported direction values are "ascending" and "descending". + /// [JsonProperty("direction")] [JsonConverter(typeof(StringEnumConverter))] public SearchDirection Direction { get; set; } + /// + /// The only supported timestamp value is "last_edited_time". + /// [JsonProperty("timestamp")] public string Timestamp { get; set; } } diff --git a/Src/Notion.Client/Api/Search/Response/ISearchResponseObject.cs b/Src/Notion.Client/Api/Search/Response/ISearchResponseObject.cs new file mode 100644 index 00000000..8907e5a3 --- /dev/null +++ b/Src/Notion.Client/Api/Search/Response/ISearchResponseObject.cs @@ -0,0 +1,12 @@ +using JsonSubTypes; +using Newtonsoft.Json; + +namespace Notion.Client +{ + [JsonConverter(typeof(JsonSubtypes), "object")] + [JsonSubtypes.KnownSubType(typeof(Page), ObjectType.Page)] + [JsonSubtypes.KnownSubType(typeof(DataSourceResponse), ObjectType.DataSource)] + public interface ISearchResponseObject : IObject + { + } +} diff --git a/Src/Notion.Client/Api/Search/Response/SearchResponse.cs b/Src/Notion.Client/Api/Search/Response/SearchResponse.cs index 2be0e2f1..603c5d21 100644 --- a/Src/Notion.Client/Api/Search/Response/SearchResponse.cs +++ b/Src/Notion.Client/Api/Search/Response/SearchResponse.cs @@ -3,9 +3,12 @@ namespace Notion.Client { - public class SearchResponse : PaginatedList + public class SearchResponse : PaginatedList { [JsonProperty("page_or_database")] public Dictionary PageOrDatabase { get; set; } + + [JsonExtensionData] + public IDictionary AdditionalData { get; set; } } } diff --git a/Src/Notion.Client/Models/Page/Page.cs b/Src/Notion.Client/Models/Page/Page.cs index c6f7c786..53e532f9 100644 --- a/Src/Notion.Client/Models/Page/Page.cs +++ b/Src/Notion.Client/Models/Page/Page.cs @@ -4,7 +4,7 @@ namespace Notion.Client { - public class Page : IObject, IObjectModificationData, IQueryDataSourceResponseObject + public class Page : IObject, IObjectModificationData, IQueryDataSourceResponseObject, ISearchResponseObject { /// /// The parent of this page. Can be a database, page, or workspace. diff --git a/Src/Notion.Client/Models/PaginatedList.cs b/Src/Notion.Client/Models/PaginatedList.cs index d0b1107f..f658b541 100644 --- a/Src/Notion.Client/Models/PaginatedList.cs +++ b/Src/Notion.Client/Models/PaginatedList.cs @@ -5,9 +5,16 @@ namespace Notion.Client { public interface IPaginationParameters { + /// + /// If supplied, this endpoint will return a page of results starting after the cursor provided. + /// If not supplied, this endpoint will return the first page of results. + /// [JsonProperty("start_cursor")] string StartCursor { get; set; } + /// + /// The number of items from the full list desired in the response. + /// [JsonProperty("page_size")] int? PageSize { get; set; } } diff --git a/Test/Notion.UnitTests/SearchClientTest.cs b/Test/Notion.UnitTests/SearchClientTest.cs index df547059..6df62898 100644 --- a/Test/Notion.UnitTests/SearchClientTest.cs +++ b/Test/Notion.UnitTests/SearchClientTest.cs @@ -49,7 +49,7 @@ public async Task Search() results.Should().SatisfyRespectively( obj => { - obj.Object.Should().Be(ObjectType.Database); + obj.Object.Should().Be(ObjectType.DataSource); }, obj => { diff --git a/Test/Notion.UnitTests/data/search/SearchResponse.json b/Test/Notion.UnitTests/data/search/SearchResponse.json index 53defa57..9e9a9414 100644 --- a/Test/Notion.UnitTests/data/search/SearchResponse.json +++ b/Test/Notion.UnitTests/data/search/SearchResponse.json @@ -8,7 +8,7 @@ "created_time": "2021-04-22T22:23:26.080Z", "id": "e6c6f8ff-c70e-4970-91ba-98f03e0d7fc6", "last_edited_time": "2021-04-23T04:21:00.000Z", - "object": "database", + "object": "data_source", "properties": { "Name": { "id": "title",