Skip to content

Commit

Permalink
feat(client): add support for create_many_and_return
Browse files Browse the repository at this point in the history
  • Loading branch information
RobertCraigie committed Aug 11, 2024
1 parent 78f0395 commit 0ce26e0
Show file tree
Hide file tree
Showing 9 changed files with 2,446 additions and 536 deletions.
7 changes: 7 additions & 0 deletions databases/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def _fromdir(path: str) -> list[str]:
'date',
'arrays',
'create_many_skip_duplicates',
'create_many_and_return_skip_duplicates',
'case_sensitivity',
'full_text_search',
},
Expand All @@ -68,6 +69,8 @@ def _fromdir(path: str) -> list[str]:
unsupported_features={
'arrays',
'case_sensitivity',
'create_many_and_return',
'create_many_and_return_skip_duplicates',
},
),
'mariadb': DatabaseConfig(
Expand All @@ -81,6 +84,8 @@ def _fromdir(path: str) -> list[str]:
'arrays',
'case_sensitivity',
'full_text_search',
'create_many_and_return',
'create_many_and_return_skip_duplicates',
},
),
}
Expand All @@ -107,6 +112,8 @@ def _fromdir(path: str) -> list[str]:
# not yet implemented
'date': [],
'create_many_skip_duplicates': ['test_create_many_skip_duplicates.py'],
'create_many_and_return': ['test_create_many_and_return.py'],
'create_many_and_return_skip_duplicates': ['test_create_many_and_return_skip_duplicates.py'],
'raw_queries': ['test_raw_queries.py', *_fromdir('types/raw_queries')],
'case_sensitivity': ['test_case_sensitivity.py'],
'full_text_search': ['test_full_text_search.py'],
Expand Down
70 changes: 70 additions & 0 deletions databases/tests/test_create_many_and_return.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import pytest

from prisma import Prisma


@pytest.mark.asyncio
async def test_create_many_and_return(client: Prisma) -> None:
"""Standard usage"""
records = await client.user.create_many_and_return([{'name': 'Robert'}, {'name': 'Tegan'}])
assert len(records) == 2
assert records[0].name == 'Robert'
assert records[1].name == 'Tegan'

user = await client.user.find_first(where={'name': 'Robert'})
assert user is not None
assert user.name == 'Robert'

assert await client.user.count() == 2


@pytest.mark.asyncio
async def test_required_relation_key_field(client: Prisma) -> None:
"""Explicitly passing a field used as a foreign key connects the relations"""
user = await client.user.create(
data={
'name': 'Robert',
},
)
user2 = await client.user.create(
data={
'name': 'Robert',
},
)
records = await client.profile.create_many_and_return(
data=[
{'user_id': user.id, 'description': 'Foo', 'country': 'Scotland'},
{
'user_id': user2.id,
'description': 'Foo 2',
'country': 'Scotland',
},
],
)
assert len(records) == 2
assert records[0].description == 'Foo'
assert records[1].description == 'Foo 2'

found = await client.user.find_unique(
where={
'id': user.id,
},
include={
'profile': True,
},
)
assert found is not None
assert found.profile is not None
assert found.profile.description == 'Foo'

found = await client.user.find_unique(
where={
'id': user2.id,
},
include={
'profile': True,
},
)
assert found is not None
assert found.profile is not None
assert found.profile.description == 'Foo 2'
22 changes: 22 additions & 0 deletions databases/tests/test_create_many_and_return_skip_duplicates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest

import prisma
from prisma import Prisma


@pytest.mark.asyncio
async def test_create_many_and_return_skip_duplicates(client: Prisma) -> None:
"""Skipping duplcates ignores unique constraint errors"""
user = await client.user.create({'name': 'Robert'})

with pytest.raises(prisma.errors.UniqueViolationError) as exc:
await client.user.create_many_and_return([{'id': user.id, 'name': 'Robert 2'}])

assert exc.match(r'Unique constraint failed')

records = await client.user.create_many_and_return(
[{'id': user.id, 'name': 'Robert 2'}, {'name': 'Tegan'}],
skip_duplicates=True,
)
assert len(records) == 1
assert records[0].name == 'Tegan'
2 changes: 2 additions & 0 deletions databases/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
'json_arrays',
'raw_queries',
'create_many_skip_duplicates',
'create_many_and_return',
'create_many_and_return_skip_duplicates',
'transactions',
'case_sensitivity',
'full_text_search',
Expand Down
2 changes: 2 additions & 0 deletions src/prisma/_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
'query_raw': 'mutation',
'query_first': 'mutation',
'create_many': 'mutation',
'create_many_and_return': 'mutation',
'execute_raw': 'mutation',
'delete_many': 'mutation',
'update_many': 'mutation',
Expand All @@ -61,6 +62,7 @@
'query_raw': 'queryRaw',
'query_first': 'queryRaw',
'create_many': 'createMany{model}',
'create_many_and_return': 'createMany{model}AndReturn',
'execute_raw': 'executeRaw',
'delete_many': 'deleteMany{model}',
'update_many': 'updateMany{model}',
Expand Down
1 change: 1 addition & 0 deletions src/prisma/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class _GenericAlias(Protocol):
'update',
'upsert',
'create_many',
'create_many_and_return',
'delete_many',
'update_many',
# read queries
Expand Down
66 changes: 66 additions & 0 deletions src/prisma/generator/templates/actions.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,72 @@ class {{ model.name }}Actions(Generic[{{ ModelType }}]):
)
return int(resp['data']['result']['count'])

{{ maybe_async_def }}create_many_and_return(
self,
data: List[types.{{ model.name }}CreateWithoutRelationsInput],
*,
skip_duplicates: Optional[bool] = None,
) -> List[{{ ModelType }}]:
"""Create multiple {{ model.name }} records at once.

This method is **not supported** on MariaDB or MySQL.

The `skip_duplicates` argument is **not supported** on SQLite.

Parameters
----------
data
List of {{ model.name }} record data
skip_duplicates
Boolean flag for ignoring unique constraint errors

Returns
-------
List[{{ RawModelType }}]
The list of all {{ model.name }} records that could be found

Raises
------
prisma.errors.UnsupportedDatabaseError
Attempting to query when using SQLite
prisma.errors.UniqueViolationError
A unique constraint check has failed, these can be ignored with the `skip_duplicates` argument
{{ query_error_doc }}
{{ base_error_doc }}

Example
-------
```py
records = {{ maybe_await }}{{ model.name }}.prisma().create_many_and_return(
data=[
{% for _ in range(2) %}
{
# data to create a {{ model.name }} record
{% for field in model.scalar_fields %}
{% if field.required_on_create %}
'{{ field.name }}': {{ field.get_sample_data() }},
{% endif %}
{% endfor %}
},
{% endfor %}
],
skip_duplicates=True,
)
```
"""
if skip_duplicates and self._client._active_provider in CREATE_MANY_SKIP_DUPLICATES_UNSUPPORTED:
raise errors.UnsupportedDatabaseError(self._client._active_provider, 'create_many_skip_duplicates')

resp = {{ maybe_await }}self._client._execute(
method='create_many_and_return',
model=self._model,
arguments={
'data': data,
'skipDuplicates': skip_duplicates,
},
)
return [model_parse(self._model, r) for r in resp['data']['result']]

{{ maybe_async_def }}delete(
self,
where: types.{{ model.name }}WhereUniqueInput,
Expand Down
Loading

0 comments on commit 0ce26e0

Please sign in to comment.