Skip to content

Commit 19e98c2

Browse files
feat(api): Add bulk delete subscriptions
1 parent fd69af2 commit 19e98c2

File tree

6 files changed

+309
-3
lines changed

6 files changed

+309
-3
lines changed

.stats.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
configured_endpoints: 89
1+
configured_endpoints: 90
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/knock%2Fknock-ce72fff9b44a47ab7e0425e496f09c61cde5b4258feb20cb5dbef6fa615a57e4.yml
33
openapi_spec_hash: 3054ea299cf43dc89b68266818fecfe4
4-
config_hash: 1470ae08f436e4d00dd096cb585b41fd
4+
config_hash: 2b42d138d85c524e65fa7e205d36cc4a

api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ Methods:
164164

165165
- <code title="post /v1/objects/{collection}/bulk/delete">client.objects.bulk.<a href="./src/knockapi/resources/objects/bulk.py">delete</a>(collection, \*\*<a href="src/knockapi/types/objects/bulk_delete_params.py">params</a>) -> <a href="./src/knockapi/types/bulk_operation.py">BulkOperation</a></code>
166166
- <code title="post /v1/objects/{collection}/bulk/subscriptions/add">client.objects.bulk.<a href="./src/knockapi/resources/objects/bulk.py">add_subscriptions</a>(collection, \*\*<a href="src/knockapi/types/objects/bulk_add_subscriptions_params.py">params</a>) -> <a href="./src/knockapi/types/bulk_operation.py">BulkOperation</a></code>
167+
- <code title="post /v1/objects/{collection}/bulk/subscriptions/delete">client.objects.bulk.<a href="./src/knockapi/resources/objects/bulk.py">delete_subscriptions</a>(collection, \*\*<a href="src/knockapi/types/objects/bulk_delete_subscriptions_params.py">params</a>) -> <a href="./src/knockapi/types/bulk_operation.py">BulkOperation</a></code>
167168
- <code title="post /v1/objects/{collection}/bulk/set">client.objects.bulk.<a href="./src/knockapi/resources/objects/bulk.py">set</a>(collection, \*\*<a href="src/knockapi/types/objects/bulk_set_params.py">params</a>) -> <a href="./src/knockapi/types/bulk_operation.py">BulkOperation</a></code>
168169

169170
# Tenants

src/knockapi/resources/objects/bulk.py

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
async_to_streamed_response_wrapper,
1818
)
1919
from ..._base_client import make_request_options
20-
from ...types.objects import bulk_set_params, bulk_delete_params, bulk_add_subscriptions_params
20+
from ...types.objects import (
21+
bulk_set_params,
22+
bulk_delete_params,
23+
bulk_add_subscriptions_params,
24+
bulk_delete_subscriptions_params,
25+
)
2126
from ...types.bulk_operation import BulkOperation
2227

2328
__all__ = ["BulkResource", "AsyncBulkResource"]
@@ -138,6 +143,54 @@ def add_subscriptions(
138143
cast_to=BulkOperation,
139144
)
140145

146+
def delete_subscriptions(
147+
self,
148+
collection: str,
149+
*,
150+
subscriptions: Iterable[bulk_delete_subscriptions_params.Subscription],
151+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
152+
# The extra values given here take precedence over values defined on the client or passed to this method.
153+
extra_headers: Headers | None = None,
154+
extra_query: Query | None = None,
155+
extra_body: Body | None = None,
156+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
157+
idempotency_key: str | None = None,
158+
) -> BulkOperation:
159+
"""Delete subscriptions for many objects in a single collection type.
160+
161+
If a
162+
subscription for an object in the collection doesn't exist, it will be skipped.
163+
164+
Args:
165+
subscriptions: A nested list of subscriptions.
166+
167+
extra_headers: Send extra headers
168+
169+
extra_query: Add additional query parameters to the request
170+
171+
extra_body: Add additional JSON properties to the request
172+
173+
timeout: Override the client-level default timeout for this request, in seconds
174+
175+
idempotency_key: Specify a custom idempotency key for this request
176+
"""
177+
if not collection:
178+
raise ValueError(f"Expected a non-empty value for `collection` but received {collection!r}")
179+
return self._post(
180+
f"/v1/objects/{collection}/bulk/subscriptions/delete",
181+
body=maybe_transform(
182+
{"subscriptions": subscriptions}, bulk_delete_subscriptions_params.BulkDeleteSubscriptionsParams
183+
),
184+
options=make_request_options(
185+
extra_headers=extra_headers,
186+
extra_query=extra_query,
187+
extra_body=extra_body,
188+
timeout=timeout,
189+
idempotency_key=idempotency_key,
190+
),
191+
cast_to=BulkOperation,
192+
)
193+
141194
def set(
142195
self,
143196
collection: str,
@@ -298,6 +351,54 @@ async def add_subscriptions(
298351
cast_to=BulkOperation,
299352
)
300353

354+
async def delete_subscriptions(
355+
self,
356+
collection: str,
357+
*,
358+
subscriptions: Iterable[bulk_delete_subscriptions_params.Subscription],
359+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
360+
# The extra values given here take precedence over values defined on the client or passed to this method.
361+
extra_headers: Headers | None = None,
362+
extra_query: Query | None = None,
363+
extra_body: Body | None = None,
364+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
365+
idempotency_key: str | None = None,
366+
) -> BulkOperation:
367+
"""Delete subscriptions for many objects in a single collection type.
368+
369+
If a
370+
subscription for an object in the collection doesn't exist, it will be skipped.
371+
372+
Args:
373+
subscriptions: A nested list of subscriptions.
374+
375+
extra_headers: Send extra headers
376+
377+
extra_query: Add additional query parameters to the request
378+
379+
extra_body: Add additional JSON properties to the request
380+
381+
timeout: Override the client-level default timeout for this request, in seconds
382+
383+
idempotency_key: Specify a custom idempotency key for this request
384+
"""
385+
if not collection:
386+
raise ValueError(f"Expected a non-empty value for `collection` but received {collection!r}")
387+
return await self._post(
388+
f"/v1/objects/{collection}/bulk/subscriptions/delete",
389+
body=await async_maybe_transform(
390+
{"subscriptions": subscriptions}, bulk_delete_subscriptions_params.BulkDeleteSubscriptionsParams
391+
),
392+
options=make_request_options(
393+
extra_headers=extra_headers,
394+
extra_query=extra_query,
395+
extra_body=extra_body,
396+
timeout=timeout,
397+
idempotency_key=idempotency_key,
398+
),
399+
cast_to=BulkOperation,
400+
)
401+
301402
async def set(
302403
self,
303404
collection: str,
@@ -353,6 +454,9 @@ def __init__(self, bulk: BulkResource) -> None:
353454
self.add_subscriptions = to_raw_response_wrapper(
354455
bulk.add_subscriptions,
355456
)
457+
self.delete_subscriptions = to_raw_response_wrapper(
458+
bulk.delete_subscriptions,
459+
)
356460
self.set = to_raw_response_wrapper(
357461
bulk.set,
358462
)
@@ -368,6 +472,9 @@ def __init__(self, bulk: AsyncBulkResource) -> None:
368472
self.add_subscriptions = async_to_raw_response_wrapper(
369473
bulk.add_subscriptions,
370474
)
475+
self.delete_subscriptions = async_to_raw_response_wrapper(
476+
bulk.delete_subscriptions,
477+
)
371478
self.set = async_to_raw_response_wrapper(
372479
bulk.set,
373480
)
@@ -383,6 +490,9 @@ def __init__(self, bulk: BulkResource) -> None:
383490
self.add_subscriptions = to_streamed_response_wrapper(
384491
bulk.add_subscriptions,
385492
)
493+
self.delete_subscriptions = to_streamed_response_wrapper(
494+
bulk.delete_subscriptions,
495+
)
386496
self.set = to_streamed_response_wrapper(
387497
bulk.set,
388498
)
@@ -398,6 +508,9 @@ def __init__(self, bulk: AsyncBulkResource) -> None:
398508
self.add_subscriptions = async_to_streamed_response_wrapper(
399509
bulk.add_subscriptions,
400510
)
511+
self.delete_subscriptions = async_to_streamed_response_wrapper(
512+
bulk.delete_subscriptions,
513+
)
401514
self.set = async_to_streamed_response_wrapper(
402515
bulk.set,
403516
)

src/knockapi/types/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
from .bulk_set_params import BulkSetParams as BulkSetParams
66
from .bulk_delete_params import BulkDeleteParams as BulkDeleteParams
77
from .bulk_add_subscriptions_params import BulkAddSubscriptionsParams as BulkAddSubscriptionsParams
8+
from .bulk_delete_subscriptions_params import BulkDeleteSubscriptionsParams as BulkDeleteSubscriptionsParams
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from __future__ import annotations
4+
5+
from typing import Iterable
6+
from typing_extensions import Required, TypedDict
7+
8+
from ..._types import SequenceNotStr
9+
from ..recipient_reference_param import RecipientReferenceParam
10+
11+
__all__ = ["BulkDeleteSubscriptionsParams", "Subscription"]
12+
13+
14+
class BulkDeleteSubscriptionsParams(TypedDict, total=False):
15+
subscriptions: Required[Iterable[Subscription]]
16+
"""A nested list of subscriptions."""
17+
18+
19+
class Subscription(TypedDict, total=False):
20+
id: Required[str]
21+
"""Unique identifier for the object."""
22+
23+
recipients: Required[SequenceNotStr[RecipientReferenceParam]]
24+
"""The recipients of the subscription.
25+
26+
You can subscribe up to 100 recipients to an object at a time.
27+
"""

tests/api_resources/objects/test_bulk.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,88 @@ def test_path_params_add_subscriptions(self, client: Knock) -> None:
129129
],
130130
)
131131

132+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
133+
@parametrize
134+
def test_method_delete_subscriptions(self, client: Knock) -> None:
135+
bulk = client.objects.bulk.delete_subscriptions(
136+
collection="projects",
137+
subscriptions=[
138+
{
139+
"id": "subscribed-to-object-1",
140+
"recipients": [{}, "subscriber-user-1"],
141+
},
142+
{
143+
"id": "subscribed-to-object-2",
144+
"recipients": ["subscriber-user-2"],
145+
},
146+
],
147+
)
148+
assert_matches_type(BulkOperation, bulk, path=["response"])
149+
150+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
151+
@parametrize
152+
def test_raw_response_delete_subscriptions(self, client: Knock) -> None:
153+
response = client.objects.bulk.with_raw_response.delete_subscriptions(
154+
collection="projects",
155+
subscriptions=[
156+
{
157+
"id": "subscribed-to-object-1",
158+
"recipients": [{}, "subscriber-user-1"],
159+
},
160+
{
161+
"id": "subscribed-to-object-2",
162+
"recipients": ["subscriber-user-2"],
163+
},
164+
],
165+
)
166+
167+
assert response.is_closed is True
168+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
169+
bulk = response.parse()
170+
assert_matches_type(BulkOperation, bulk, path=["response"])
171+
172+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
173+
@parametrize
174+
def test_streaming_response_delete_subscriptions(self, client: Knock) -> None:
175+
with client.objects.bulk.with_streaming_response.delete_subscriptions(
176+
collection="projects",
177+
subscriptions=[
178+
{
179+
"id": "subscribed-to-object-1",
180+
"recipients": [{}, "subscriber-user-1"],
181+
},
182+
{
183+
"id": "subscribed-to-object-2",
184+
"recipients": ["subscriber-user-2"],
185+
},
186+
],
187+
) as response:
188+
assert not response.is_closed
189+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
190+
191+
bulk = response.parse()
192+
assert_matches_type(BulkOperation, bulk, path=["response"])
193+
194+
assert cast(Any, response.is_closed) is True
195+
196+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
197+
@parametrize
198+
def test_path_params_delete_subscriptions(self, client: Knock) -> None:
199+
with pytest.raises(ValueError, match=r"Expected a non-empty value for `collection` but received ''"):
200+
client.objects.bulk.with_raw_response.delete_subscriptions(
201+
collection="",
202+
subscriptions=[
203+
{
204+
"id": "subscribed-to-object-1",
205+
"recipients": [{}, "subscriber-user-1"],
206+
},
207+
{
208+
"id": "subscribed-to-object-2",
209+
"recipients": ["subscriber-user-2"],
210+
},
211+
],
212+
)
213+
132214
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
133215
@parametrize
134216
def test_method_set(self, client: Knock) -> None:
@@ -293,6 +375,88 @@ async def test_path_params_add_subscriptions(self, async_client: AsyncKnock) ->
293375
],
294376
)
295377

378+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
379+
@parametrize
380+
async def test_method_delete_subscriptions(self, async_client: AsyncKnock) -> None:
381+
bulk = await async_client.objects.bulk.delete_subscriptions(
382+
collection="projects",
383+
subscriptions=[
384+
{
385+
"id": "subscribed-to-object-1",
386+
"recipients": [{}, "subscriber-user-1"],
387+
},
388+
{
389+
"id": "subscribed-to-object-2",
390+
"recipients": ["subscriber-user-2"],
391+
},
392+
],
393+
)
394+
assert_matches_type(BulkOperation, bulk, path=["response"])
395+
396+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
397+
@parametrize
398+
async def test_raw_response_delete_subscriptions(self, async_client: AsyncKnock) -> None:
399+
response = await async_client.objects.bulk.with_raw_response.delete_subscriptions(
400+
collection="projects",
401+
subscriptions=[
402+
{
403+
"id": "subscribed-to-object-1",
404+
"recipients": [{}, "subscriber-user-1"],
405+
},
406+
{
407+
"id": "subscribed-to-object-2",
408+
"recipients": ["subscriber-user-2"],
409+
},
410+
],
411+
)
412+
413+
assert response.is_closed is True
414+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
415+
bulk = await response.parse()
416+
assert_matches_type(BulkOperation, bulk, path=["response"])
417+
418+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
419+
@parametrize
420+
async def test_streaming_response_delete_subscriptions(self, async_client: AsyncKnock) -> None:
421+
async with async_client.objects.bulk.with_streaming_response.delete_subscriptions(
422+
collection="projects",
423+
subscriptions=[
424+
{
425+
"id": "subscribed-to-object-1",
426+
"recipients": [{}, "subscriber-user-1"],
427+
},
428+
{
429+
"id": "subscribed-to-object-2",
430+
"recipients": ["subscriber-user-2"],
431+
},
432+
],
433+
) as response:
434+
assert not response.is_closed
435+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
436+
437+
bulk = await response.parse()
438+
assert_matches_type(BulkOperation, bulk, path=["response"])
439+
440+
assert cast(Any, response.is_closed) is True
441+
442+
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
443+
@parametrize
444+
async def test_path_params_delete_subscriptions(self, async_client: AsyncKnock) -> None:
445+
with pytest.raises(ValueError, match=r"Expected a non-empty value for `collection` but received ''"):
446+
await async_client.objects.bulk.with_raw_response.delete_subscriptions(
447+
collection="",
448+
subscriptions=[
449+
{
450+
"id": "subscribed-to-object-1",
451+
"recipients": [{}, "subscriber-user-1"],
452+
},
453+
{
454+
"id": "subscribed-to-object-2",
455+
"recipients": ["subscriber-user-2"],
456+
},
457+
],
458+
)
459+
296460
@pytest.mark.skip(reason="Prism doesn't support callbacks yet")
297461
@parametrize
298462
async def test_method_set(self, async_client: AsyncKnock) -> None:

0 commit comments

Comments
 (0)