3131)
3232from stac_fastapi .core .extensions import filter
3333from stac_fastapi .core .serializers import CollectionSerializer , ItemSerializer
34- from stac_fastapi .core .utilities import MAX_LIMIT , bbox2polygon
34+ from stac_fastapi .core .utilities import MAX_LIMIT , bbox2polygon , get_bool_env
3535from stac_fastapi .opensearch .config import (
3636 AsyncOpensearchSettings as AsyncSearchSettings ,
3737)
@@ -723,7 +723,7 @@ async def check_collection_exists(self, collection_id: str):
723723 if not await self .client .exists (index = COLLECTIONS_INDEX , id = collection_id ):
724724 raise NotFoundError (f"Collection { collection_id } does not exist" )
725725
726- async def prep_create_item (
726+ async def async_prep_create_item (
727727 self , item : Item , base_url : str , exist_ok : bool = False
728728 ) -> Item :
729729 """
@@ -753,42 +753,105 @@ async def prep_create_item(
753753
754754 return self .item_serializer .stac_to_db (item , base_url )
755755
756- def sync_prep_create_item (
756+ async def bulk_async_prep_create_item (
757757 self , item : Item , base_url : str , exist_ok : bool = False
758758 ) -> Item :
759759 """
760760 Prepare an item for insertion into the database.
761761
762- This method performs pre-insertion preparation on the given `item`,
763- such as checking if the collection the item belongs to exists,
764- and optionally verifying that an item with the same ID does not already exist in the database.
762+ This method performs pre-insertion preparation on the given `item`, such as:
763+ - Verifying that the collection the item belongs to exists.
764+ - Optionally checking if an item with the same ID already exists in the database.
765+ - Serializing the item into a database-compatible format.
765766
766767 Args:
767- item (Item): The item to be inserted into the database.
768- base_url (str): The base URL used for constructing URLs for the item.
769- exist_ok (bool): Indicates whether the item can exist already.
768+ item (Item): The item to be prepared for insertion.
769+ base_url (str): The base URL used to construct the item's self URL.
770+ exist_ok (bool): Indicates whether the item can already exist in the database.
771+ If False, a `ConflictError` is raised if the item exists.
770772
771773 Returns:
772- Item: The item after preparation is done .
774+ Item: The prepared item, serialized into a database-compatible format .
773775
774776 Raises:
775777 NotFoundError: If the collection that the item belongs to does not exist in the database.
776- ConflictError: If an item with the same ID already exists in the collection.
778+ ConflictError: If an item with the same ID already exists in the collection and `exist_ok` is False,
779+ and `RAISE_ON_BULK_ERROR` is set to `true`.
777780 """
778- item_id = item ["id" ]
779- collection_id = item ["collection" ]
780- if not self .sync_client .exists (index = COLLECTIONS_INDEX , id = collection_id ):
781- raise NotFoundError (f"Collection { collection_id } does not exist" )
781+ logger .debug (f"Preparing item { item ['id' ]} in collection { item ['collection' ]} ." )
782782
783- if not exist_ok and self .sync_client .exists (
784- index = index_alias_by_collection_id (collection_id ),
785- id = mk_item_id (item_id , collection_id ),
783+ # Check if the collection exists
784+ await self .check_collection_exists (collection_id = item ["collection" ])
785+
786+ # Check if the item already exists in the database
787+ if not exist_ok and await self .client .exists (
788+ index = index_alias_by_collection_id (item ["collection" ]),
789+ id = mk_item_id (item ["id" ], item ["collection" ]),
786790 ):
787- raise ConflictError (
788- f"Item { item_id } in collection { collection_id } already exists"
791+ error_message = (
792+ f"Item { item [ 'id' ] } in collection { item [ 'collection' ] } already exists. "
789793 )
794+ if get_bool_env ("RAISE_ON_BULK_ERROR" , default = False ):
795+ raise ConflictError (error_message )
796+ else :
797+ logger .warning (
798+ f"{ error_message } Continuing as `RAISE_ON_BULK_ERROR` is set to false."
799+ )
800+ # Serialize the item into a database-compatible format
801+ prepped_item = self .item_serializer .stac_to_db (item , base_url )
802+ logger .debug (f"Item { item ['id' ]} prepared successfully." )
803+ return prepped_item
804+
805+ def bulk_sync_prep_create_item (
806+ self , item : Item , base_url : str , exist_ok : bool = False
807+ ) -> Item :
808+ """
809+ Prepare an item for insertion into the database.
790810
791- return self .item_serializer .stac_to_db (item , base_url )
811+ This method performs pre-insertion preparation on the given `item`, such as:
812+ - Verifying that the collection the item belongs to exists.
813+ - Optionally checking if an item with the same ID already exists in the database.
814+ - Serializing the item into a database-compatible format.
815+
816+ Args:
817+ item (Item): The item to be prepared for insertion.
818+ base_url (str): The base URL used to construct the item's self URL.
819+ exist_ok (bool): Indicates whether the item can already exist in the database.
820+ If False, a `ConflictError` is raised if the item exists.
821+
822+ Returns:
823+ Item: The prepared item, serialized into a database-compatible format.
824+
825+ Raises:
826+ NotFoundError: If the collection that the item belongs to does not exist in the database.
827+ ConflictError: If an item with the same ID already exists in the collection and `exist_ok` is False,
828+ and `RAISE_ON_BULK_ERROR` is set to `true`.
829+ """
830+ logger .debug (f"Preparing item { item ['id' ]} in collection { item ['collection' ]} ." )
831+
832+ # Check if the collection exists
833+ if not self .sync_client .exists (index = COLLECTIONS_INDEX , id = item ["collection" ]):
834+ raise NotFoundError (f"Collection { item ['collection' ]} does not exist" )
835+
836+ # Check if the item already exists in the database
837+ if not exist_ok and self .sync_client .exists (
838+ index = index_alias_by_collection_id (item ["collection" ]),
839+ id = mk_item_id (item ["id" ], item ["collection" ]),
840+ ):
841+ error_message = (
842+ f"Item { item ['id' ]} in collection { item ['collection' ]} already exists."
843+ )
844+ if get_bool_env ("RAISE_ON_BULK_ERROR" , default = False ):
845+ raise ConflictError (error_message )
846+ else :
847+ logger .warning (
848+ f"{ error_message } Continuing as `RAISE_ON_BULK_ERROR` is set to false."
849+ )
850+
851+ # Serialize the item into a database-compatible format
852+ prepped_item = self .item_serializer .stac_to_db (item , base_url )
853+ logger .debug (f"Item { item ['id' ]} prepared successfully." )
854+ return prepped_item
792855
793856 async def create_item (self , item : Item , refresh : bool = False ):
794857 """Database logic for creating one item.
@@ -987,7 +1050,6 @@ async def bulk_async(
9871050 collection_id : str ,
9881051 processed_items : List [Item ],
9891052 refresh : bool = False ,
990- raise_on_error : bool = False ,
9911053 ) -> Tuple [int , List [Dict [str , Any ]]]:
9921054 """
9931055 Perform a bulk insert of items into the database asynchronously.
@@ -996,7 +1058,6 @@ async def bulk_async(
9961058 collection_id (str): The ID of the collection to which the items belong.
9971059 processed_items (List[Item]): A list of `Item` objects to be inserted into the database.
9981060 refresh (bool): Whether to refresh the index after the bulk insert (default: False).
999- raise_on_error (bool): Whether to raise an error if the bulk operation fails (default: False).
10001061
10011062 Returns:
10021063 Tuple[int, List[Dict[str, Any]]]: A tuple containing:
@@ -1009,6 +1070,7 @@ async def bulk_async(
10091070 The `mk_actions` function is called to generate a list of actions for the bulk insert. If `refresh` is set to True,
10101071 the index is refreshed after the bulk insert.
10111072 """
1073+ raise_on_error = get_bool_env ("RAISE_ON_BULK_ERROR" , default = False )
10121074 success , errors = await helpers .async_bulk (
10131075 self .client ,
10141076 mk_actions (collection_id , processed_items ),
@@ -1022,7 +1084,6 @@ def bulk_sync(
10221084 collection_id : str ,
10231085 processed_items : List [Item ],
10241086 refresh : bool = False ,
1025- raise_on_error : bool = False ,
10261087 ) -> Tuple [int , List [Dict [str , Any ]]]:
10271088 """
10281089 Perform a bulk insert of items into the database synchronously.
@@ -1031,7 +1092,6 @@ def bulk_sync(
10311092 collection_id (str): The ID of the collection to which the items belong.
10321093 processed_items (List[Item]): A list of `Item` objects to be inserted into the database.
10331094 refresh (bool): Whether to refresh the index after the bulk insert (default: False).
1034- raise_on_error (bool): Whether to raise an error if the bulk operation fails (default: False).
10351095
10361096 Returns:
10371097 Tuple[int, List[Dict[str, Any]]]: A tuple containing:
@@ -1044,6 +1104,7 @@ def bulk_sync(
10441104 completed. The `mk_actions` function is called to generate a list of actions for the bulk insert. If `refresh` is set to
10451105 True, the index is refreshed after the bulk insert.
10461106 """
1107+ raise_on_error = get_bool_env ("RAISE_ON_BULK_ERROR" , default = False )
10471108 success , errors = helpers .bulk (
10481109 self .sync_client ,
10491110 mk_actions (collection_id , processed_items ),
0 commit comments