diff --git a/source-hubspot-native/source_hubspot_native/api.py b/source-hubspot-native/source_hubspot_native/api.py index 4ffe171a7c..1431739633 100644 --- a/source-hubspot-native/source_hubspot_native/api.py +++ b/source-hubspot-native/source_hubspot_native/api.py @@ -90,6 +90,7 @@ async def fetch_page_with_associations( # Closed over via functools.partial: cls: type[CRMObject], http: HTTPSession, + with_history: bool, object_name: str, # Remainder is common.FetchPageFn: log: Logger, @@ -123,10 +124,12 @@ async def fetch_page_with_associations( property_names = ",".join(props) input = { - "limit": 50, # Maximum when requesting history. + "limit": 100, "properties": property_names, - "propertiesWithHistory": property_names, } + if with_history: + input["propertiesWithHistory"] = property_names + input["limit"] = 50 if len(cls.ASSOCIATED_ENTITIES) > 0: input["associations"] = ",".join(cls.ASSOCIATED_ENTITIES) if page: @@ -157,7 +160,8 @@ async def fetch_page_with_associations( output[idx].updatedAt = doc.updatedAt # We'll discard this document per the check a little further down. output[idx].properties.update(doc.properties) - output[idx].propertiesWithHistory.update(doc.propertiesWithHistory) + if with_history: + output[idx].propertiesWithHistory.update(doc.propertiesWithHistory) for doc in output: if doc.updatedAt < cutoff: @@ -171,6 +175,7 @@ async def _fetch_batch( log: Logger, cls: type[CRMObject], http: HTTPSession, + with_history: bool, object_name: str, ids: Iterable[str], ) -> BatchResult[CRMObject]: @@ -182,8 +187,9 @@ async def _fetch_batch( input = { "inputs": [{"id": id} for id in ids], "properties": property_names, - "propertiesWithHistory": property_names, } + if with_history: + input["propertiesWithHistory"] = property_names _cls: Any = cls # Silence mypy false-positive. return BatchResult[_cls].model_validate_json( @@ -211,12 +217,13 @@ async def fetch_batch_with_associations( log: Logger, cls: type[CRMObject], http: HTTPSession, + with_history: bool, object_name: str, ids: list[str], ) -> BatchResult[CRMObject]: batch, all_associated = await asyncio.gather( - _fetch_batch(log, cls, http, object_name, ids), + _fetch_batch(log, cls, http, with_history, object_name, ids), asyncio.gather( *( fetch_association(log, cls, http, object_name, ids, e) @@ -239,7 +246,7 @@ async def fetch_batch_with_associations( FetchRecentFn = Callable[ - [Logger, HTTPSession, datetime, datetime | None], + [Logger, HTTPSession, bool, datetime, datetime | None], AsyncGenerator[tuple[datetime, str, Any], None], ] ''' @@ -257,7 +264,7 @@ async def fetch_batch_with_associations( ''' FetchDelayedFn = Callable[ - [Logger, HTTPSession, datetime, datetime], + [Logger, HTTPSession, bool, datetime, datetime], AsyncGenerator[tuple[datetime, str, Any], None], ] ''' @@ -313,6 +320,7 @@ async def process_changes( fetch_recent: FetchRecentFn, fetch_delayed: FetchDelayedFn, http: HTTPSession, + with_history: bool, # Remainder is common.FetchChangesFn: log: Logger, log_cursor: LogCursor, @@ -359,7 +367,7 @@ async def process_changes( max_ts: datetime = log_cursor try: - async for ts, key, obj in fetch_recent(log, http, log_cursor, fetch_recent_end_time): + async for ts, key, obj in fetch_recent(log, http, with_history, log_cursor, fetch_recent_end_time): if fetch_recent_end_time and ts > fetch_recent_end_time: continue elif ts > log_cursor: @@ -391,7 +399,7 @@ async def process_changes( if delayed_fetch_next_end - delayed_fetch_next_start > delayed_fetch_minimum_window: # Poll the delayed stream for documents if we need to. try: - async for ts, key, obj in fetch_delayed(log, http, delayed_fetch_next_start, delayed_fetch_next_end): + async for ts, key, obj in fetch_delayed(log, http, with_history, delayed_fetch_next_start, delayed_fetch_next_end): if ts > delayed_fetch_next_end: # In case the FetchDelayedFn is unable to filter based on # `delayed_fetch_next_end`. @@ -440,6 +448,7 @@ async def fetch_changes_with_associations( fetcher: _FetchIdsFn, log: Logger, http: HTTPSession, + with_history: bool, since: datetime, until: datetime | None, ) -> AsyncGenerator[tuple[datetime, str, CRMObject], None]: @@ -479,14 +488,13 @@ async def _do_batch_fetch(batch: list[tuple[datetime, str]]) -> Iterable[tuple[d dts = {id: dt for dt, id in batch} documents: BatchResult[CRMObject] = await fetch_batch_with_associations( - log, cls, http, object_name, [id for _, id in batch] + log, cls, http, with_history, object_name, [id for _, id in batch] ) return ((dts[str(doc.id)], str(doc.id), doc) for doc in documents.results) - async def _batches_gen() -> AsyncGenerator[Awaitable[Iterable[tuple[datetime, str, CRMObject]]], None]: - for batch_it in itertools.batched(recent, 50): + for batch_it in itertools.batched(recent, 50 if with_history else 100): yield _do_batch_fetch(list(batch_it)) async for res in buffer_ordered(_batches_gen(), 3): @@ -728,30 +736,30 @@ async def fetch_search_objects_modified_at( def fetch_recent_custom_objects( - object_name: str, log: Logger, http: HTTPSession, since: datetime, until: datetime | None + object_name: str, log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, CustomObject], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(object_name, log, http, since, until, page) return fetch_changes_with_associations( - object_name, CustomObject, do_fetch, log, http, since, until + object_name, CustomObject, do_fetch, log, http, with_history, since, until ) def fetch_delayed_custom_objects( - object_name: str, log: Logger, http: HTTPSession, since: datetime, until: datetime + object_name: str, log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, CustomObject], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(object_name, log, http, since, until, page) return fetch_changes_with_associations( - object_name, CustomObject, do_fetch, log, http, since, until + object_name, CustomObject, do_fetch, log, http, with_history, since, until ) def fetch_recent_companies( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None, + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None, ) -> AsyncGenerator[tuple[datetime, str, Company], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: @@ -772,24 +780,24 @@ async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetim return fetch_changes_with_associations( - Names.companies, Company, do_fetch, log, http, since, until + Names.companies, Company, do_fetch, log, http, with_history, since, until ) def fetch_delayed_companies( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Company], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.companies, log, http, since, until, page) return fetch_changes_with_associations( - Names.companies, Company, do_fetch, log, http, since, until + Names.companies, Company, do_fetch, log, http, with_history, since, until ) def fetch_recent_contacts( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, Contact], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: if count >= 9_900: @@ -816,24 +824,24 @@ async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetim return fetch_changes_with_associations( - Names.contacts, Contact, do_fetch, log, http, since, until + Names.contacts, Contact, do_fetch, log, http, with_history, since, until ) def fetch_delayed_contacts( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Contact], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.contacts, log, http, since, until, page, "lastmodifieddate") return fetch_changes_with_associations( - Names.contacts, Contact, do_fetch, log, http, since, until + Names.contacts, Contact, do_fetch, log, http, with_history, since, until ) def fetch_recent_deals( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, Deal], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: @@ -855,19 +863,19 @@ async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetim return fetch_changes_with_associations( - Names.deals, Deal, do_fetch, log, http, since, until + Names.deals, Deal, do_fetch, log, http, with_history, since, until ) def fetch_delayed_deals( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Deal], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.deals, log, http, since, until, page) return fetch_changes_with_associations( - Names.deals, Deal, do_fetch, log, http, since, until + Names.deals, Deal, do_fetch, log, http, with_history, since, until ) @@ -895,7 +903,7 @@ async def _fetch_engagements( def fetch_recent_engagements( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, Engagement], None]: return fetch_changes_with_associations( Names.engagements, @@ -903,13 +911,14 @@ def fetch_recent_engagements( functools.partial(_fetch_engagements, log, http), log, http, + with_history, since, until, ) def fetch_delayed_engagements( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Engagement], None]: # There is no way to fetch engagements other than starting with the most # recent and reading backward, so this is the same process as fetching @@ -921,13 +930,14 @@ def fetch_delayed_engagements( functools.partial(_fetch_engagements, log, http), log, http, + with_history, since, until, ) def fetch_recent_tickets( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, Ticket], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: @@ -944,67 +954,67 @@ async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetim return fetch_changes_with_associations( - Names.tickets, Ticket, do_fetch, log, http, since, until + Names.tickets, Ticket, do_fetch, log, http, with_history, since, until ) def fetch_delayed_tickets( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Ticket], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.tickets, log, http, since, until, page) return fetch_changes_with_associations( - Names.tickets, Ticket, do_fetch, log, http, since, until + Names.tickets, Ticket, do_fetch, log, http, with_history, since, until ) def fetch_recent_products( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, Product], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.products, log, http, since, until, page) return fetch_changes_with_associations( - Names.products, Product, do_fetch, log, http, since, until + Names.products, Product, do_fetch, log, http, with_history, since, until ) def fetch_delayed_products( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, Product], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.products, log, http, since, until, page) return fetch_changes_with_associations( - Names.products, Product, do_fetch, log, http, since, until + Names.products, Product, do_fetch, log, http, with_history, since, until ) def fetch_recent_line_items( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, LineItem], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.line_items, log, http, since, until, page) return fetch_changes_with_associations( - Names.line_items, LineItem, do_fetch, log, http, since, until + Names.line_items, LineItem, do_fetch, log, http, with_history, since, until ) def fetch_delayed_line_items( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, with_history: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, LineItem], None]: async def do_fetch(page: PageCursor, count: int) -> tuple[Iterable[tuple[datetime, str]], PageCursor]: return await fetch_search_objects(Names.line_items, log, http, since, until, page) return fetch_changes_with_associations( - Names.line_items, LineItem, do_fetch, log, http, since, until + Names.line_items, LineItem, do_fetch, log, http, with_history, since, until ) async def list_custom_objects( @@ -1077,13 +1087,13 @@ async def _fetch_email_events( def fetch_recent_email_events( - log: Logger, http: HTTPSession, since: datetime, until: datetime | None + log: Logger, http: HTTPSession, _: bool, since: datetime, until: datetime | None ) -> AsyncGenerator[tuple[datetime, str, EmailEvent], None]: return _fetch_email_events(log, http, since + timedelta(milliseconds=1), until) def fetch_delayed_email_events( - log: Logger, http: HTTPSession, since: datetime, until: datetime + log: Logger, http: HTTPSession, _: bool, since: datetime, until: datetime ) -> AsyncGenerator[tuple[datetime, str, EmailEvent], None]: return _fetch_email_events(log, http, since, until) diff --git a/source-hubspot-native/source_hubspot_native/models.py b/source-hubspot-native/source_hubspot_native/models.py index d2f45b0933..a313213184 100644 --- a/source-hubspot-native/source_hubspot_native/models.py +++ b/source-hubspot-native/source_hubspot_native/models.py @@ -2,6 +2,7 @@ from datetime import datetime from enum import StrEnum, auto from typing import TYPE_CHECKING, Annotated, ClassVar, Generic, Literal, Self, TypeVar +from pydantic.json_schema import SkipJsonSchema from estuary_cdk.capture.common import ( AccessToken, @@ -81,6 +82,11 @@ class EndpointConfig(BaseModel): discriminator="credentials_title", title="Authentication", ) + capturePropertyHistory: bool = Field( + title="Capture Property History", + description="Include historical data for changes to properties of HubSpot objects in captured documents.", + default=False, + ) # We use ResourceState directly, without extending it. @@ -139,7 +145,7 @@ class Owner(BaseDocument, extra="allow"): class BaseCRMObject(BaseDocument, extra="forbid"): ASSOCIATED_ENTITIES: ClassVar[list[str]] - class History(BaseDocument, extra="forbid"): + class History(BaseModel, extra="forbid"): timestamp: datetime value: str sourceType: str @@ -153,7 +159,7 @@ class History(BaseDocument, extra="forbid"): archived: bool properties: dict[str, str | None] - propertiesWithHistory: dict[str, list[History]] = {} + propertiesWithHistory: SkipJsonSchema[dict[str, list[History]]] = {} class InlineAssociations(BaseModel): class Entry(BaseModel): diff --git a/source-hubspot-native/source_hubspot_native/resources.py b/source-hubspot-native/source_hubspot_native/resources.py index 6384739fcf..62e510da85 100644 --- a/source-hubspot-native/source_hubspot_native/resources.py +++ b/source-hubspot-native/source_hubspot_native/resources.py @@ -84,12 +84,18 @@ async def all_resources( # Docs reference: https://developers.hubspot.com/docs/api/crm/crm-custom-objects#retrieve-existing-custom-objects custom_object_path_components = [f"p_{n}" for n in custom_object_names] + # TODO(whb): Set this value from the endpoint configuration after all + # pre-existing tasks have had the option set to True. + # with_history = config.capturePropertyHistory + with_history = True + custom_object_resources = [ crm_object_with_associations( CustomObject, n, custom_object_path_components[index], http, + with_history, functools.partial(fetch_recent_custom_objects, custom_object_path_components[index]), functools.partial(fetch_delayed_custom_objects, custom_object_path_components[index]), ) @@ -97,13 +103,13 @@ async def all_resources( ] resources = [ - crm_object_with_associations(Company, Names.companies, Names.companies, http, fetch_recent_companies, fetch_delayed_companies), - crm_object_with_associations(Contact, Names.contacts, Names.contacts, http, fetch_recent_contacts, fetch_delayed_contacts), - crm_object_with_associations(Deal, Names.deals, Names.deals, http, fetch_recent_deals, fetch_delayed_deals), - crm_object_with_associations(Engagement, Names.engagements, Names.engagements, http, fetch_recent_engagements, fetch_delayed_engagements), - crm_object_with_associations(Ticket, Names.tickets, Names.tickets, http, fetch_recent_tickets, fetch_delayed_tickets), - crm_object_with_associations(Product, Names.products, Names.products, http, fetch_recent_products, fetch_delayed_products), - crm_object_with_associations(LineItem, Names.line_items, Names.line_items, http, fetch_recent_line_items, fetch_delayed_line_items), + crm_object_with_associations(Company, Names.companies, Names.companies, http, with_history, fetch_recent_companies, fetch_delayed_companies), + crm_object_with_associations(Contact, Names.contacts, Names.contacts, http, with_history, fetch_recent_contacts, fetch_delayed_contacts), + crm_object_with_associations(Deal, Names.deals, Names.deals, http, with_history, fetch_recent_deals, fetch_delayed_deals), + crm_object_with_associations(Engagement, Names.engagements, Names.engagements, http, with_history, fetch_recent_engagements, fetch_delayed_engagements), + crm_object_with_associations(Ticket, Names.tickets, Names.tickets, http, with_history, fetch_recent_tickets, fetch_delayed_tickets), + crm_object_with_associations(Product, Names.products, Names.products, http, with_history, fetch_recent_products, fetch_delayed_products), + crm_object_with_associations(LineItem, Names.line_items, Names.line_items, http, with_history, fetch_recent_line_items, fetch_delayed_line_items), properties(http, itertools.chain(standard_object_names, custom_object_path_components)), deal_pipelines(http), owners(http), @@ -111,7 +117,7 @@ async def all_resources( ] try: - async for _ in fetch_recent_email_events(log, http, datetime.now(tz=UTC), None): + async for _ in fetch_recent_email_events(log, http, with_history, datetime.now(tz=UTC), None): break resources.append(email_events(http)) @@ -129,6 +135,7 @@ def crm_object_with_associations( object_name: str, path_component: str, http: HTTPSession, + with_history: bool, fetch_recent: FetchRecentFn, fetch_delayed: FetchDelayedFn, ) -> Resource: @@ -151,8 +158,9 @@ def open( fetch_recent, fetch_delayed, http, + with_history, ), - fetch_page=functools.partial(fetch_page_with_associations, cls, http, path_component), + fetch_page=functools.partial(fetch_page_with_associations, cls, http, with_history, path_component), ) started_at = datetime.now(tz=UTC) @@ -296,6 +304,7 @@ def open( fetch_recent_email_events, fetch_delayed_email_events, http, + True, # email events do not include property history ), fetch_page=functools.partial(fetch_email_events_page, http), ) diff --git a/source-hubspot-native/tests/snapshots/snapshots__discover__stdout.json b/source-hubspot-native/tests/snapshots/snapshots__discover__stdout.json index 5bfca19176..ae600999d2 100644 --- a/source-hubspot-native/tests/snapshots/snapshots__discover__stdout.json +++ b/source-hubspot-native/tests/snapshots/snapshots__discover__stdout.json @@ -6,79 +6,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -149,17 +76,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -205,79 +121,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -348,17 +191,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -396,79 +228,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -539,17 +298,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -603,79 +351,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -746,17 +421,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -794,79 +458,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -937,17 +528,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -1001,79 +581,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -1144,17 +651,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, @@ -1184,79 +680,6 @@ }, "documentSchema": { "$defs": { - "History": { - "additionalProperties": false, - "properties": { - "_meta": { - "allOf": [ - { - "$ref": "#/$defs/Meta" - } - ], - "default": { - "op": "u", - "row_id": -1 - }, - "description": "Document metadata" - }, - "timestamp": { - "format": "date-time", - "title": "Timestamp", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - }, - "sourceType": { - "title": "Sourcetype", - "type": "string" - }, - "sourceId": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourceid" - }, - "sourceLabel": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Sourcelabel" - }, - "updatedByUserId": { - "anyOf": [ - { - "type": "integer" - }, - { - "type": "null" - } - ], - "default": null, - "title": "Updatedbyuserid" - } - }, - "required": [ - "timestamp", - "value", - "sourceType" - ], - "title": "History", - "type": "object" - }, "Meta": { "properties": { "op": { @@ -1327,17 +750,6 @@ }, "title": "Properties" }, - "propertiesWithHistory": { - "additionalProperties": { - "items": { - "$ref": "#/$defs/History" - }, - "type": "array" - }, - "default": {}, - "title": "Propertieswithhistory", - "type": "object" - }, "associations": { "additionalProperties": false, "default": {}, diff --git a/source-hubspot-native/tests/snapshots/snapshots__spec__stdout.json b/source-hubspot-native/tests/snapshots/snapshots__spec__stdout.json index c05975c540..b0b92eea3f 100644 --- a/source-hubspot-native/tests/snapshots/snapshots__spec__stdout.json +++ b/source-hubspot-native/tests/snapshots/snapshots__spec__stdout.json @@ -75,6 +75,12 @@ } ], "title": "Authentication" + }, + "capturePropertyHistory": { + "default": false, + "description": "Include historical data for changes to properties of HubSpot objects in captured documents.", + "title": "Capture Property History", + "type": "boolean" } }, "required": [