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