Skip to content

Commit d096fca

Browse files
committed
feat: implementation along with tests
1 parent 6f06c2f commit d096fca

File tree

9 files changed

+453
-7
lines changed

9 files changed

+453
-7
lines changed

openfga_sdk/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
from openfga_sdk.models.not_found_error_code import NotFoundErrorCode
7272
from openfga_sdk.models.null_value import NullValue
7373
from openfga_sdk.models.object_relation import ObjectRelation
74+
from openfga_sdk.models.on_duplicate_writes import OnDuplicateWrites
75+
from openfga_sdk.models.on_missing_deletes import OnMissingDeletes
7476
from openfga_sdk.models.path_unknown_error_message_response import (
7577
PathUnknownErrorMessageResponse,
7678
)
@@ -200,6 +202,8 @@
200202
"NotFoundErrorCode",
201203
"NullValue",
202204
"ObjectRelation",
205+
"OnDuplicateWrites",
206+
"OnMissingDeletes",
203207
"PathUnknownErrorMessageResponse",
204208
"ReadAssertionsResponse",
205209
"ReadAuthorizationModelResponse",
@@ -249,4 +253,4 @@
249253
"TelemetryConfigurationType",
250254
"TelemetryMetricConfiguration",
251255
"TelemetryMetricsConfiguration",
252-
]
256+
]

openfga_sdk/client/client.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,22 @@ def options_to_kwargs(
133133
return kwargs
134134

135135

136+
def options_to_conflict(
137+
options: dict[str, int | str | dict[str, int | str]] | None = None,
138+
) -> tuple[str | None, str | None]:
139+
"""
140+
Extract conflict options from options dict
141+
"""
142+
if options is not None and options.get("conflict"):
143+
conflict = options["conflict"]
144+
if isinstance(conflict, dict):
145+
return (
146+
conflict.get("on_duplicate_writes"),
147+
conflict.get("on_missing_deletes"),
148+
)
149+
return (None, None)
150+
151+
136152
def options_to_transaction_info(
137153
options: dict[str, int | str | dict[str, int | str]] | None = None,
138154
):
@@ -537,11 +553,15 @@ async def _write_with_transaction(
537553
if body.deletes_tuple_keys:
538554
deletes_tuple_keys = body.deletes_tuple_keys
539555

556+
on_duplicate_writes, on_missing_deletes = options_to_conflict(options)
557+
540558
await self._api.write(
541559
WriteRequest(
542560
writes=writes_tuple_keys,
543561
deletes=deletes_tuple_keys,
544562
authorization_model_id=self._get_authorization_model_id(options),
563+
on_duplicate_writes=on_duplicate_writes,
564+
on_missing_deletes=on_missing_deletes,
545565
),
546566
**kwargs,
547567
)
@@ -1083,4 +1103,4 @@ def map_to_assertion(client_assertion: ClientAssertion):
10831103
api_response = await self._api.write_assertions(
10841104
authorization_model_id, api_request_body, **kwargs
10851105
)
1086-
return api_response
1106+
return api_response

openfga_sdk/models/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
from openfga_sdk.models.not_found_error_code import NotFoundErrorCode
5757
from openfga_sdk.models.null_value import NullValue
5858
from openfga_sdk.models.object_relation import ObjectRelation
59+
from openfga_sdk.models.on_duplicate_writes import OnDuplicateWrites
60+
from openfga_sdk.models.on_missing_deletes import OnMissingDeletes
5961
from openfga_sdk.models.path_unknown_error_message_response import (
6062
PathUnknownErrorMessageResponse,
6163
)
@@ -167,6 +169,8 @@
167169
"NotFoundErrorCode",
168170
"NullValue",
169171
"ObjectRelation",
172+
"OnDuplicateWrites",
173+
"OnMissingDeletes",
170174
"PathUnknownErrorMessageResponse",
171175
"ReadAssertionsResponse",
172176
"ReadAuthorizationModelResponse",
@@ -211,4 +215,4 @@
211215
"WriteRequest",
212216
"WriteRequestDeletes",
213217
"WriteRequestWrites",
214-
]
218+
]
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""
2+
Python SDK for OpenFGA
3+
4+
API version: 1.x
5+
Website: https://openfga.dev
6+
Documentation: https://openfga.dev/docs
7+
Support: https://openfga.dev/community
8+
License: [Apache-2.0](https://github.com/openfga/python-sdk/blob/main/LICENSE)
9+
10+
NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
11+
"""
12+
13+
import pprint
14+
15+
from inspect import getfullargspec
16+
17+
from openfga_sdk.configuration import Configuration
18+
19+
20+
class OnDuplicateWrites:
21+
"""NOTE: This class is auto generated by OpenAPI Generator.
22+
Ref: https://openapi-generator.tech
23+
24+
Do not edit the class manually.
25+
"""
26+
27+
"""
28+
allowed enum values
29+
"""
30+
IGNORE = "IGNORE"
31+
ERROR = "ERROR"
32+
33+
allowable_values = [IGNORE, ERROR]
34+
35+
"""
36+
Attributes:
37+
openapi_types (dict): The key is attribute name
38+
and the value is attribute type.
39+
attribute_map (dict): The key is attribute name
40+
and the value is json key in definition.
41+
"""
42+
openapi_types: dict[str, str] = {}
43+
44+
attribute_map: dict[str, str] = {}
45+
46+
def __init__(self, local_vars_configuration=None):
47+
"""OnDuplicateWrites - a model defined in OpenAPI"""
48+
if local_vars_configuration is None:
49+
local_vars_configuration = Configuration.get_default_copy()
50+
self.local_vars_configuration = local_vars_configuration
51+
self.discriminator = None
52+
53+
def to_dict(self, serialize=False):
54+
"""Returns the model properties as a dict"""
55+
result = {}
56+
57+
def convert(x):
58+
if hasattr(x, "to_dict"):
59+
args = getfullargspec(x.to_dict).args
60+
if len(args) == 1:
61+
return x.to_dict()
62+
else:
63+
return x.to_dict(serialize)
64+
else:
65+
return x
66+
67+
for attr, _ in self.openapi_types.items():
68+
value = getattr(self, attr)
69+
attr = self.attribute_map.get(attr, attr) if serialize else attr
70+
if isinstance(value, list):
71+
result[attr] = list(map(lambda x: convert(x), value))
72+
elif isinstance(value, dict):
73+
result[attr] = dict(
74+
map(lambda item: (item[0], convert(item[1])), value.items())
75+
)
76+
else:
77+
result[attr] = convert(value)
78+
79+
return result
80+
81+
def to_str(self):
82+
"""Returns the string representation of the model"""
83+
return pprint.pformat(self.to_dict())
84+
85+
def __repr__(self):
86+
"""For `print` and `pprint`"""
87+
return self.to_str()
88+
89+
def __eq__(self, other):
90+
"""Returns true if both objects are equal"""
91+
if not isinstance(other, OnDuplicateWrites):
92+
return False
93+
94+
return self.to_dict() == other.to_dict()
95+
96+
def __ne__(self, other):
97+
"""Returns true if both objects are not equal"""
98+
if not isinstance(other, OnDuplicateWrites):
99+
return True
100+
101+
return self.to_dict() != other.to_dict()
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""
2+
Python SDK for OpenFGA
3+
4+
API version: 1.x
5+
Website: https://openfga.dev
6+
Documentation: https://openfga.dev/docs
7+
Support: https://openfga.dev/community
8+
License: [Apache-2.0](https://github.com/openfga/python-sdk/blob/main/LICENSE)
9+
10+
NOTE: This file was auto generated by OpenAPI Generator (https://openapi-generator.tech). DO NOT EDIT.
11+
"""
12+
13+
import pprint
14+
15+
from inspect import getfullargspec
16+
17+
from openfga_sdk.configuration import Configuration
18+
19+
20+
class OnMissingDeletes:
21+
"""NOTE: This class is auto generated by OpenAPI Generator.
22+
Ref: https://openapi-generator.tech
23+
24+
Do not edit the class manually.
25+
"""
26+
27+
"""
28+
allowed enum values
29+
"""
30+
IGNORE = "IGNORE"
31+
ERROR = "ERROR"
32+
33+
allowable_values = [IGNORE, ERROR]
34+
35+
"""
36+
Attributes:
37+
openapi_types (dict): The key is attribute name
38+
and the value is attribute type.
39+
attribute_map (dict): The key is attribute name
40+
and the value is json key in definition.
41+
"""
42+
openapi_types: dict[str, str] = {}
43+
44+
attribute_map: dict[str, str] = {}
45+
46+
def __init__(self, local_vars_configuration=None):
47+
"""OnMissingDeletes - a model defined in OpenAPI"""
48+
if local_vars_configuration is None:
49+
local_vars_configuration = Configuration.get_default_copy()
50+
self.local_vars_configuration = local_vars_configuration
51+
self.discriminator = None
52+
53+
def to_dict(self, serialize=False):
54+
"""Returns the model properties as a dict"""
55+
result = {}
56+
57+
def convert(x):
58+
if hasattr(x, "to_dict"):
59+
args = getfullargspec(x.to_dict).args
60+
if len(args) == 1:
61+
return x.to_dict()
62+
else:
63+
return x.to_dict(serialize)
64+
else:
65+
return x
66+
67+
for attr, _ in self.openapi_types.items():
68+
value = getattr(self, attr)
69+
attr = self.attribute_map.get(attr, attr) if serialize else attr
70+
if isinstance(value, list):
71+
result[attr] = list(map(lambda x: convert(x), value))
72+
elif isinstance(value, dict):
73+
result[attr] = dict(
74+
map(lambda item: (item[0], convert(item[1])), value.items())
75+
)
76+
else:
77+
result[attr] = convert(value)
78+
79+
return result
80+
81+
def to_str(self):
82+
"""Returns the string representation of the model"""
83+
return pprint.pformat(self.to_dict())
84+
85+
def __repr__(self):
86+
"""For `print` and `pprint`"""
87+
return self.to_str()
88+
89+
def __eq__(self, other):
90+
"""Returns true if both objects are equal"""
91+
if not isinstance(other, OnMissingDeletes):
92+
return False
93+
94+
return self.to_dict() == other.to_dict()
95+
96+
def __ne__(self, other):
97+
"""Returns true if both objects are not equal"""
98+
if not isinstance(other, OnMissingDeletes):
99+
return True
100+
101+
return self.to_dict() != other.to_dict()

0 commit comments

Comments
 (0)