RPC Functions
This document describes the Remote Procedure Call (RPC) functions available in the Handelsregister application database.
store_discovery_results
Summary: A worker-facing function that receives the results of a basic discovery search and writes the outcome to the database.
Context: This is the primary entry point for the basic discovery worker after it has queried the Handelsregister API. The function encapsulates all the business logic required to handle the different outcomes (e.g., too many results, a few results, etc.). It ensures that the searches, processing_jobs, entities, and optionally bulk_search_items tables are all updated atomically and consistently based on the result count.
The function supports both regular searches and bulk search operations. When bulk_search_item_id is present in the job data, the function updates the corresponding bulk_search_items entry with the appropriate status and results.
Signature:
store_discovery_results(p_job_id uuid, p_search_id uuid, p_result_count integer, p_results jsonb) RETURNS voidParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_job_id | uuid | Yes | The ID of the processing_jobs entry that the worker processed. |
p_search_id | uuid | Yes | The ID of the original search from the public.searches table. |
p_result_count | integer | Yes | The total number of results found by the worker. |
p_results | jsonb | Yes | A JSON array of the companies found. The structure depends on the path taken. |
p_results JSON Structure:
A JSON array of objects. Each object must contain the following fields:
name(text)legal_form(text)register_court(text)register_number(text)address(text)seat(text)state(text)raw(text)register_type(text)registration_status(text)hrapi_id(text, optional - used for fallback API tracking)si_document_xml(text, only for Path A, can be null)si_document_json(jsonb, only for Path A when using PDF fallback, can be null)
For Path A (≤3 results): A complete object including either
si_document_xmlorsi_document_json(or both).json[{ "name": "Example GmbH", "legal_form": "Gesellschaft mit beschränkter Haftung", "register_court": "District Court Berlin (Charlottenburg)", "register_number": "123456", "address": "Beispielstraße 1, 10117 Berlin", "seat": "Berlin", "state": "active", "raw": "raw response data", "register_type": "HRB", "registration_status": "currently registered", "hrapi_id": "12345", "si_document_xml": "<xml>...</xml>", "si_document_json": null }]OR with PDF fallback:
json[{ "name": "Example GmbH", "legal_form": "Gesellschaft mit beschränkter Haftung", "register_court": "District Court Berlin (Charlottenburg)", "register_number": "123456", "address": "Beispielstraße 1, 10117 Berlin", "seat": "Berlin", "state": "active", "raw": "raw response data", "register_type": "HRB", "registration_status": "currently registered", "hrapi_id": "12345", "si_document_xml": null, "si_document_json": {"shareholders": [...], "capital": {...}} }]For Path B (4-20 results): The object without
si_document_xmlorsi_document_json.json[{ "name": "Example AG", "legal_form": "Aktiengesellschaft", "register_court": "District Court Munich", "register_number": "789012", "address": "Musterstraße 2, 80331 München", "seat": "Munich", "state": "active", "raw": "raw response data", "register_type": "HRB", "registration_status": "currently registered", "hrapi_id": "67890" }]For Path C (>20 results): An empty array
[].
Core Logic & Behavior:
The function first validates the p_job_id to ensure it exists and is in a processing state. It uses a FOR UPDATE lock to prevent concurrent modifications. It then proceeds based on the p_result_count using defined constants:
MAX_RESULTS_FOR_AUTO_DOWNLOAD = 3MAX_RESULTS_FOR_USER_SELECTION = 20
Path C: Too Many Results
- Trigger:
p_result_count > 20. - Actions:
- Updates
public.searchesstatus toresult_count_exceeds_limit(ifp_search_idis provided). - Updates
bulk_search_itemsstatus to'failed'with error message ifbulk_search_item_idis present in job data. - Updates the
processing.processing_jobsentry with statuscompletedand a descriptiveresultmessage (properly cast to jsonb). - No entities are created.
- Updates
- Trigger:
Path B: User Selection List
- Trigger:
p_result_countis between 4 and 20. - Actions:
- Updates
public.searchesstatus tocompletedand storesresults_count(ifp_search_idis provided). - For each item in
p_results, checks if an entity with the sameregister_numberalready exists. - If entity exists, updates it with new data; if not, creates a new entity with
processing_statusset todiscovered. - Updates
hrapi_idif provided (used for fallback API tracking). - Creates linking entries in
public.search_entitiesusingON CONFLICT DO NOTHING(only ifp_search_idis provided). - Updates
bulk_search_itemsstatus to'failed'with error message ifbulk_search_item_idis present in job data. - Marks the
processing.processing_jobsentry ascompleted.
- Updates
- Trigger:
Path A: Auto-Download
- Trigger:
p_result_countis between 1 and 3. - Actions:
- Updates
public.searchesstatus tocompletedand storesresults_count(ifp_search_idis provided). - For each item in
p_results, checks if an entity with the sameregister_numberalready exists. - If entity exists, updates it with new data including XML/JSON; if not, creates a new entity.
- Processing Status Logic:
- If
si_document_json IS NOT NULL: Setsprocessing_status = 'basic_discovery_complete'(parsing already done by PDF fallback). - Otherwise: Sets
processing_status = 'xml_ready'(needs XML parsing or waiting for fallback).
- If
- Sets
si_document_retrieved_atto current timestamp when XML or JSON is provided. - Updates
hrapi_idif provided (used for fallback API tracking). - Creates linking entries in
public.search_entitiesusingON CONFLICT DO NOTHING(only ifp_search_idis provided). - Updates
bulk_search_itemsstatus to'processing'ifbulk_search_item_idis present in job data. - Marks the
processing.processing_jobsentry ascompleted.
- Updates
- Trigger:
No Results
- Trigger:
p_result_countis 0. - Actions:
- Updates
public.searchesstatus tocompletedwith aresults_countof 0 (ifp_search_idis provided). - Updates
bulk_search_itemsstatus to'failed'with error message ifbulk_search_item_idis present in job data. - Marks the
processing.processing_jobsentry ascompleted.
- Updates
- Trigger:
Return Value: The function returns VOID on a successful transaction. If any error occurs, it throws an exception instead.
Error Handling:
- The function is transactional. All database writes are performed as a single unit; if any step fails, the entire transaction is rolled back, leaving the database in its original state.
- Graceful degradation: If the job is not found or is not in a
runningstate, the function silently returns without throwing exceptions. This prevents errors from invalid job states that may occur due to race conditions or worker restarts.
Permissions: This function is intended to be called by a trusted service_role client, such as the backend worker.
retry_shareholder_parsing
Summary: A user-facing function that creates a new shareholder parsing job after a previous parsing attempt has failed.
Context: This function is called from the frontend when a user clicks a "retry" button after shareholder parsing has failed. It validates that the entity is in a parsing_failed state, retrieves the document ID from the previous failed job, and creates a new parsing job to retry the operation.
Signature:
retry_shareholder_parsing(p_entity_id UUID) RETURNS JSONBParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_entity_id | UUID | Yes | The ID of the entity for which to retry shareholder parsing. |
Return Value:
Returns a JSONB object with the following structure:
{
"job_id": "uuid-of-new-job",
"error": null,
"retry": false
}| Field | Type | Description |
|---|---|---|
job_id | UUID or null | The ID of the newly created parsing job, or null if an error occurred. |
error | string or null | Error message if the operation failed, null on success. |
retry | boolean | Whether the client should retry the request (true for transient errors like deadlocks). |
Core Logic & Behavior:
Entity Status Validation:
- Trigger: The function is called.
- Actions:
- Locks the entity row using
FOR UPDATE. - Validates that the entity exists.
- Validates that the entity's
shareholder_research_statusisparsing_failed. - Returns error if validation fails.
- Locks the entity row using
Document Retrieval:
- Trigger: Entity validation succeeds.
- Actions:
- Queries
processing.processing_jobsfor the most recent failedshareholder_parsingjob for this entity. - Extracts the
document_idfrom the job'sdatafield. - Returns error if no failed job is found.
- Queries
Entity Status Update:
- Trigger: Document ID is successfully retrieved.
- Actions:
- Updates the entity's
shareholder_research_statustoparsing. - Sets the
updated_attimestamp.
- Updates the entity's
Job Creation:
- Trigger: Entity status is successfully updated.
- Actions:
- Creates a new
shareholder_parsingjob inprocessing.processing_jobs. - Sets job status to
queued. - Stores the
document_idin the job'sdatafield as{"document_id": "..."}. - Links the job to the entity via
entity_id.
- Creates a new
Error Cases:
| Error Message | Cause | Retry? |
|---|---|---|
"Entity with id ... does not exist" | Invalid entity ID provided | No |
"Invalid entity status: ... (expected parsing_failed)" | Entity is not in parsing_failed state | No |
"No failed parsing job found for entity" | No previous failed parsing job exists | No |
"Deadlock detected: ..." | Database deadlock occurred | Yes |
| Other SQL errors | Unexpected database error | No |
Usage Example:
const { data, error } = await supabase.rpc('retry_shareholder_parsing', {
p_entity_id: 'entity-uuid-here'
});
if (error) {
console.error('Failed to retry parsing:', error);
} else if (data.error) {
console.error('RPC error:', data.error);
if (data.retry) {
// Transient error, retry the request
}
} else {
console.log('New parsing job created:', data.job_id);
}Notes:
- This function is user-facing and should be called with proper authentication checks.
- The function uses
FOR UPDATElocking to prevent race conditions. - The new job will be picked up by the shareholder parsing worker automatically.
- The function preserves the original document ID, so the same file will be re-parsed.
Permissions: This function should be accessible to authenticated users who have permission to manage the entity. It is not exposed to the public API.
store_xml_parsing_results
Summary: A worker-facing function that stores the results of the XML parsing phase.
Context: This function is called by the XML parsing worker after it has successfully extracted structured data from a company's XML document. It updates the target entity with the parsed JSON data, moves the entity to the next stage in the processing pipeline, and marks the parsing job as complete.
Signature:
store_xml_parsing_results(p_job_id uuid, p_entity_id uuid, p_results jsonb, p_address text DEFAULT NULL) RETURNS voidParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_job_id | uuid | Yes | The ID of the xml_parsing job from the processing.processing_jobs table. |
p_entity_id | uuid | Yes | The ID of the content.entities record to update with the results. |
p_results | jsonb | Yes | The structured JSON data extracted from the XML. |
p_address | text | No | An optional updated address for the entity. If NULL, the existing address is kept. |
p_results JSON Structure:
A JSON object containing the key-value pairs extracted from the XML document. The structure is flexible but should be consistent.
{
"company_details": {
"name": "Example Company GmbH",
"legal_form": "GmbH"
},
"registration": {
"court": "Amtsgericht Charlottenburg",
"number": "12345 B"
},
"capital": "25000 EUR"
}Core Logic & Behavior:
The function performs the following steps in a single transaction:
Job and Entity Validation:
- Trigger: The function is called.
- Actions:
- Locks the job and entity rows using
FOR UPDATEto prevent race conditions. - Validates that the
processing.processing_jobsentry exists, itstypeisxml_parsing, and itsstatusisrunning. - Validates that the
content.entitiesrecord exists and itsprocessing_statusisxml_parsing_running. - Raises an exception if any validation fails.
- Locks the job and entity rows using
Entity Update:
- Trigger: Validation succeeds.
- Actions:
- Updates the
content.entitiesrecord. - Sets the
si_document_jsonfield to thep_resultsvalue. - Updates the
addressonly ifp_addressis not NULL. - Changes the
processing_statustobasic_discovery_complete. - Updates the
updated_attimestamp.
- Updates the
Job Completion:
- Trigger: The entity is successfully updated.
- Actions:
- Updates the
processing.processing_jobsentry. - Sets the
statustocompleted. - Stores a success message in the
resultfield. - Sets the
completed_attimestamp.
- Updates the
Return Value: The function returns VOID on successful completion.
Error Handling:
- The function is transactional. If any step fails, the entire operation is rolled back.
- Graceful degradation: If the job is not found, is not in a
runningstate, is not of typexml_parsing, or if the entity is not found or not inxml_parsing_runningstate, the function silently returns without throwing exceptions. This prevents errors from invalid states that may occur due to race conditions or worker restarts.
Permissions: This function is intended to be called by a trusted service_role client, such as the backend worker.
record_job_error
Summary: Provides a centralized and consistent way for workers to report job failures.
Context: This is the single entry point for marking a job as failed. It ensures that all errors are stored in a consistent, structured format and prevents workers from needing to construct complex JSON objects themselves. It gracefully handles edge cases where a job might not be in a fail-able state.
Signature:
record_job_error(p_job_id uuid, p_error_source text, p_error_type text, p_error_sub_type text, p_error_severity text, p_error_message text) RETURNS voidParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_job_id | uuid | Yes | The ID of the processing_jobs entry that has failed. |
p_error_source | text | Yes | The origin of the error (e.g., worker, rpc_function). |
p_error_type | text | Yes | A broad categorization of the error (e.g., api_error, validation_error). |
p_error_sub_type | text | Yes | A specific, machine-readable code for the error (e.g., api_timeout, job_not_found). |
p_error_severity | text | Yes | Indicates the error's impact (1 - 5 (most severe)). |
p_error_message | text | Yes | A detailed, human-readable description of the error. |
Core Logic & Behavior:
- Job Validation:
- Trigger: The function is called.
- Actions:
- Finds the job by
p_job_idand locks the row. - If the job is not found, it logs a warning and exits.
- If the job's status is not
running, it logs a warning that the job cannot be failed and exits. This prevents race conditions where a job might have been handled by another process.
- Finds the job by
- Error Recording:
- Trigger: The job is found and is in a
runningstate. - Actions:
- Constructs a standard, structured
jsonberror object. - Updates the job's
statustofailed, sets theresultfield to the error object, and records thecompleted_attimestamp. - This update fires the
on_job_failuretrigger, which handles the retry/final failure logic.
- Constructs a standard, structured
- Trigger: The job is found and is in a
Return Value: The function returns VOID. It does not throw exceptions for invalid job states, allowing workers to "fire and forget" without needing complex error handling for cases they cannot fix.
Permissions: This function is intended to be called by trusted service_role clients, such as backend workers. It uses the default SECURITY INVOKER model.
start_entity_basic_discovery
Summary: Initiates the basic discovery process for an entity by updating its processing status from 'discovered' to 'basic_discovery_running'.
Context: This function is part of Path B in the technical flow, where users manually select specific entities from a list of 4-20 discovered results. After a user chooses which entities they want to process further, this function updates the entity's status to trigger the next phase of processing. A database trigger (to be implemented) will automatically create basic discovery jobs for entities with this status.
Signature:
start_entity_basic_discovery(entity_id uuid) RETURNS jsonParameters:
| Name | Type | Required | Description |
|---|---|---|---|
entity_id | uuid | Yes | The unique identifier of the entity to start basic discovery for |
Core Logic & Behavior:
Authentication Check:
- Trigger: Function is called.
- Actions:
- Verifies user is authenticated via
auth.uid(). - Returns error if not authenticated.
- Verifies user is authenticated via
Entity Validation:
- Trigger: After authentication passes.
- Actions:
- Checks if entity exists in
content.entities. - Validates current
processing_statusis 'discovered'. - Returns specific error for entity not found or invalid status.
- Checks if entity exists in
Status Update:
- Trigger: All validations pass.
- Actions:
- Updates
processing_statusto 'basic_discovery_running'. - Sets
updated_atto current timestamp. - Uses conditional WHERE clause to prevent race conditions.
- Updates
Return Value: Returns a JSON object indicating success or failure. On success, includes a confirmation message. On failure, includes specific error details and current status when applicable.
Error Handling:
- Non-transactional: Returns JSON error responses instead of throwing exceptions.
- Comprehensive validation: Checks authentication, entity existence, and valid status transitions.
- Race condition protection: Uses conditional UPDATE to ensure only entities with 'discovered' status are modified.
Permissions: This function uses SECURITY DEFINER and requires user authentication. It's intended to be called by authenticated frontend users who want to process specific entities from their search results.
start_deep_research
Initiates the deep research process for an entity by updating its processing status from 'basic_discovery_complete' to 'deep_research_ready' and creating a processing job.
- Writes to:
processing.processing_jobs,content.entities
Function Signature
CREATE OR REPLACE FUNCTION start_deep_research(entity_id UUID)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINERParameters
entity_id(UUID): The unique identifier of the entity to start deep research for
Return Value
Returns a JSONB object with the following structure:
Success Response:
{
"success": true
}Error Responses:
{
"success": false,
"error": "Authentication required"
}{
"success": false,
"error": "Basic discovery not complete"
}Notes
- Requires authentication
- Only works on entities with status 'basic_discovery_complete'
- Creates a processing job of type 'collection' with status 'queued'
- Part of the processing pipeline:
basic_discovery_complete → deep_research_ready - The worker will update the status to 'deep_research_running' when it starts processing
record_file_and_document
Summary: A function to register a successfully uploaded file into the database, creating records in both
content.filesandcontent.documents.
Context: This is the primary entry point after a file has been successfully uploaded to the storage bucket. The function is designed to handle file deduplication by checking the file's hash. If the file already exists in content.files, it reuses the existing record; otherwise, it creates a new one. It then creates a new content.documents record that links the file to a specific entity and stores its associated metadata.
Signature:
record_file_and_document(
p_file_hash TEXT,
p_storage_path TEXT,
p_file_size_bytes BIGINT,
p_mime_type TEXT,
p_entity_id UUID,
p_original_filename TEXT,
p_parent_document_id UUID DEFAULT NULL,
p_display_name TEXT DEFAULT NULL,
p_hr_document_path TEXT DEFAULT NULL,
p_document_date DATE DEFAULT NULL,
p_received_on DATE DEFAULT NULL,
p_published_on DATE DEFAULT NULL,
p_created_by TEXT DEFAULT NULL,
p_type_of_document TEXT DEFAULT NULL,
p_language_identifier TEXT DEFAULT NULL
) RETURNS UUIDParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_file_hash | TEXT | Yes | The SHA256 hash of the file's content, used for deduplication. |
p_storage_path | TEXT | Yes | The full path to the file in the Supabase storage bucket. |
p_file_size_bytes | BIGINT | Yes | The size of the file in bytes. |
p_mime_type | TEXT | Yes | The MIME type of the file (e.g., 'application/pdf'). |
p_entity_id | UUID | Yes | The ID of the content.entities record this document belongs to. |
p_original_filename | TEXT | Yes | The original filename from the Handelsregister. |
p_parent_document_id | UUID | No | If extracted from an archive, this points to the parent document. |
p_display_name | TEXT | No | A clean, human-readable name for the document. |
p_hr_document_path | TEXT | No | The navigational path from the Handelsregister portal (e.g., "VÖ/1/2"). |
p_document_date | DATE | No | The date printed on the document itself. |
p_received_on | DATE | No | The date the document was received by the register. |
p_published_on | DATE | No | The date the document was officially published. |
p_created_by | TEXT | No | The source provided by the handelsregister. |
p_type_of_document | TEXT | No | The specific type of the document (e.g., 'Gesellschafterliste', 'Jahresabschluss'). |
p_language_identifier | TEXT | No | The language of the document |
Core Logic & Behavior:
The function executes the following steps within a single transaction:
File Deduplication:
- Trigger: The function is called.
- Action: It first queries the
content.filestable for a row with a matchingp_file_hash. - If a match is found: It uses the
idof the existing file record. - If no match is found: It inserts a new row into
content.fileswith the provided file metadata and retrieves the newid.
Document Creation:
- Trigger: After the file ID has been determined (either found or created).
- Action: It inserts a new row into the
content.documentstable, linking the document to the entity (p_entity_id) and the physical file (file_id). It populates all provided metadata, including the optional fields.
Return Value: The function returns the UUID of the newly created row in the content.documents table.
Error Handling:
- The function is transactional. If any step fails (e.g., a required parameter is missing, or a foreign key constraint is violated), the entire transaction is rolled back, ensuring no partial data is left in the database.
- It relies on database constraints to ensure data integrity. For example, trying to insert a document for a non-existent
p_entity_idwill fail.
Permissions: This function uses SECURITY DEFINER, allowing it to be called by roles that do not have direct INSERT permissions on the underlying content.files or content.documents tables. It is intended to be called by a trusted service_role client or an authenticated user who has successfully completed a file upload.
request_shareholder_research
Summary: A user-facing function to initiate shareholder research for a specific entity.
Context: This function is triggered when a user clicks the button to request shareholder information for a company. It validates that shareholder research hasn't already been initiated, updates the entity's status to indicate research is ready to begin, and creates a download job. This is the entry point for a two-stage workflow: download first, then parse.
Signature:
request_shareholder_research(p_entity_id UUID) RETURNS UUIDParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_entity_id | UUID | Yes | The ID of the entity to research shareholders for. |
Core Logic & Behavior:
Entity Validation:
- Trigger: The function is called.
- Actions:
- Checks if the entity exists by querying its
shareholder_research_status. - Raises an exception if the entity is not found.
- Validates that the current status is
not_started. - Raises an exception if research has already been initiated (any status other than
not_started).
- Checks if the entity exists by querying its
Status Update:
- Trigger: Validation succeeds.
- Actions:
- Updates the entity's
shareholder_research_statustoready. - Sets the
updated_attimestamp.
- Updates the entity's
Job Creation:
- Trigger: The entity status is successfully updated.
- Actions:
- Inserts a new row into
processing.processing_jobs. - Sets the job
typetoshareholder_download(first stage). - Sets the job
statustoqueued. - Links the job to the entity via
entity_id.
- Inserts a new row into
Return Value: Returns the UUID of the newly created download job.
Error Handling:
- The function is transactional. If any step fails, the entire operation is rolled back.
- Explicit exceptions: Raises exceptions for entity not found or invalid status, allowing the frontend to display appropriate error messages to the user.
Permissions: This function uses SECURITY DEFINER and is intended to be called by authenticated frontend users.
Workflow: This initiates a two-stage process:
- Download stage: Worker downloads the shareholder list document and stores it via
store_shareholder_download_results - Parsing stage: Automatically created after download, extracts data via LLM and stores via
store_shareholder_parsing_results
store_shareholder_download_results
Summary: A worker-facing function that records successful download of a shareholder list document and queues it for parsing.
Context: This function is called by the shareholder download worker after it has successfully downloaded a shareholder list document from the Handelsregister and stored it via record_file_and_document. By separating download from parsing, we ensure the expensive file download only happens once, even if LLM extraction fails and needs retry. This respects Handelsregister rate limits.
Signature:
store_shareholder_download_results(p_job_id UUID, p_entity_id UUID, p_document_id UUID) RETURNS voidParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_job_id | UUID | Yes | The ID of the shareholder_download job from the processing.processing_jobs table. |
p_entity_id | UUID | Yes | The ID of the entity whose document was downloaded. |
p_document_id | UUID | Yes | The ID of the stored document in content.documents. |
Core Logic & Behavior:
Job and Entity Validation:
- Trigger: The function is called.
- Actions:
- Locks the job and entity rows using
FOR UPDATE. - Validates that the
processing.processing_jobsentry exists, itstypeisshareholder_download, and itsstatusisrunning. - Validates that the entity's
shareholder_research_statusisdownloading. - Silently returns if validation fails (graceful degradation for race conditions).
- Locks the job and entity rows using
Entity Status Update:
- Trigger: Validation succeeds.
- Actions:
- Updates the entity's
shareholder_research_statustodownloaded. - Sets the
updated_attimestamp.
- Updates the entity's
Download Job Completion:
- Trigger: The entity status is successfully updated.
- Actions:
- Updates the download job's
statustocompleted. - Stores a success message in the
resultfield. - Sets the
completed_attimestamp.
- Updates the download job's
Parsing Job Creation:
- Trigger: The download job is marked complete.
- Actions:
- Creates a new
shareholder_parsingjob. - Sets status to
queued. - Stores the
document_idin the job'sdatafield for the parsing worker.
- Creates a new
Return Value: The function returns VOID on successful completion.
Error Handling:
- The function is transactional. If any step fails, the entire operation is rolled back.
- Graceful degradation: If the job or entity is not in the expected state, the function silently returns without throwing exceptions, preventing errors from race conditions or worker restarts.
Permissions: This function is intended to be called by a trusted service_role client, such as the backend worker.
store_shareholder_parsing_results
Summary: A worker-facing function that stores the extracted shareholder data and completes the shareholder research process.
Context: This function is called by the shareholder parsing worker after it has successfully processed a downloaded shareholder list document through an LLM and extracted structured shareholder information. It validates the job and entity states, inserts all shareholders into the database, and marks the research as complete.
Signature:
store_shareholder_parsing_results(p_job_id UUID, p_entity_id UUID, p_source_document_id UUID, p_shareholders JSONB) RETURNS voidParameters:
| Name | Type | Required | Description |
|---|---|---|---|
p_job_id | UUID | Yes | The ID of the shareholder_parsing job from the processing.processing_jobs table. |
p_entity_id | UUID | Yes | The ID of the entity whose shareholders are being stored. |
p_source_document_id | UUID | Yes | The ID of the source document in content.documents from which the data was extracted. |
p_shareholders | JSONB | Yes | A JSON array of shareholder objects. |
p_shareholders JSON Structure:
A JSON array of objects, where each object represents a shareholder. Fields differ based on shareholder_type:
For natural persons:
{
"shareholder_type": "natural_person",
"first_name": "Max",
"last_name": "Mustermann",
"date_of_birth": "1980-05-15",
"residence": "Berlin",
"share_nominal_amount": 25000,
"share_percentage": 50.0,
"sequence_number": 1
}For organizations:
{
"shareholder_type": "organization",
"company_name": "Example Holding GmbH",
"register_court": "Amtsgericht München",
"register_number": "HRB 12345",
"seat": "München",
"foreign_entity": false,
"share_nominal_amount": 25000,
"share_percentage": 50.0,
"sequence_number": 2
}Complete example:
[
{
"shareholder_type": "natural_person",
"first_name": "Max",
"last_name": "Mustermann",
"date_of_birth": "1980-05-15",
"residence": "Berlin",
"share_nominal_amount": 25000,
"share_percentage": 50.0,
"sequence_number": 1
},
{
"shareholder_type": "organization",
"company_name": "Example Holding GmbH",
"register_court": "Amtsgericht München",
"register_number": "HRB 12345",
"seat": "München",
"foreign_entity": false,
"share_nominal_amount": 25000,
"share_percentage": 50.0,
"sequence_number": 2
}
]Core Logic & Behavior:
Job and Entity Validation:
- Trigger: The function is called.
- Actions:
- Locks the job and entity rows using
FOR UPDATE. - Validates that the
processing.processing_jobsentry exists, itstypeisshareholder_parsing, and itsstatusisrunning. - Validates that the entity's
shareholder_research_statusisparsing. - Silently returns if validation fails (graceful degradation for race conditions).
- Locks the job and entity rows using
Shareholder Data Insertion:
- Trigger: Validation succeeds.
- Actions:
- Loops through each object in the
p_shareholdersJSONB array. - Inserts each shareholder into
content.entity_shareholders. - Links each shareholder to the entity via
entity_idand to the source document viasource_document_id.
- Loops through each object in the
Entity Status Update:
- Trigger: All shareholders are successfully inserted.
- Actions:
- Updates the entity's
shareholder_research_statustocomplete. - Sets the
updated_attimestamp.
- Updates the entity's
Job Completion:
- Trigger: The entity status is successfully updated.
- Actions:
- Updates the job's
statustocompleted. - Stores a success message in the
resultfield. - Sets the
completed_attimestamp.
- Updates the job's
Return Value: The function returns VOID on successful completion.
Error Handling:
- The function is transactional. If any step fails, the entire operation is rolled back.
- Graceful degradation: If the job or entity is not in the expected state, the function silently returns without throwing exceptions, preventing errors from race conditions or worker restarts.
Permissions: This function is intended to be called by a trusted service_role client, such as the backend worker.