From 15cc440cf7320f2d958ee121f0d456a2063b168b Mon Sep 17 00:00:00 2001 From: Owen Kephart Date: Wed, 3 Jan 2024 10:11:17 -0500 Subject: [PATCH] Return tree instead of recursive resolver --- .../src/graphql/possibleTypes.generated.json | 687 +----------------- .../ui-core/src/graphql/schema.graphql | 84 ++- .../packages/ui-core/src/graphql/types.ts | 176 +++-- .../fetch_asset_condition_evaluations.py | 8 +- .../schema/asset_condition_evaluations.py | 154 ++-- .../dagster_graphql/schema/roots/query.py | 4 +- .../test_asset_condition_evaluations.py | 274 +++---- 7 files changed, 416 insertions(+), 971 deletions(-) diff --git a/js_modules/dagster-ui/packages/ui-core/src/graphql/possibleTypes.generated.json b/js_modules/dagster-ui/packages/ui-core/src/graphql/possibleTypes.generated.json index b52ff13572230..2ed9f866f8b2f 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graphql/possibleTypes.generated.json +++ b/js_modules/dagster-ui/packages/ui-core/src/graphql/possibleTypes.generated.json @@ -1,686 +1 @@ -{ - "DisplayableEvent": [ - "EngineEvent", - "ExecutionStepOutputEvent", - "ExpectationResult", - "FailureMetadata", - "HandledOutputEvent", - "LoadedInputEvent", - "ObjectStoreOperationResult", - "ResourceInitFailureEvent", - "ResourceInitStartedEvent", - "ResourceInitSuccessEvent", - "StepWorkerStartedEvent", - "StepWorkerStartingEvent", - "MaterializationEvent", - "ObservationEvent", - "TypeCheck" - ], - "MarkerEvent": [ - "EngineEvent", - "ResourceInitFailureEvent", - "ResourceInitStartedEvent", - "ResourceInitSuccessEvent", - "StepWorkerStartedEvent", - "StepWorkerStartingEvent" - ], - "ErrorEvent": [ - "EngineEvent", - "ExecutionStepFailureEvent", - "ExecutionStepUpForRetryEvent", - "HookErroredEvent", - "RunFailureEvent", - "ResourceInitFailureEvent" - ], - "MessageEvent": [ - "EngineEvent", - "ExecutionStepFailureEvent", - "ExecutionStepInputEvent", - "ExecutionStepOutputEvent", - "ExecutionStepRestartEvent", - "ExecutionStepSkippedEvent", - "ExecutionStepStartEvent", - "ExecutionStepSuccessEvent", - "ExecutionStepUpForRetryEvent", - "HandledOutputEvent", - "HookCompletedEvent", - "HookErroredEvent", - "HookSkippedEvent", - "LoadedInputEvent", - "LogMessageEvent", - "ObjectStoreOperationEvent", - "RunCanceledEvent", - "RunCancelingEvent", - "RunDequeuedEvent", - "RunEnqueuedEvent", - "RunFailureEvent", - "ResourceInitFailureEvent", - "ResourceInitStartedEvent", - "ResourceInitSuccessEvent", - "RunStartEvent", - "RunStartingEvent", - "RunSuccessEvent", - "StepExpectationResultEvent", - "StepWorkerStartedEvent", - "StepWorkerStartingEvent", - "MaterializationEvent", - "ObservationEvent", - "AssetMaterializationPlannedEvent", - "LogsCapturedEvent", - "AlertStartEvent", - "AlertSuccessEvent", - "AlertFailureEvent", - "AssetCheckEvaluationPlannedEvent", - "AssetCheckEvaluationEvent" - ], - "RunEvent": [ - "RunCanceledEvent", - "RunCancelingEvent", - "RunDequeuedEvent", - "RunEnqueuedEvent", - "RunFailureEvent", - "RunStartEvent", - "RunStartingEvent", - "RunSuccessEvent", - "AssetMaterializationPlannedEvent", - "AlertStartEvent", - "AlertSuccessEvent", - "AlertFailureEvent" - ], - "PipelineRunStepStats": [ - "RunStepStats" - ], - "StepEvent": [ - "EngineEvent", - "ExecutionStepFailureEvent", - "ExecutionStepInputEvent", - "ExecutionStepOutputEvent", - "ExecutionStepRestartEvent", - "ExecutionStepSkippedEvent", - "ExecutionStepStartEvent", - "ExecutionStepSuccessEvent", - "ExecutionStepUpForRetryEvent", - "HandledOutputEvent", - "HookCompletedEvent", - "HookErroredEvent", - "HookSkippedEvent", - "LoadedInputEvent", - "ObjectStoreOperationEvent", - "ResourceInitFailureEvent", - "ResourceInitStartedEvent", - "ResourceInitSuccessEvent", - "StepExpectationResultEvent", - "StepWorkerStartedEvent", - "StepWorkerStartingEvent", - "MaterializationEvent", - "ObservationEvent", - "AssetCheckEvaluationPlannedEvent", - "AssetCheckEvaluationEvent" - ], - "AssetPartitionStatuses": [ - "DefaultPartitionStatuses", - "MultiPartitionStatuses", - "TimePartitionStatuses" - ], - "PartitionStatus1D": [ - "TimePartitionStatuses", - "DefaultPartitionStatuses" - ], - "AssetChecksOrError": [ - "AssetChecks", - "AssetCheckNeedsMigrationError", - "AssetCheckNeedsUserCodeUpgrade", - "AssetCheckNeedsAgentUpgradeError" - ], - "Instigator": [ - "Schedule", - "Sensor" - ], - "EvaluationStackEntry": [ - "EvaluationStackListItemEntry", - "EvaluationStackPathEntry", - "EvaluationStackMapKeyEntry", - "EvaluationStackMapValueEntry" - ], - "IPipelineSnapshot": [ - "Pipeline", - "PipelineSnapshot", - "Job" - ], - "PipelineConfigValidationError": [ - "FieldNotDefinedConfigError", - "FieldsNotDefinedConfigError", - "MissingFieldConfigError", - "MissingFieldsConfigError", - "RuntimeMismatchConfigError", - "SelectorTypeConfigError" - ], - "PipelineConfigValidationInvalid": [ - "RunConfigValidationInvalid" - ], - "PipelineConfigValidationResult": [ - "InvalidSubsetError", - "PipelineConfigValidationValid", - "RunConfigValidationInvalid", - "PipelineNotFoundError", - "PythonError" - ], - "PipelineReference": [ - "PipelineSnapshot", - "UnknownPipeline" - ], - "PipelineRun": [ - "Run" - ], - "DagsterRunEvent": [ - "ExecutionStepFailureEvent", - "ExecutionStepInputEvent", - "ExecutionStepOutputEvent", - "ExecutionStepSkippedEvent", - "ExecutionStepStartEvent", - "ExecutionStepSuccessEvent", - "ExecutionStepUpForRetryEvent", - "ExecutionStepRestartEvent", - "LogMessageEvent", - "ResourceInitFailureEvent", - "ResourceInitStartedEvent", - "ResourceInitSuccessEvent", - "RunFailureEvent", - "RunStartEvent", - "RunEnqueuedEvent", - "RunDequeuedEvent", - "RunStartingEvent", - "RunCancelingEvent", - "RunCanceledEvent", - "RunSuccessEvent", - "StepWorkerStartedEvent", - "StepWorkerStartingEvent", - "HandledOutputEvent", - "LoadedInputEvent", - "LogsCapturedEvent", - "ObjectStoreOperationEvent", - "StepExpectationResultEvent", - "MaterializationEvent", - "ObservationEvent", - "EngineEvent", - "HookCompletedEvent", - "HookSkippedEvent", - "HookErroredEvent", - "AlertStartEvent", - "AlertSuccessEvent", - "AlertFailureEvent", - "AssetMaterializationPlannedEvent", - "AssetCheckEvaluationPlannedEvent", - "AssetCheckEvaluationEvent" - ], - "PipelineRunLogsSubscriptionPayload": [ - "PipelineRunLogsSubscriptionSuccess", - "PipelineRunLogsSubscriptionFailure" - ], - "RunOrError": [ - "Run", - "RunNotFoundError", - "PythonError" - ], - "PipelineRunStatsSnapshot": [ - "RunStatsSnapshot" - ], - "RunStatsSnapshotOrError": [ - "RunStatsSnapshot", - "PythonError" - ], - "PipelineSnapshotOrError": [ - "PipelineNotFoundError", - "PipelineSnapshot", - "PipelineSnapshotNotFoundError", - "PythonError" - ], - "AssetOrError": [ - "Asset", - "AssetNotFoundError" - ], - "AssetsOrError": [ - "AssetConnection", - "PythonError" - ], - "DeletePipelineRunResult": [ - "DeletePipelineRunSuccess", - "UnauthorizedError", - "PythonError", - "RunNotFoundError" - ], - "ExecutionPlanOrError": [ - "ExecutionPlan", - "RunConfigValidationInvalid", - "PipelineNotFoundError", - "InvalidSubsetError", - "PythonError" - ], - "PipelineOrError": [ - "Pipeline", - "PipelineNotFoundError", - "InvalidSubsetError", - "PythonError" - ], - "ReloadRepositoryLocationMutationResult": [ - "WorkspaceLocationEntry", - "ReloadNotSupported", - "RepositoryLocationNotFound", - "UnauthorizedError", - "PythonError" - ], - "RepositoryLocationOrLoadError": [ - "RepositoryLocation", - "PythonError" - ], - "ReloadWorkspaceMutationResult": [ - "Workspace", - "UnauthorizedError", - "PythonError" - ], - "ShutdownRepositoryLocationMutationResult": [ - "ShutdownRepositoryLocationSuccess", - "RepositoryLocationNotFound", - "UnauthorizedError", - "PythonError" - ], - "TerminatePipelineExecutionFailure": [ - "TerminateRunFailure" - ], - "TerminatePipelineExecutionSuccess": [ - "TerminateRunSuccess" - ], - "TerminateRunResult": [ - "TerminateRunSuccess", - "TerminateRunFailure", - "RunNotFoundError", - "UnauthorizedError", - "PythonError" - ], - "ScheduleMutationResult": [ - "PythonError", - "UnauthorizedError", - "ScheduleStateResult" - ], - "ScheduleOrError": [ - "Schedule", - "ScheduleNotFoundError", - "PythonError" - ], - "SchedulerOrError": [ - "Scheduler", - "SchedulerNotDefinedError", - "PythonError" - ], - "SchedulesOrError": [ - "Schedules", - "RepositoryNotFoundError", - "PythonError" - ], - "ScheduleTickSpecificData": [ - "ScheduleTickSuccessData", - "ScheduleTickFailureData" - ], - "LaunchBackfillResult": [ - "LaunchBackfillSuccess", - "PartitionSetNotFoundError", - "InvalidStepError", - "InvalidOutputError", - "RunConfigValidationInvalid", - "PipelineNotFoundError", - "RunConflict", - "UnauthorizedError", - "PythonError", - "InvalidSubsetError", - "PresetNotFoundError", - "ConflictingExecutionParamsError", - "NoModeProvidedError" - ], - "ConfigTypeOrError": [ - "EnumConfigType", - "CompositeConfigType", - "RegularConfigType", - "PipelineNotFoundError", - "ConfigTypeNotFoundError", - "PythonError" - ], - "ConfigType": [ - "ArrayConfigType", - "CompositeConfigType", - "EnumConfigType", - "NullableConfigType", - "RegularConfigType", - "ScalarUnionConfigType", - "MapConfigType" - ], - "WrappingConfigType": [ - "ArrayConfigType", - "NullableConfigType" - ], - "DagsterType": [ - "ListDagsterType", - "NullableDagsterType", - "RegularDagsterType" - ], - "DagsterTypeOrError": [ - "RegularDagsterType", - "PipelineNotFoundError", - "DagsterTypeNotFoundError", - "PythonError" - ], - "WrappingDagsterType": [ - "ListDagsterType", - "NullableDagsterType" - ], - "Error": [ - "AssetCheckNeedsMigrationError", - "AssetCheckNeedsUserCodeUpgrade", - "AssetCheckNeedsAgentUpgradeError", - "AssetNotFoundError", - "ConflictingExecutionParamsError", - "ConfigTypeNotFoundError", - "DagsterTypeNotFoundError", - "InvalidPipelineRunsFilterError", - "InvalidSubsetError", - "ModeNotFoundError", - "NoModeProvidedError", - "PartitionSetNotFoundError", - "PipelineNotFoundError", - "RunConflict", - "PipelineSnapshotNotFoundError", - "PresetNotFoundError", - "PythonError", - "ErrorChainLink", - "UnauthorizedError", - "ReloadNotSupported", - "RepositoryLocationNotFound", - "RepositoryNotFoundError", - "ResourceNotFoundError", - "RunGroupNotFoundError", - "RunNotFoundError", - "ScheduleNotFoundError", - "SchedulerNotDefinedError", - "SensorNotFoundError", - "DuplicateDynamicPartitionError", - "InstigationStateNotFoundError", - "SolidStepStatusUnavailableError", - "GraphNotFoundError", - "BackfillNotFoundError", - "PartitionSubsetDeserializationError", - "AutoMaterializeAssetEvaluationNeedsMigrationError" - ], - "PipelineRunConflict": [ - "RunConflict" - ], - "PipelineRunNotFoundError": [ - "RunNotFoundError" - ], - "RepositoriesOrError": [ - "RepositoryConnection", - "PythonError" - ], - "RepositoryOrError": [ - "PythonError", - "Repository", - "RepositoryNotFoundError" - ], - "InstigationTypeSpecificData": [ - "SensorData", - "ScheduleData" - ], - "InstigationStateOrError": [ - "InstigationState", - "InstigationStateNotFoundError", - "PythonError" - ], - "InstigationStatesOrError": [ - "InstigationStates", - "PythonError" - ], - "MetadataEntry": [ - "TableSchemaMetadataEntry", - "TableMetadataEntry", - "FloatMetadataEntry", - "IntMetadataEntry", - "JsonMetadataEntry", - "BoolMetadataEntry", - "MarkdownMetadataEntry", - "PathMetadataEntry", - "NotebookMetadataEntry", - "PythonArtifactMetadataEntry", - "TextMetadataEntry", - "UrlMetadataEntry", - "PipelineRunMetadataEntry", - "AssetMetadataEntry", - "JobMetadataEntry", - "NullMetadataEntry" - ], - "PartitionRunConfigOrError": [ - "PartitionRunConfig", - "PythonError" - ], - "AssetBackfillStatus": [ - "AssetPartitionsStatusCounts", - "UnpartitionedAssetStatus" - ], - "PartitionSetOrError": [ - "PartitionSet", - "PartitionSetNotFoundError", - "PythonError" - ], - "PartitionSetsOrError": [ - "PartitionSets", - "PipelineNotFoundError", - "PythonError" - ], - "PartitionsOrError": [ - "Partitions", - "PythonError" - ], - "PartitionStatusesOrError": [ - "PartitionStatuses", - "PythonError" - ], - "PartitionTagsOrError": [ - "PartitionTags", - "PythonError" - ], - "RunConfigSchemaOrError": [ - "RunConfigSchema", - "PipelineNotFoundError", - "InvalidSubsetError", - "ModeNotFoundError", - "PythonError" - ], - "LaunchRunResult": [ - "LaunchRunSuccess", - "InvalidStepError", - "InvalidOutputError", - "RunConfigValidationInvalid", - "PipelineNotFoundError", - "RunConflict", - "UnauthorizedError", - "PythonError", - "InvalidSubsetError", - "PresetNotFoundError", - "ConflictingExecutionParamsError", - "NoModeProvidedError" - ], - "LaunchRunReexecutionResult": [ - "LaunchRunSuccess", - "InvalidStepError", - "InvalidOutputError", - "RunConfigValidationInvalid", - "PipelineNotFoundError", - "RunConflict", - "UnauthorizedError", - "PythonError", - "InvalidSubsetError", - "PresetNotFoundError", - "ConflictingExecutionParamsError", - "NoModeProvidedError" - ], - "LaunchPipelineRunSuccess": [ - "LaunchRunSuccess" - ], - "RunsOrError": [ - "Runs", - "InvalidPipelineRunsFilterError", - "PythonError" - ], - "PipelineRuns": [ - "Runs" - ], - "RunGroupOrError": [ - "RunGroup", - "RunGroupNotFoundError", - "PythonError" - ], - "SensorOrError": [ - "Sensor", - "SensorNotFoundError", - "UnauthorizedError", - "PythonError" - ], - "SensorsOrError": [ - "Sensors", - "RepositoryNotFoundError", - "PythonError" - ], - "StopSensorMutationResultOrError": [ - "StopSensorMutationResult", - "UnauthorizedError", - "PythonError" - ], - "ISolidDefinition": [ - "CompositeSolidDefinition", - "SolidDefinition" - ], - "SolidContainer": [ - "Pipeline", - "PipelineSnapshot", - "Job", - "CompositeSolidDefinition", - "Graph" - ], - "SolidStepStatsOrError": [ - "SolidStepStatsConnection", - "SolidStepStatusUnavailableError" - ], - "WorkspaceOrError": [ - "Workspace", - "PythonError" - ], - "WorkspaceLocationStatusEntriesOrError": [ - "WorkspaceLocationStatusEntries", - "PythonError" - ], - "GraphOrError": [ - "Graph", - "GraphNotFoundError", - "PythonError" - ], - "ResourceDetailsOrError": [ - "ResourceDetails", - "ResourceNotFoundError", - "PythonError" - ], - "ResourcesOrError": [ - "ResourceDetailsList", - "RepositoryNotFoundError", - "PythonError" - ], - "EnvVarWithConsumersOrError": [ - "EnvVarWithConsumersList", - "PythonError" - ], - "RunTagKeysOrError": [ - "PythonError", - "RunTagKeys" - ], - "RunTagsOrError": [ - "PythonError", - "RunTags" - ], - "RunIdsOrError": [ - "RunIds", - "InvalidPipelineRunsFilterError", - "PythonError" - ], - "AssetNodeOrError": [ - "AssetNode", - "AssetNotFoundError" - ], - "PartitionBackfillOrError": [ - "PartitionBackfill", - "BackfillNotFoundError", - "PythonError" - ], - "PartitionBackfillsOrError": [ - "PartitionBackfills", - "PythonError" - ], - "EventConnectionOrError": [ - "EventConnection", - "RunNotFoundError", - "PythonError" - ], - "AutoMaterializeAssetEvaluationRecordsOrError": [ - "AutoMaterializeAssetEvaluationRecords", - "AutoMaterializeAssetEvaluationNeedsMigrationError" - ], - "PartitionKeysOrError": [ - "PartitionKeys", - "PartitionSubsetDeserializationError" - ], - "AutoMaterializeRuleEvaluationData": [ - "TextRuleEvaluationData", - "ParentMaterializedRuleEvaluationData", - "WaitingOnKeysRuleEvaluationData" - ], - "SensorDryRunResult": [ - "PythonError", - "SensorNotFoundError", - "DryRunInstigationTick" - ], - "ScheduleDryRunResult": [ - "DryRunInstigationTick", - "PythonError", - "ScheduleNotFoundError" - ], - "TerminateRunsResultOrError": [ - "TerminateRunsResult", - "PythonError" - ], - "AssetWipeMutationResult": [ - "AssetNotFoundError", - "UnauthorizedError", - "PythonError", - "AssetWipeSuccess" - ], - "ReportRunlessAssetEventsResult": [ - "UnauthorizedError", - "PythonError", - "ReportRunlessAssetEventsSuccess" - ], - "ResumeBackfillResult": [ - "ResumeBackfillSuccess", - "UnauthorizedError", - "PythonError" - ], - "CancelBackfillResult": [ - "CancelBackfillSuccess", - "UnauthorizedError", - "PythonError" - ], - "LogTelemetryMutationResult": [ - "LogTelemetrySuccess", - "PythonError" - ], - "AddDynamicPartitionResult": [ - "AddDynamicPartitionSuccess", - "UnauthorizedError", - "PythonError", - "DuplicateDynamicPartitionError" - ] -} \ No newline at end of file +{"DisplayableEvent":["EngineEvent","ExecutionStepOutputEvent","ExpectationResult","FailureMetadata","HandledOutputEvent","LoadedInputEvent","ObjectStoreOperationResult","ResourceInitFailureEvent","ResourceInitStartedEvent","ResourceInitSuccessEvent","StepWorkerStartedEvent","StepWorkerStartingEvent","MaterializationEvent","ObservationEvent","TypeCheck"],"MarkerEvent":["EngineEvent","ResourceInitFailureEvent","ResourceInitStartedEvent","ResourceInitSuccessEvent","StepWorkerStartedEvent","StepWorkerStartingEvent"],"ErrorEvent":["EngineEvent","ExecutionStepFailureEvent","ExecutionStepUpForRetryEvent","HookErroredEvent","RunFailureEvent","ResourceInitFailureEvent"],"MessageEvent":["EngineEvent","ExecutionStepFailureEvent","ExecutionStepInputEvent","ExecutionStepOutputEvent","ExecutionStepRestartEvent","ExecutionStepSkippedEvent","ExecutionStepStartEvent","ExecutionStepSuccessEvent","ExecutionStepUpForRetryEvent","HandledOutputEvent","HookCompletedEvent","HookErroredEvent","HookSkippedEvent","LoadedInputEvent","LogMessageEvent","ObjectStoreOperationEvent","RunCanceledEvent","RunCancelingEvent","RunDequeuedEvent","RunEnqueuedEvent","RunFailureEvent","ResourceInitFailureEvent","ResourceInitStartedEvent","ResourceInitSuccessEvent","RunStartEvent","RunStartingEvent","RunSuccessEvent","StepExpectationResultEvent","StepWorkerStartedEvent","StepWorkerStartingEvent","MaterializationEvent","ObservationEvent","AssetMaterializationPlannedEvent","LogsCapturedEvent","AlertStartEvent","AlertSuccessEvent","AlertFailureEvent","AssetCheckEvaluationPlannedEvent","AssetCheckEvaluationEvent"],"RunEvent":["RunCanceledEvent","RunCancelingEvent","RunDequeuedEvent","RunEnqueuedEvent","RunFailureEvent","RunStartEvent","RunStartingEvent","RunSuccessEvent","AssetMaterializationPlannedEvent","AlertStartEvent","AlertSuccessEvent","AlertFailureEvent"],"PipelineRunStepStats":["RunStepStats"],"StepEvent":["EngineEvent","ExecutionStepFailureEvent","ExecutionStepInputEvent","ExecutionStepOutputEvent","ExecutionStepRestartEvent","ExecutionStepSkippedEvent","ExecutionStepStartEvent","ExecutionStepSuccessEvent","ExecutionStepUpForRetryEvent","HandledOutputEvent","HookCompletedEvent","HookErroredEvent","HookSkippedEvent","LoadedInputEvent","ObjectStoreOperationEvent","ResourceInitFailureEvent","ResourceInitStartedEvent","ResourceInitSuccessEvent","StepExpectationResultEvent","StepWorkerStartedEvent","StepWorkerStartingEvent","MaterializationEvent","ObservationEvent","AssetCheckEvaluationPlannedEvent","AssetCheckEvaluationEvent"],"AssetPartitionStatuses":["DefaultPartitionStatuses","MultiPartitionStatuses","TimePartitionStatuses"],"PartitionStatus1D":["TimePartitionStatuses","DefaultPartitionStatuses"],"AssetChecksOrError":["AssetChecks","AssetCheckNeedsMigrationError","AssetCheckNeedsUserCodeUpgrade","AssetCheckNeedsAgentUpgradeError"],"Instigator":["Schedule","Sensor"],"EvaluationStackEntry":["EvaluationStackListItemEntry","EvaluationStackPathEntry","EvaluationStackMapKeyEntry","EvaluationStackMapValueEntry"],"IPipelineSnapshot":["Pipeline","PipelineSnapshot","Job"],"PipelineConfigValidationError":["FieldNotDefinedConfigError","FieldsNotDefinedConfigError","MissingFieldConfigError","MissingFieldsConfigError","RuntimeMismatchConfigError","SelectorTypeConfigError"],"PipelineConfigValidationInvalid":["RunConfigValidationInvalid"],"PipelineConfigValidationResult":["InvalidSubsetError","PipelineConfigValidationValid","RunConfigValidationInvalid","PipelineNotFoundError","PythonError"],"PipelineReference":["PipelineSnapshot","UnknownPipeline"],"PipelineRun":["Run"],"DagsterRunEvent":["ExecutionStepFailureEvent","ExecutionStepInputEvent","ExecutionStepOutputEvent","ExecutionStepSkippedEvent","ExecutionStepStartEvent","ExecutionStepSuccessEvent","ExecutionStepUpForRetryEvent","ExecutionStepRestartEvent","LogMessageEvent","ResourceInitFailureEvent","ResourceInitStartedEvent","ResourceInitSuccessEvent","RunFailureEvent","RunStartEvent","RunEnqueuedEvent","RunDequeuedEvent","RunStartingEvent","RunCancelingEvent","RunCanceledEvent","RunSuccessEvent","StepWorkerStartedEvent","StepWorkerStartingEvent","HandledOutputEvent","LoadedInputEvent","LogsCapturedEvent","ObjectStoreOperationEvent","StepExpectationResultEvent","MaterializationEvent","ObservationEvent","EngineEvent","HookCompletedEvent","HookSkippedEvent","HookErroredEvent","AlertStartEvent","AlertSuccessEvent","AlertFailureEvent","AssetMaterializationPlannedEvent","AssetCheckEvaluationPlannedEvent","AssetCheckEvaluationEvent"],"PipelineRunLogsSubscriptionPayload":["PipelineRunLogsSubscriptionSuccess","PipelineRunLogsSubscriptionFailure"],"RunOrError":["Run","RunNotFoundError","PythonError"],"PipelineRunStatsSnapshot":["RunStatsSnapshot"],"RunStatsSnapshotOrError":["RunStatsSnapshot","PythonError"],"PipelineSnapshotOrError":["PipelineNotFoundError","PipelineSnapshot","PipelineSnapshotNotFoundError","PythonError"],"AssetOrError":["Asset","AssetNotFoundError"],"AssetsOrError":["AssetConnection","PythonError"],"DeletePipelineRunResult":["DeletePipelineRunSuccess","UnauthorizedError","PythonError","RunNotFoundError"],"ExecutionPlanOrError":["ExecutionPlan","RunConfigValidationInvalid","PipelineNotFoundError","InvalidSubsetError","PythonError"],"PipelineOrError":["Pipeline","PipelineNotFoundError","InvalidSubsetError","PythonError"],"ReloadRepositoryLocationMutationResult":["WorkspaceLocationEntry","ReloadNotSupported","RepositoryLocationNotFound","UnauthorizedError","PythonError"],"RepositoryLocationOrLoadError":["RepositoryLocation","PythonError"],"ReloadWorkspaceMutationResult":["Workspace","UnauthorizedError","PythonError"],"ShutdownRepositoryLocationMutationResult":["ShutdownRepositoryLocationSuccess","RepositoryLocationNotFound","UnauthorizedError","PythonError"],"TerminatePipelineExecutionFailure":["TerminateRunFailure"],"TerminatePipelineExecutionSuccess":["TerminateRunSuccess"],"TerminateRunResult":["TerminateRunSuccess","TerminateRunFailure","RunNotFoundError","UnauthorizedError","PythonError"],"ScheduleMutationResult":["PythonError","UnauthorizedError","ScheduleStateResult"],"ScheduleOrError":["Schedule","ScheduleNotFoundError","PythonError"],"SchedulerOrError":["Scheduler","SchedulerNotDefinedError","PythonError"],"SchedulesOrError":["Schedules","RepositoryNotFoundError","PythonError"],"ScheduleTickSpecificData":["ScheduleTickSuccessData","ScheduleTickFailureData"],"LaunchBackfillResult":["LaunchBackfillSuccess","PartitionSetNotFoundError","InvalidStepError","InvalidOutputError","RunConfigValidationInvalid","PipelineNotFoundError","RunConflict","UnauthorizedError","PythonError","InvalidSubsetError","PresetNotFoundError","ConflictingExecutionParamsError","NoModeProvidedError"],"ConfigTypeOrError":["EnumConfigType","CompositeConfigType","RegularConfigType","PipelineNotFoundError","ConfigTypeNotFoundError","PythonError"],"ConfigType":["ArrayConfigType","CompositeConfigType","EnumConfigType","NullableConfigType","RegularConfigType","ScalarUnionConfigType","MapConfigType"],"WrappingConfigType":["ArrayConfigType","NullableConfigType"],"DagsterType":["ListDagsterType","NullableDagsterType","RegularDagsterType"],"DagsterTypeOrError":["RegularDagsterType","PipelineNotFoundError","DagsterTypeNotFoundError","PythonError"],"WrappingDagsterType":["ListDagsterType","NullableDagsterType"],"Error":["AssetCheckNeedsMigrationError","AssetCheckNeedsUserCodeUpgrade","AssetCheckNeedsAgentUpgradeError","AssetNotFoundError","ConflictingExecutionParamsError","ConfigTypeNotFoundError","DagsterTypeNotFoundError","InvalidPipelineRunsFilterError","InvalidSubsetError","ModeNotFoundError","NoModeProvidedError","PartitionSetNotFoundError","PipelineNotFoundError","RunConflict","PipelineSnapshotNotFoundError","PresetNotFoundError","PythonError","ErrorChainLink","UnauthorizedError","ReloadNotSupported","RepositoryLocationNotFound","RepositoryNotFoundError","ResourceNotFoundError","RunGroupNotFoundError","RunNotFoundError","ScheduleNotFoundError","SchedulerNotDefinedError","SensorNotFoundError","DuplicateDynamicPartitionError","InstigationStateNotFoundError","SolidStepStatusUnavailableError","GraphNotFoundError","BackfillNotFoundError","PartitionSubsetDeserializationError","AutoMaterializeAssetEvaluationNeedsMigrationError"],"PipelineRunConflict":["RunConflict"],"PipelineRunNotFoundError":["RunNotFoundError"],"RepositoriesOrError":["RepositoryConnection","PythonError"],"RepositoryOrError":["PythonError","Repository","RepositoryNotFoundError"],"InstigationTypeSpecificData":["SensorData","ScheduleData"],"InstigationStateOrError":["InstigationState","InstigationStateNotFoundError","PythonError"],"InstigationStatesOrError":["InstigationStates","PythonError"],"MetadataEntry":["TableSchemaMetadataEntry","TableMetadataEntry","FloatMetadataEntry","IntMetadataEntry","JsonMetadataEntry","BoolMetadataEntry","MarkdownMetadataEntry","PathMetadataEntry","NotebookMetadataEntry","PythonArtifactMetadataEntry","TextMetadataEntry","UrlMetadataEntry","PipelineRunMetadataEntry","AssetMetadataEntry","JobMetadataEntry","NullMetadataEntry"],"PartitionRunConfigOrError":["PartitionRunConfig","PythonError"],"AssetBackfillStatus":["AssetPartitionsStatusCounts","UnpartitionedAssetStatus"],"PartitionSetOrError":["PartitionSet","PartitionSetNotFoundError","PythonError"],"PartitionSetsOrError":["PartitionSets","PipelineNotFoundError","PythonError"],"PartitionsOrError":["Partitions","PythonError"],"PartitionStatusesOrError":["PartitionStatuses","PythonError"],"PartitionTagsOrError":["PartitionTags","PythonError"],"RunConfigSchemaOrError":["RunConfigSchema","PipelineNotFoundError","InvalidSubsetError","ModeNotFoundError","PythonError"],"LaunchRunResult":["LaunchRunSuccess","InvalidStepError","InvalidOutputError","RunConfigValidationInvalid","PipelineNotFoundError","RunConflict","UnauthorizedError","PythonError","InvalidSubsetError","PresetNotFoundError","ConflictingExecutionParamsError","NoModeProvidedError"],"LaunchRunReexecutionResult":["LaunchRunSuccess","InvalidStepError","InvalidOutputError","RunConfigValidationInvalid","PipelineNotFoundError","RunConflict","UnauthorizedError","PythonError","InvalidSubsetError","PresetNotFoundError","ConflictingExecutionParamsError","NoModeProvidedError"],"LaunchPipelineRunSuccess":["LaunchRunSuccess"],"RunsOrError":["Runs","InvalidPipelineRunsFilterError","PythonError"],"PipelineRuns":["Runs"],"RunGroupOrError":["RunGroup","RunGroupNotFoundError","PythonError"],"SensorOrError":["Sensor","SensorNotFoundError","UnauthorizedError","PythonError"],"SensorsOrError":["Sensors","RepositoryNotFoundError","PythonError"],"StopSensorMutationResultOrError":["StopSensorMutationResult","UnauthorizedError","PythonError"],"ISolidDefinition":["CompositeSolidDefinition","SolidDefinition"],"SolidContainer":["Pipeline","PipelineSnapshot","Job","CompositeSolidDefinition","Graph"],"SolidStepStatsOrError":["SolidStepStatsConnection","SolidStepStatusUnavailableError"],"WorkspaceOrError":["Workspace","PythonError"],"WorkspaceLocationStatusEntriesOrError":["WorkspaceLocationStatusEntries","PythonError"],"GraphOrError":["Graph","GraphNotFoundError","PythonError"],"ResourceDetailsOrError":["ResourceDetails","ResourceNotFoundError","PythonError"],"ResourcesOrError":["ResourceDetailsList","RepositoryNotFoundError","PythonError"],"EnvVarWithConsumersOrError":["EnvVarWithConsumersList","PythonError"],"RunTagKeysOrError":["PythonError","RunTagKeys"],"RunTagsOrError":["PythonError","RunTags"],"RunIdsOrError":["RunIds","InvalidPipelineRunsFilterError","PythonError"],"AssetNodeOrError":["AssetNode","AssetNotFoundError"],"PartitionBackfillOrError":["PartitionBackfill","BackfillNotFoundError","PythonError"],"PartitionBackfillsOrError":["PartitionBackfills","PythonError"],"EventConnectionOrError":["EventConnection","RunNotFoundError","PythonError"],"AutoMaterializeAssetEvaluationRecordsOrError":["AutoMaterializeAssetEvaluationRecords","AutoMaterializeAssetEvaluationNeedsMigrationError"],"PartitionKeysOrError":["PartitionKeys","PartitionSubsetDeserializationError"],"AutoMaterializeRuleEvaluationData":["TextRuleEvaluationData","ParentMaterializedRuleEvaluationData","WaitingOnKeysRuleEvaluationData"],"AssetConditionEvaluationNode":["UnpartitionedAssetConditionEvaluationNode","PartitionedAssetConditionEvaluationNode","SpecificPartitionAssetConditionEvaluationNode"],"AssetConditionEvaluationRecordsOrError":["AssetConditionEvaluationRecords","AutoMaterializeAssetEvaluationNeedsMigrationError"],"SensorDryRunResult":["PythonError","SensorNotFoundError","DryRunInstigationTick"],"ScheduleDryRunResult":["DryRunInstigationTick","PythonError","ScheduleNotFoundError"],"TerminateRunsResultOrError":["TerminateRunsResult","PythonError"],"AssetWipeMutationResult":["AssetNotFoundError","UnauthorizedError","PythonError","AssetWipeSuccess"],"ReportRunlessAssetEventsResult":["UnauthorizedError","PythonError","ReportRunlessAssetEventsSuccess"],"ResumeBackfillResult":["ResumeBackfillSuccess","UnauthorizedError","PythonError"],"CancelBackfillResult":["CancelBackfillSuccess","UnauthorizedError","PythonError"],"LogTelemetryMutationResult":["LogTelemetrySuccess","PythonError"],"AddDynamicPartitionResult":["AddDynamicPartitionSuccess","UnauthorizedError","PythonError","DuplicateDynamicPartitionError"]} \ No newline at end of file diff --git a/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql b/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql index a9eded8e57181..e041453585e77 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql +++ b/js_modules/dagster-ui/packages/ui-core/src/graphql/schema.graphql @@ -3162,14 +3162,22 @@ type Query { limit: Int! cursor: String ): AutoMaterializeAssetEvaluationRecordsOrError - assetConditionEvaluationsOrError( + autoMaterializeEvaluationsForEvaluationId( + evaluationId: Int! + ): AutoMaterializeAssetEvaluationRecordsOrError + assetConditionEvaluationForPartition( + assetKey: AssetKeyInput! + evaluationId: Int! + partition: String! + ): AssetConditionEvaluation + assetConditionEvaluationRecordsOrError( assetKey: AssetKeyInput! limit: Int! cursor: String ): AssetConditionEvaluationRecordsOrError - autoMaterializeEvaluationsForEvaluationId( + assetConditionEvaluationsForEvaluationId( evaluationId: Int! - ): AutoMaterializeAssetEvaluationRecordsOrError + ): AssetConditionEvaluationRecordsOrError autoMaterializeTicks( dayRange: Int dayOffset: Int @@ -3395,36 +3403,24 @@ type AutoMaterializeAssetEvaluationNeedsMigrationError implements Error { message: String! } -union AssetConditionEvaluationRecordsOrError = - AssetConditionEvaluationRecords - | AutoMaterializeAssetEvaluationNeedsMigrationError - -type AssetConditionEvaluationRecords { - records: [AssetConditionEvaluationRecord!]! -} - -type AssetConditionEvaluationRecord { - id: ID! - evaluationId: Int! - runIds: [String!]! - timestamp: Float! - assetKey: AssetKey! - numRequested: Int! - evaluation: AssetConditionEvaluation! +type AssetConditionEvaluation { + rootUniqueId: String! + evaluationNodes: [AssetConditionEvaluationNode!]! } -union AssetConditionEvaluation = - UnpartitionedAssetConditionEvaluation - | PartitionedAssetConditionEvaluation - | SpecificPartitionAssetConditionEvaluation +union AssetConditionEvaluationNode = + UnpartitionedAssetConditionEvaluationNode + | PartitionedAssetConditionEvaluationNode + | SpecificPartitionAssetConditionEvaluationNode -type UnpartitionedAssetConditionEvaluation { +type UnpartitionedAssetConditionEvaluationNode { + uniqueId: String! description: String! - startTimestamp: Float! - endTimestamp: Float! + startTimestamp: Float + endTimestamp: Float metadataEntries: [MetadataEntry!]! status: AssetConditionEvaluationStatus! - childEvaluations: [UnpartitionedAssetConditionEvaluation!] + childUniqueIds: [String!]! } enum AssetConditionEvaluationStatus { @@ -3433,17 +3429,18 @@ enum AssetConditionEvaluationStatus { SKIPPED } -type PartitionedAssetConditionEvaluation { +type PartitionedAssetConditionEvaluationNode { + uniqueId: String! description: String! - startTimestamp: Float! - endTimestamp: Float! + startTimestamp: Float + endTimestamp: Float trueSubset: AssetSubset! falseSubset: AssetSubset! candidateSubset: AssetSubset numTrue: Int! numFalse: Int! numSkipped: Int! - childEvaluations: [PartitionedAssetConditionEvaluation!] + childUniqueIds: [String!]! } type AssetSubset { @@ -3458,11 +3455,32 @@ type AssetSubsetValue { isPartitioned: Boolean! } -type SpecificPartitionAssetConditionEvaluation { +type SpecificPartitionAssetConditionEvaluationNode { + uniqueId: String! description: String! metadataEntries: [MetadataEntry!]! status: AssetConditionEvaluationStatus! - childEvaluations: [UnpartitionedAssetConditionEvaluation!] + childUniqueIds: [String!]! +} + +union AssetConditionEvaluationRecordsOrError = + AssetConditionEvaluationRecords + | AutoMaterializeAssetEvaluationNeedsMigrationError + +type AssetConditionEvaluationRecords { + records: [AssetConditionEvaluationRecord!]! +} + +type AssetConditionEvaluationRecord { + id: ID! + evaluationId: Int! + runIds: [String!]! + timestamp: Float! + assetKey: AssetKey! + numRequested: Int! + startTimestamp: Float + endTimestamp: Float + evaluation: AssetConditionEvaluation! } type Mutation { diff --git a/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts b/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts index 3d4cb117e2a02..25d7491d2fcda 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts +++ b/js_modules/dagster-ui/packages/ui-core/src/graphql/types.ts @@ -245,19 +245,27 @@ export type AssetChecksOrError = | AssetCheckNeedsUserCodeUpgrade | AssetChecks; -export type AssetConditionEvaluation = - | PartitionedAssetConditionEvaluation - | SpecificPartitionAssetConditionEvaluation - | UnpartitionedAssetConditionEvaluation; +export type AssetConditionEvaluation = { + __typename: 'AssetConditionEvaluation'; + evaluationNodes: Array; + rootUniqueId: Scalars['String']; +}; + +export type AssetConditionEvaluationNode = + | PartitionedAssetConditionEvaluationNode + | SpecificPartitionAssetConditionEvaluationNode + | UnpartitionedAssetConditionEvaluationNode; export type AssetConditionEvaluationRecord = { __typename: 'AssetConditionEvaluationRecord'; assetKey: AssetKey; + endTimestamp: Maybe; evaluation: AssetConditionEvaluation; evaluationId: Scalars['Int']; id: Scalars['ID']; numRequested: Scalars['Int']; runIds: Array; + startTimestamp: Maybe; timestamp: Scalars['Float']; }; @@ -2654,18 +2662,19 @@ export type PartitionTags = { export type PartitionTagsOrError = PartitionTags | PythonError; -export type PartitionedAssetConditionEvaluation = { - __typename: 'PartitionedAssetConditionEvaluation'; +export type PartitionedAssetConditionEvaluationNode = { + __typename: 'PartitionedAssetConditionEvaluationNode'; candidateSubset: Maybe; - childEvaluations: Maybe>; + childUniqueIds: Array; description: Scalars['String']; - endTimestamp: Scalars['Float']; + endTimestamp: Maybe; falseSubset: AssetSubset; numFalse: Scalars['Int']; numSkipped: Scalars['Int']; numTrue: Scalars['Int']; - startTimestamp: Scalars['Float']; + startTimestamp: Maybe; trueSubset: AssetSubset; + uniqueId: Scalars['String']; }; export type Partitions = { @@ -3002,7 +3011,9 @@ export type Query = { allTopLevelResourceDetailsOrError: ResourcesOrError; assetBackfillPreview: Array; assetCheckExecutions: Array; - assetConditionEvaluationsOrError: Maybe; + assetConditionEvaluationForPartition: Maybe; + assetConditionEvaluationRecordsOrError: Maybe; + assetConditionEvaluationsForEvaluationId: Maybe; assetNodeDefinitionCollisions: Array; assetNodeOrError: AssetNodeOrError; assetNodes: Array; @@ -3069,12 +3080,22 @@ export type QueryAssetCheckExecutionsArgs = { limit: Scalars['Int']; }; -export type QueryAssetConditionEvaluationsOrErrorArgs = { +export type QueryAssetConditionEvaluationForPartitionArgs = { + assetKey: AssetKeyInput; + evaluationId: Scalars['Int']; + partition: Scalars['String']; +}; + +export type QueryAssetConditionEvaluationRecordsOrErrorArgs = { assetKey: AssetKeyInput; cursor?: InputMaybe; limit: Scalars['Int']; }; +export type QueryAssetConditionEvaluationsForEvaluationIdArgs = { + evaluationId: Scalars['Int']; +}; + export type QueryAssetNodeDefinitionCollisionsArgs = { assetKeys?: InputMaybe>; }; @@ -4157,12 +4178,13 @@ export type SolidStepStatusUnavailableError = Error & { message: Scalars['String']; }; -export type SpecificPartitionAssetConditionEvaluation = { - __typename: 'SpecificPartitionAssetConditionEvaluation'; - childEvaluations: Maybe>; +export type SpecificPartitionAssetConditionEvaluationNode = { + __typename: 'SpecificPartitionAssetConditionEvaluationNode'; + childUniqueIds: Array; description: Scalars['String']; metadataEntries: Array; status: AssetConditionEvaluationStatus; + uniqueId: Scalars['String']; }; export type StaleCause = { @@ -4474,14 +4496,15 @@ export type UnknownPipeline = PipelineReference & { solidSelection: Maybe>; }; -export type UnpartitionedAssetConditionEvaluation = { - __typename: 'UnpartitionedAssetConditionEvaluation'; - childEvaluations: Maybe>; +export type UnpartitionedAssetConditionEvaluationNode = { + __typename: 'UnpartitionedAssetConditionEvaluationNode'; + childUniqueIds: Array; description: Scalars['String']; - endTimestamp: Scalars['Float']; + endTimestamp: Maybe; metadataEntries: Array; - startTimestamp: Scalars['Float']; + startTimestamp: Maybe; status: AssetConditionEvaluationStatus; + uniqueId: Scalars['String']; }; export type UnpartitionedAssetStatus = { @@ -4997,6 +5020,21 @@ export const buildAssetChecks = ( }; }; +export const buildAssetConditionEvaluation = ( + overrides?: Partial, + _relationshipsToOmit: Set = new Set(), +): {__typename: 'AssetConditionEvaluation'} & AssetConditionEvaluation => { + const relationshipsToOmit: Set = new Set(_relationshipsToOmit); + relationshipsToOmit.add('AssetConditionEvaluation'); + return { + __typename: 'AssetConditionEvaluation', + evaluationNodes: + overrides && overrides.hasOwnProperty('evaluationNodes') ? overrides.evaluationNodes! : [], + rootUniqueId: + overrides && overrides.hasOwnProperty('rootUniqueId') ? overrides.rootUniqueId! : 'eos', + }; +}; + export const buildAssetConditionEvaluationRecord = ( overrides?: Partial, _relationshipsToOmit: Set = new Set(), @@ -5011,12 +5049,14 @@ export const buildAssetConditionEvaluationRecord = ( : relationshipsToOmit.has('AssetKey') ? ({} as AssetKey) : buildAssetKey({}, relationshipsToOmit), + endTimestamp: + overrides && overrides.hasOwnProperty('endTimestamp') ? overrides.endTimestamp! : 4.33, evaluation: overrides && overrides.hasOwnProperty('evaluation') ? overrides.evaluation! - : relationshipsToOmit.has('PartitionedAssetConditionEvaluation') - ? ({} as PartitionedAssetConditionEvaluation) - : buildPartitionedAssetConditionEvaluation({}, relationshipsToOmit), + : relationshipsToOmit.has('AssetConditionEvaluation') + ? ({} as AssetConditionEvaluation) + : buildAssetConditionEvaluation({}, relationshipsToOmit), evaluationId: overrides && overrides.hasOwnProperty('evaluationId') ? overrides.evaluationId! : 5501, id: @@ -5026,6 +5066,8 @@ export const buildAssetConditionEvaluationRecord = ( numRequested: overrides && overrides.hasOwnProperty('numRequested') ? overrides.numRequested! : 2364, runIds: overrides && overrides.hasOwnProperty('runIds') ? overrides.runIds! : [], + startTimestamp: + overrides && overrides.hasOwnProperty('startTimestamp') ? overrides.startTimestamp! : 6.66, timestamp: overrides && overrides.hasOwnProperty('timestamp') ? overrides.timestamp! : 6.88, }; }; @@ -9647,43 +9689,46 @@ export const buildPartitionTags = ( }; }; -export const buildPartitionedAssetConditionEvaluation = ( - overrides?: Partial, +export const buildPartitionedAssetConditionEvaluationNode = ( + overrides?: Partial, _relationshipsToOmit: Set = new Set(), -): {__typename: 'PartitionedAssetConditionEvaluation'} & PartitionedAssetConditionEvaluation => { +): { + __typename: 'PartitionedAssetConditionEvaluationNode'; +} & PartitionedAssetConditionEvaluationNode => { const relationshipsToOmit: Set = new Set(_relationshipsToOmit); - relationshipsToOmit.add('PartitionedAssetConditionEvaluation'); + relationshipsToOmit.add('PartitionedAssetConditionEvaluationNode'); return { - __typename: 'PartitionedAssetConditionEvaluation', + __typename: 'PartitionedAssetConditionEvaluationNode', candidateSubset: overrides && overrides.hasOwnProperty('candidateSubset') ? overrides.candidateSubset! : relationshipsToOmit.has('AssetSubset') ? ({} as AssetSubset) : buildAssetSubset({}, relationshipsToOmit), - childEvaluations: - overrides && overrides.hasOwnProperty('childEvaluations') ? overrides.childEvaluations! : [], + childUniqueIds: + overrides && overrides.hasOwnProperty('childUniqueIds') ? overrides.childUniqueIds! : [], description: - overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'non', + overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'quam', endTimestamp: - overrides && overrides.hasOwnProperty('endTimestamp') ? overrides.endTimestamp! : 6.63, + overrides && overrides.hasOwnProperty('endTimestamp') ? overrides.endTimestamp! : 9.74, falseSubset: overrides && overrides.hasOwnProperty('falseSubset') ? overrides.falseSubset! : relationshipsToOmit.has('AssetSubset') ? ({} as AssetSubset) : buildAssetSubset({}, relationshipsToOmit), - numFalse: overrides && overrides.hasOwnProperty('numFalse') ? overrides.numFalse! : 7739, - numSkipped: overrides && overrides.hasOwnProperty('numSkipped') ? overrides.numSkipped! : 7712, - numTrue: overrides && overrides.hasOwnProperty('numTrue') ? overrides.numTrue! : 6991, + numFalse: overrides && overrides.hasOwnProperty('numFalse') ? overrides.numFalse! : 4729, + numSkipped: overrides && overrides.hasOwnProperty('numSkipped') ? overrides.numSkipped! : 5678, + numTrue: overrides && overrides.hasOwnProperty('numTrue') ? overrides.numTrue! : 3015, startTimestamp: - overrides && overrides.hasOwnProperty('startTimestamp') ? overrides.startTimestamp! : 3.43, + overrides && overrides.hasOwnProperty('startTimestamp') ? overrides.startTimestamp! : 5.96, trueSubset: overrides && overrides.hasOwnProperty('trueSubset') ? overrides.trueSubset! : relationshipsToOmit.has('AssetSubset') ? ({} as AssetSubset) : buildAssetSubset({}, relationshipsToOmit), + uniqueId: overrides && overrides.hasOwnProperty('uniqueId') ? overrides.uniqueId! : 'sed', }; }; @@ -10376,9 +10421,21 @@ export const buildQuery = ( overrides && overrides.hasOwnProperty('assetCheckExecutions') ? overrides.assetCheckExecutions! : [], - assetConditionEvaluationsOrError: - overrides && overrides.hasOwnProperty('assetConditionEvaluationsOrError') - ? overrides.assetConditionEvaluationsOrError! + assetConditionEvaluationForPartition: + overrides && overrides.hasOwnProperty('assetConditionEvaluationForPartition') + ? overrides.assetConditionEvaluationForPartition! + : relationshipsToOmit.has('AssetConditionEvaluation') + ? ({} as AssetConditionEvaluation) + : buildAssetConditionEvaluation({}, relationshipsToOmit), + assetConditionEvaluationRecordsOrError: + overrides && overrides.hasOwnProperty('assetConditionEvaluationRecordsOrError') + ? overrides.assetConditionEvaluationRecordsOrError! + : relationshipsToOmit.has('AssetConditionEvaluationRecords') + ? ({} as AssetConditionEvaluationRecords) + : buildAssetConditionEvaluationRecords({}, relationshipsToOmit), + assetConditionEvaluationsForEvaluationId: + overrides && overrides.hasOwnProperty('assetConditionEvaluationsForEvaluationId') + ? overrides.assetConditionEvaluationsForEvaluationId! : relationshipsToOmit.has('AssetConditionEvaluationRecords') ? ({} as AssetConditionEvaluationRecords) : buildAssetConditionEvaluationRecords({}, relationshipsToOmit), @@ -12484,26 +12541,28 @@ export const buildSolidStepStatusUnavailableError = ( }; }; -export const buildSpecificPartitionAssetConditionEvaluation = ( - overrides?: Partial, +export const buildSpecificPartitionAssetConditionEvaluationNode = ( + overrides?: Partial, _relationshipsToOmit: Set = new Set(), ): { - __typename: 'SpecificPartitionAssetConditionEvaluation'; -} & SpecificPartitionAssetConditionEvaluation => { + __typename: 'SpecificPartitionAssetConditionEvaluationNode'; +} & SpecificPartitionAssetConditionEvaluationNode => { const relationshipsToOmit: Set = new Set(_relationshipsToOmit); - relationshipsToOmit.add('SpecificPartitionAssetConditionEvaluation'); + relationshipsToOmit.add('SpecificPartitionAssetConditionEvaluationNode'); return { - __typename: 'SpecificPartitionAssetConditionEvaluation', - childEvaluations: - overrides && overrides.hasOwnProperty('childEvaluations') ? overrides.childEvaluations! : [], + __typename: 'SpecificPartitionAssetConditionEvaluationNode', + childUniqueIds: + overrides && overrides.hasOwnProperty('childUniqueIds') ? overrides.childUniqueIds! : [], description: - overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'vel', + overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'ut', metadataEntries: overrides && overrides.hasOwnProperty('metadataEntries') ? overrides.metadataEntries! : [], status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : AssetConditionEvaluationStatus.FALSE, + uniqueId: + overrides && overrides.hasOwnProperty('uniqueId') ? overrides.uniqueId! : 'repudiandae', }; }; @@ -13164,30 +13223,31 @@ export const buildUnknownPipeline = ( }; }; -export const buildUnpartitionedAssetConditionEvaluation = ( - overrides?: Partial, +export const buildUnpartitionedAssetConditionEvaluationNode = ( + overrides?: Partial, _relationshipsToOmit: Set = new Set(), ): { - __typename: 'UnpartitionedAssetConditionEvaluation'; -} & UnpartitionedAssetConditionEvaluation => { + __typename: 'UnpartitionedAssetConditionEvaluationNode'; +} & UnpartitionedAssetConditionEvaluationNode => { const relationshipsToOmit: Set = new Set(_relationshipsToOmit); - relationshipsToOmit.add('UnpartitionedAssetConditionEvaluation'); + relationshipsToOmit.add('UnpartitionedAssetConditionEvaluationNode'); return { - __typename: 'UnpartitionedAssetConditionEvaluation', - childEvaluations: - overrides && overrides.hasOwnProperty('childEvaluations') ? overrides.childEvaluations! : [], + __typename: 'UnpartitionedAssetConditionEvaluationNode', + childUniqueIds: + overrides && overrides.hasOwnProperty('childUniqueIds') ? overrides.childUniqueIds! : [], description: - overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'deserunt', + overrides && overrides.hasOwnProperty('description') ? overrides.description! : 'veniam', endTimestamp: - overrides && overrides.hasOwnProperty('endTimestamp') ? overrides.endTimestamp! : 7.57, + overrides && overrides.hasOwnProperty('endTimestamp') ? overrides.endTimestamp! : 3.21, metadataEntries: overrides && overrides.hasOwnProperty('metadataEntries') ? overrides.metadataEntries! : [], startTimestamp: - overrides && overrides.hasOwnProperty('startTimestamp') ? overrides.startTimestamp! : 0.96, + overrides && overrides.hasOwnProperty('startTimestamp') ? overrides.startTimestamp! : 2.94, status: overrides && overrides.hasOwnProperty('status') ? overrides.status! : AssetConditionEvaluationStatus.FALSE, + uniqueId: overrides && overrides.hasOwnProperty('uniqueId') ? overrides.uniqueId! : 'et', }; }; diff --git a/python_modules/dagster-graphql/dagster_graphql/implementation/fetch_asset_condition_evaluations.py b/python_modules/dagster-graphql/dagster_graphql/implementation/fetch_asset_condition_evaluations.py index b96f42a563e6e..b04af439c46ac 100644 --- a/python_modules/dagster-graphql/dagster_graphql/implementation/fetch_asset_condition_evaluations.py +++ b/python_modules/dagster-graphql/dagster_graphql/implementation/fetch_asset_condition_evaluations.py @@ -10,7 +10,6 @@ GrapheneAssetConditionEvaluationRecord, GrapheneAssetConditionEvaluationRecords, GrapheneAssetConditionEvaluationRecordsOrError, - GrapheneSpecificPartitionAssetConditionEvaluation, ) from dagster_graphql.schema.auto_materialize_asset_evaluations import ( GrapheneAutoMaterializeAssetEvaluationNeedsMigrationError, @@ -86,8 +85,11 @@ def fetch_asset_condition_evaluation_record_for_partition( if asset_node and asset_node.external_asset_node.partitions_def_data else None ) - return GrapheneSpecificPartitionAssetConditionEvaluation( - record.get_evaluation_with_run_ids(partitions_def).evaluation, partition_key + return GrapheneAssetConditionEvaluation( + record.get_evaluation_with_run_ids(partitions_def).evaluation, + partitions_def, + graphene_info.context.instance, + partition_key, ) diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py b/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py index 9b81ff2204b70..bb9f6e6919278 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/asset_condition_evaluations.py @@ -1,15 +1,17 @@ import enum +import itertools from typing import Optional, Sequence, Union import graphene import pendulum -from dagster._core.definitions.asset_condition import AssetConditionEvaluation +from dagster._core.definitions.asset_condition import AssetConditionEvaluationResult from dagster._core.definitions.asset_subset import AssetSubset from dagster._core.definitions.partition import PartitionsDefinition, PartitionsSubset from dagster._core.definitions.time_window_partitions import BaseTimeWindowPartitionsSubset from dagster._core.instance import DynamicPartitionsStore from dagster._core.scheduler.instigation import AutoMaterializeAssetEvaluationRecord +from dagster_graphql.implementation.events import iterate_metadata_entries from dagster_graphql.schema.auto_materialize_asset_evaluations import ( GrapheneAutoMaterializeAssetEvaluationNeedsMigrationError, ) @@ -48,6 +50,7 @@ def __init__(self, value: Union[bool, PartitionsSubset]): GraphenePartitionKeyRange(start, end) for start, end in value.get_partition_key_ranges(value.partitions_def) ] + partition_keys = value.get_partition_keys() else: partition_keys = value.get_partition_keys() @@ -75,7 +78,8 @@ def __init__(self, asset_subset: AssetSubset): ) -class GrapheneUnpartitionedAssetConditionEvaluation(graphene.ObjectType): +class GrapheneUnpartitionedAssetConditionEvaluationNode(graphene.ObjectType): + uniqueId = graphene.NonNull(graphene.String) description = graphene.NonNull(graphene.String) startTimestamp = graphene.Field(graphene.Float) @@ -84,29 +88,31 @@ class GrapheneUnpartitionedAssetConditionEvaluation(graphene.ObjectType): metadataEntries = non_null_list(GrapheneMetadataEntry) status = graphene.NonNull(GrapheneAssetConditionEvaluationStatus) - childEvaluations = graphene.Field( - graphene.List(graphene.NonNull(lambda: GrapheneUnpartitionedAssetConditionEvaluation)) - ) + childUniqueIds = non_null_list(graphene.String) class Meta: - name = "UnpartitionedAssetConditionEvaluation" + name = "UnpartitionedAssetConditionEvaluationNode" - def __init__(self, evaluation: AssetConditionEvaluation): + def __init__(self, evaluation: AssetConditionEvaluationResult): + self._evaluation = evaluation if evaluation.true_subset.bool_value: status = AssetConditionEvaluationStatus.TRUE - elif evaluation.candidate_subset and evaluation.candidate_subset.bool_value: + elif ( + isinstance(evaluation.candidate_subset, AssetSubset) + and evaluation.candidate_subset.bool_value + ): status = AssetConditionEvaluationStatus.FALSE else: status = AssetConditionEvaluationStatus.SKIPPED super().__init__( + uniqueId=evaluation.condition_snapshot.unique_id, description=evaluation.condition_snapshot.description, startTimestamp=evaluation.start_timestamp, endTimestamp=evaluation.end_timestamp, status=status, - childEvaluations=[ - GrapheneUnpartitionedAssetConditionEvaluation(child) - for child in evaluation.child_evaluations + childUniqueIds=[ + child.condition_snapshot.unique_id for child in evaluation.child_evaluations ], ) @@ -117,10 +123,11 @@ def resolve_metadataEntries( (subset.metadata for subset in self._evaluation.subsets_with_metadata), {}, ) - return [GrapheneMetadataEntry(key=key, value=value) for key, value in metadata.items()] + return list(iterate_metadata_entries(metadata)) -class GraphenePartitionedAssetConditionEvaluation(graphene.ObjectType): +class GraphenePartitionedAssetConditionEvaluationNode(graphene.ObjectType): + uniqueId = graphene.NonNull(graphene.String) description = graphene.NonNull(graphene.String) startTimestamp = graphene.Field(graphene.Float) @@ -134,16 +141,14 @@ class GraphenePartitionedAssetConditionEvaluation(graphene.ObjectType): numFalse = graphene.NonNull(graphene.Int) numSkipped = graphene.NonNull(graphene.Int) - childEvaluations = graphene.Field( - graphene.List(graphene.NonNull(lambda: GraphenePartitionedAssetConditionEvaluation)) - ) + childUniqueIds = non_null_list(graphene.String) class Meta: - name = "PartitionedAssetConditionEvaluation" + name = "PartitionedAssetConditionEvaluationNode" def __init__( self, - evaluation: AssetConditionEvaluation, + evaluation: AssetConditionEvaluationResult, partitions_def: Optional[PartitionsDefinition], dynamic_partitions_store: DynamicPartitionsStore, ): @@ -154,20 +159,22 @@ def __init__( evaluation.asset_key, partitions_def, dynamic_partitions_store, pendulum.now("UTC") ) - # if the candidate_subset is unset, then we evaluated all partitions - self._candidate_subset = evaluation.candidate_subset or self._all_subset + # if the candidate_subset is a HistoricalAssetSubset, then we evaluated all partitions + self._candidate_subset = ( + evaluation.candidate_subset + if isinstance(evaluation.candidate_subset, AssetSubset) + else self._all_subset + ) super().__init__( + uniqueId=evaluation.condition_snapshot.unique_id, description=evaluation.condition_snapshot.description, startTimestamp=evaluation.start_timestamp, endTimestamp=evaluation.end_timestamp, trueSubset=GrapheneAssetSubset(evaluation.true_subset), candidateSubset=GrapheneAssetSubset(self._candidate_subset), - childEvaluations=[ - GraphenePartitionedAssetConditionEvaluation( - child, partitions_def, dynamic_partitions_store - ) - for child in evaluation.child_evaluations + childUniqueIds=[ + child.condition_snapshot.unique_id for child in evaluation.child_evaluations ], ) @@ -184,27 +191,26 @@ def resolve_numSkipped(self, graphene_info: ResolveInfo) -> int: return self._all_subset.size - self._candidate_subset.size -class GrapheneSpecificPartitionAssetConditionEvaluation(graphene.ObjectType): +class GrapheneSpecificPartitionAssetConditionEvaluationNode(graphene.ObjectType): + uniqueId = graphene.NonNull(graphene.String) description = graphene.NonNull(graphene.String) metadataEntries = non_null_list(GrapheneMetadataEntry) status = graphene.NonNull(GrapheneAssetConditionEvaluationStatus) - childEvaluations = graphene.Field( - graphene.List(graphene.NonNull(lambda: GrapheneSpecificPartitionAssetConditionEvaluation)) - ) + childUniqueIds = non_null_list(graphene.String) class Meta: - name = "SpecificPartitionAssetConditionEvaluation" + name = "SpecificPartitionAssetConditionEvaluationNode" - def __init__(self, evaluation: AssetConditionEvaluation, partition_key: str): + def __init__(self, evaluation: AssetConditionEvaluationResult, partition_key: str): self._evaluation = evaluation self._partition_key = partition_key if partition_key in evaluation.true_subset.subset_value: status = AssetConditionEvaluationStatus.TRUE elif ( - evaluation.candidate_subset is None + not isinstance(evaluation.candidate_subset, AssetSubset) or partition_key in evaluation.candidate_subset.subset_value ): status = AssetConditionEvaluationStatus.FALSE @@ -212,11 +218,11 @@ def __init__(self, evaluation: AssetConditionEvaluation, partition_key: str): status = AssetConditionEvaluationStatus.SKIPPED super().__init__( + uniqueId=evaluation.condition_snapshot.unique_id, description=evaluation.condition_snapshot.description, status=status, - childEvaluations=[ - GrapheneSpecificPartitionAssetConditionEvaluation(child, partition_key) - for child in evaluation.child_evaluations + childUniqueIds=[ + child.condition_snapshot.unique_id for child in evaluation.child_evaluations ], ) @@ -232,18 +238,63 @@ def resolve_metadataEntries( ), {}, ) - return [GrapheneMetadataEntry(key=key, value=value) for key, value in metadata.items()] + return list(iterate_metadata_entries(metadata)) -class GrapheneAssetConditionEvaluation(graphene.Union): +class GrapheneAssetConditionEvaluationNode(graphene.Union): class Meta: types = ( - GrapheneUnpartitionedAssetConditionEvaluation, - GraphenePartitionedAssetConditionEvaluation, - GrapheneSpecificPartitionAssetConditionEvaluation, + GrapheneUnpartitionedAssetConditionEvaluationNode, + GraphenePartitionedAssetConditionEvaluationNode, + GrapheneSpecificPartitionAssetConditionEvaluationNode, ) + name = "AssetConditionEvaluationNode" + + +class GrapheneAssetConditionEvaluation(graphene.ObjectType): + rootUniqueId = graphene.NonNull(graphene.String) + evaluationNodes = non_null_list(GrapheneAssetConditionEvaluationNode) + + class Meta: name = "AssetConditionEvaluation" + def __init__( + self, + evaluation: AssetConditionEvaluationResult, + partitions_def: Optional[PartitionsDefinition], + dynamic_partitions_store: DynamicPartitionsStore, + partition_key: Optional[str] = None, + ): + # flatten the evaluation tree into a list of nodes + def _flatten(e: AssetConditionEvaluationResult) -> Sequence[AssetConditionEvaluationResult]: + return list(itertools.chain([e], *(_flatten(ce) for ce in e.child_evaluations))) + + all_nodes = _flatten(evaluation) + + if evaluation.true_subset.is_partitioned: + if partition_key is None: + evaluationNodes = [ + GraphenePartitionedAssetConditionEvaluationNode( + evaluation, partitions_def, dynamic_partitions_store + ) + for evaluation in all_nodes + ] + else: + evaluationNodes = [ + GrapheneSpecificPartitionAssetConditionEvaluationNode(evaluation, partition_key) + for evaluation in all_nodes + ] + else: + evaluationNodes = [ + GrapheneUnpartitionedAssetConditionEvaluationNode(evaluation) + for evaluation in all_nodes + ] + + super().__init__( + rootUniqueId=evaluation.condition_snapshot.unique_id, + evaluationNodes=evaluationNodes, + ) + class GrapheneAssetConditionEvaluationRecord(graphene.ObjectType): id = graphene.NonNull(graphene.ID) @@ -254,6 +305,9 @@ class GrapheneAssetConditionEvaluationRecord(graphene.ObjectType): assetKey = graphene.NonNull(GrapheneAssetKey) numRequested = graphene.NonNull(graphene.Int) + startTimestamp = graphene.Field(graphene.Float) + endTimestamp = graphene.Field(graphene.Float) + evaluation = graphene.NonNull(GrapheneAssetConditionEvaluation) class Meta: @@ -264,22 +318,8 @@ def __init__( record: AutoMaterializeAssetEvaluationRecord, partitions_def: Optional[PartitionsDefinition], dynamic_partitions_store: DynamicPartitionsStore, - partition_key: Optional[str] = None, ): evaluation_with_run_ids = record.get_evaluation_with_run_ids(partitions_def) - if evaluation_with_run_ids.evaluation.true_subset.is_partitioned: - if partition_key is None: - evaluation = GraphenePartitionedAssetConditionEvaluation( - evaluation_with_run_ids.evaluation, partitions_def, dynamic_partitions_store - ) - else: - evaluation = GrapheneSpecificPartitionAssetConditionEvaluation( - evaluation_with_run_ids.evaluation, partition_key - ) - else: - evaluation = GrapheneUnpartitionedAssetConditionEvaluation( - evaluation_with_run_ids.evaluation - ) super().__init__( id=record.id, @@ -288,7 +328,11 @@ def __init__( runIds=evaluation_with_run_ids.run_ids, assetKey=GrapheneAssetKey(path=record.asset_key.path), numRequested=evaluation_with_run_ids.evaluation.true_subset.size, - evaluation=evaluation, + startTimestamp=evaluation_with_run_ids.evaluation.start_timestamp, + endTimestamp=evaluation_with_run_ids.evaluation.end_timestamp, + evaluation=GrapheneAssetConditionEvaluation( + evaluation_with_run_ids.evaluation, partitions_def, dynamic_partitions_store + ), ) diff --git a/python_modules/dagster-graphql/dagster_graphql/schema/roots/query.py b/python_modules/dagster-graphql/dagster_graphql/schema/roots/query.py index e0baa9225b6ec..9228b6a19cf28 100644 --- a/python_modules/dagster-graphql/dagster_graphql/schema/roots/query.py +++ b/python_modules/dagster-graphql/dagster_graphql/schema/roots/query.py @@ -36,8 +36,8 @@ from dagster_graphql.implementation.fetch_logs import get_captured_log_metadata from dagster_graphql.implementation.fetch_runs import get_assets_latest_info from dagster_graphql.schema.asset_condition_evaluations import ( + GrapheneAssetConditionEvaluation, GrapheneAssetConditionEvaluationRecordsOrError, - GrapheneSpecificPartitionAssetConditionEvaluation, ) from dagster_graphql.schema.auto_materialize_asset_evaluations import ( GrapheneAutoMaterializeAssetEvaluationRecordsOrError, @@ -523,7 +523,7 @@ class Meta: ) assetConditionEvaluationForPartition = graphene.Field( - GrapheneSpecificPartitionAssetConditionEvaluation, + GrapheneAssetConditionEvaluation, assetKey=graphene.Argument(graphene.NonNull(GrapheneAssetKeyInput)), evaluationId=graphene.Argument(graphene.NonNull(graphene.Int)), partition=graphene.Argument(graphene.NonNull(graphene.String)), diff --git a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_asset_condition_evaluations.py b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_asset_condition_evaluations.py index d62d4b8524bcf..b0b66c5ed0bfd 100644 --- a/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_asset_condition_evaluations.py +++ b/python_modules/dagster-graphql/dagster_graphql_tests/graphql/test_asset_condition_evaluations.py @@ -1,11 +1,12 @@ -from typing import Optional, Sequence +import random +from typing import Any, Mapping, Optional, Sequence from unittest.mock import PropertyMock, patch import dagster._check as check import pendulum from dagster import AssetKey, RunRequest from dagster._core.definitions.asset_condition import ( - AssetConditionEvaluation, + AssetConditionEvaluationResult, AssetConditionEvaluationWithRunIds, AssetConditionSnapshot, HistoricalAllPartitionsSubset, @@ -213,63 +214,44 @@ def test_get_tick_range(self, graphql_context): FRAGMENTS = """ -fragment unpartitionedEvaluationFields on UnpartitionedAssetConditionEvaluation { - description - startTimestamp - endTimestamp - status -} - -fragment partitionedEvaluationFields on PartitionedAssetConditionEvaluation { - description - startTimestamp - endTimestamp - numTrue - numFalse - numSkipped - trueSubset { - subsetValue { - isPartitioned - partitionKeys - } - } - falseSubset { - subsetValue { - isPartitioned - partitionKeys - } - } -} - fragment evaluationFields on AssetConditionEvaluation { - ... on UnpartitionedAssetConditionEvaluation { - ...unpartitionedEvaluationFields - childEvaluations { - ...unpartitionedEvaluationFields - childEvaluations { - ...unpartitionedEvaluationFields - childEvaluations { - ...unpartitionedEvaluationFields - childEvaluations { - ...unpartitionedEvaluationFields - } + rootUniqueId + evaluationNodes { + ... on UnpartitionedAssetConditionEvaluationNode { + description + startTimestamp + endTimestamp + status + uniqueId + childUniqueIds + } + ... on PartitionedAssetConditionEvaluationNode { + description + startTimestamp + endTimestamp + numTrue + numFalse + numSkipped + trueSubset { + subsetValue { + isPartitioned + partitionKeys } } - } - } - ... on PartitionedAssetConditionEvaluation { - ...partitionedEvaluationFields - childEvaluations { - ...partitionedEvaluationFields - childEvaluations { - ...partitionedEvaluationFields - childEvaluations { - ...partitionedEvaluationFields - childEvaluations { - ...partitionedEvaluationFields - } + falseSubset { + subsetValue { + isPartitioned + partitionKeys } } + uniqueId + childUniqueIds + } + ... on SpecificPartitionAssetConditionEvaluationNode { + description + status + uniqueId + childUniqueIds } } } @@ -304,29 +286,16 @@ def test_get_tick_range(self, graphql_context): """ ) -QUERY_FOR_SPECIFIC_PARTITION = """ -fragment specificPartitionEvaluationFields on SpecificPartitionAssetConditionEvaluation { - description - status -} +QUERY_FOR_SPECIFIC_PARTITION = ( + FRAGMENTS + + """ query GetPartitionEvaluationQuery($assetKey: AssetKeyInput!, $partition: String!, $evaluationId: Int!) { assetConditionEvaluationForPartition(assetKey: $assetKey, partition: $partition, evaluationId: $evaluationId) { - ...specificPartitionEvaluationFields - childEvaluations { - ...specificPartitionEvaluationFields - childEvaluations { - ...specificPartitionEvaluationFields - childEvaluations { - ...specificPartitionEvaluationFields - childEvaluations { - ...specificPartitionEvaluationFields - } - } - } - } + ...evaluationFields } } """ +) QUERY_FOR_EVALUATION_ID = ( FRAGMENTS @@ -416,7 +385,7 @@ def test_get_historic_rules_without_evaluation_data( assert len(results.data["assetConditionEvaluationRecordsOrError"]["records"]) == 1 asset_one_record = results.data["assetConditionEvaluationRecordsOrError"]["records"][0] assert asset_one_record["assetKey"] == {"path": ["asset_one"]} - assert asset_one_record["evaluation"]["status"] == "SKIPPED" + assert asset_one_record["evaluation"]["evaluationNodes"][0]["status"] == "SKIPPED" results = execute_dagster_graphql( graphql_context, @@ -425,16 +394,22 @@ def test_get_historic_rules_without_evaluation_data( ) assert len(results.data["assetConditionEvaluationRecordsOrError"]["records"]) == 1 asset_two_record = results.data["assetConditionEvaluationRecordsOrError"]["records"][0] - assert asset_two_record["evaluation"]["description"] == "All of" - assert asset_two_record["evaluation"]["status"] == "SKIPPED" - asset_two_children = asset_two_record["evaluation"]["childEvaluations"] - assert len(asset_two_children) == 2 - assert asset_two_children[0]["description"] == "Any of" - assert asset_two_children[0]["status"] == "SKIPPED" - assert ( - asset_two_children[0]["childEvaluations"][0]["description"] - == "materialization is missing" + asset_two_root = asset_two_record["evaluation"]["evaluationNodes"][0] + + assert asset_two_root["description"] == "All of" + assert asset_two_root["status"] == "SKIPPED" + assert len(asset_two_root["childUniqueIds"]) == 2 + + asset_two_child = self._get_node( + asset_two_root["childUniqueIds"][0], asset_two_record["evaluation"]["evaluationNodes"] ) + assert asset_two_child["description"] == "Any of" + assert asset_two_child["status"] == "SKIPPED" + + asset_two_missing_node = self._get_node( + asset_two_child["childUniqueIds"][0], asset_two_record["evaluation"]["evaluationNodes"] + ) + assert asset_two_missing_node["description"] == "materialization is missing" results = execute_dagster_graphql( graphql_context, @@ -450,6 +425,7 @@ def test_get_historic_rules_without_evaluation_data( assert any(record == asset_one_record for record in records) assert any(record == asset_two_record for record in records) + # this evaluationId doesn't exist results = execute_dagster_graphql( graphql_context, QUERY_FOR_EVALUATION_ID, @@ -485,17 +461,24 @@ def test_get_historic_evaluation_with_evaluation_data( records = results.data["assetConditionEvaluationRecordsOrError"]["records"] assert len(records) == 1 + evaluation = records[0]["evaluation"] - assert evaluation["numTrue"] == 0 - assert evaluation["numFalse"] == 6 - assert evaluation["numSkipped"] == 0 - assert len(evaluation["childEvaluations"]) == 2 - not_skip_evaluation = evaluation["childEvaluations"][1] - assert not_skip_evaluation["description"] == "Not" - assert not_skip_evaluation["numTrue"] == 1 - assert len(not_skip_evaluation["childEvaluations"]) == 1 - assert not_skip_evaluation["childEvaluations"][0]["description"] == "Any of" - assert len(not_skip_evaluation["childEvaluations"][0]["childEvaluations"]) == 2 + rootNode = evaluation["evaluationNodes"][0] + assert rootNode["uniqueId"] == evaluation["rootUniqueId"] + + assert rootNode["numTrue"] == 0 + assert rootNode["numFalse"] == 6 + assert rootNode["numSkipped"] == 0 + assert len(rootNode["childUniqueIds"]) == 2 + + notSkipNode = self._get_node(rootNode["childUniqueIds"][0], evaluation["evaluationNodes"]) + assert notSkipNode["description"] == "Not" + assert notSkipNode["numTrue"] == 1 + assert len(notSkipNode["childUniqueIds"]) == 1 + + skipNode = self._get_node(rootNode["childUniqueIds"][1], evaluation["evaluationNodes"]) + assert skipNode["description"] == "Any of" + assert len(skipNode["childUniqueIds"]) == 2 def test_get_evaluations(self, graphql_context: WorkspaceRequestContext): evaluation1 = deserialize_auto_materialize_asset_evaluation_to_asset_condition_evaluation_with_run_ids( @@ -658,6 +641,11 @@ def test_get_evaluations(self, graphql_context: WorkspaceRequestContext): }, } + def _get_node( + self, unique_id: str, evaluations: Sequence[Mapping[str, Any]] + ) -> Mapping[str, Any]: + return next(iter([node for node in evaluations if node["uniqueId"] == unique_id])) + def _get_condition_evaluation( self, asset_key: AssetKey, @@ -665,10 +653,12 @@ def _get_condition_evaluation( partitions_def: PartitionsDefinition, true_partition_keys: Sequence[str], candidate_partition_keys: Optional[Sequence[str]] = None, - child_evaluations: Optional[Sequence[AssetConditionEvaluation]] = None, - ) -> AssetConditionEvaluation: - return AssetConditionEvaluation( - condition_snapshot=AssetConditionSnapshot("...", description, "a1b2"), + child_evaluations: Optional[Sequence[AssetConditionEvaluationResult]] = None, + ) -> AssetConditionEvaluationResult: + return AssetConditionEvaluationResult( + condition_snapshot=AssetConditionSnapshot( + "...", description, str(random.randint(0, 100000000)) + ), true_subset=AssetSubset( asset_key=asset_key, value=partitions_def.subset_with_partition_keys(true_partition_keys), @@ -782,26 +772,32 @@ def test_get_evaluations_with_partitions(self, graphql_context: WorkspaceRequest assert records[0]["numRequested"] == 2 evaluation = records[0]["evaluation"] - assert evaluation["description"] == "All of" - assert evaluation["numTrue"] == 2 - assert evaluation["numFalse"] == 4 - assert evaluation["numSkipped"] == 0 - assert set(evaluation["trueSubset"]["subsetValue"]["partitionKeys"]) == {"a", "b"} - assert len(evaluation["childEvaluations"]) == 2 - - not_evaluation = evaluation["childEvaluations"][1] - assert not_evaluation["description"] == "Not" - assert not_evaluation["numTrue"] == 2 - assert not_evaluation["numFalse"] == 1 - assert not_evaluation["numSkipped"] == 3 - assert set(not_evaluation["trueSubset"]["subsetValue"]["partitionKeys"]) == {"a", "b"} - - skip_evaluation = not_evaluation["childEvaluations"][0] - assert skip_evaluation["description"] == "Any of" - assert skip_evaluation["numTrue"] == 1 - assert skip_evaluation["numFalse"] == 2 - assert skip_evaluation["numSkipped"] == 3 - assert set(skip_evaluation["trueSubset"]["subsetValue"]["partitionKeys"]) == {"c"} + + # all nodes in the tree + assert len(evaluation["evaluationNodes"]) == 9 + + rootNode = evaluation["evaluationNodes"][0] + assert rootNode["uniqueId"] == evaluation["rootUniqueId"] + assert rootNode["description"] == "All of" + assert rootNode["numTrue"] == 2 + assert rootNode["numFalse"] == 4 + assert rootNode["numSkipped"] == 0 + assert set(rootNode["trueSubset"]["subsetValue"]["partitionKeys"]) == {"a", "b"} + assert len(rootNode["childUniqueIds"]) == 2 + + notNode = self._get_node(rootNode["childUniqueIds"][1], evaluation["evaluationNodes"]) + assert notNode["description"] == "Not" + assert notNode["numTrue"] == 2 + assert notNode["numFalse"] == 1 + assert notNode["numSkipped"] == 3 + assert set(notNode["trueSubset"]["subsetValue"]["partitionKeys"]) == {"a", "b"} + + skipNode = self._get_node(notNode["childUniqueIds"][0], evaluation["evaluationNodes"]) + assert skipNode["description"] == "Any of" + assert skipNode["numTrue"] == 1 + assert skipNode["numFalse"] == 2 + assert skipNode["numSkipped"] == 3 + assert set(skipNode["trueSubset"]["subsetValue"]["partitionKeys"]) == {"c"} # test one of the true partitions specific_result = execute_dagster_graphql( @@ -815,17 +811,22 @@ def test_get_evaluations_with_partitions(self, graphql_context: WorkspaceRequest ) evaluation = specific_result.data["assetConditionEvaluationForPartition"] - assert evaluation["description"] == "All of" - assert evaluation["status"] == "TRUE" - assert len(evaluation["childEvaluations"]) == 2 + assert len(evaluation["evaluationNodes"]) == 9 + + rootNode = evaluation["evaluationNodes"][0] + assert rootNode["uniqueId"] == evaluation["rootUniqueId"] + + assert rootNode["description"] == "All of" + assert rootNode["status"] == "TRUE" + assert len(rootNode["childUniqueIds"]) == 2 - not_evaluation = evaluation["childEvaluations"][1] - assert not_evaluation["description"] == "Not" - assert not_evaluation["status"] == "TRUE" + notNode = self._get_node(rootNode["childUniqueIds"][1], evaluation["evaluationNodes"]) + assert notNode["description"] == "Not" + assert notNode["status"] == "TRUE" - skip_evaluation = not_evaluation["childEvaluations"][0] - assert skip_evaluation["description"] == "Any of" - assert skip_evaluation["status"] == "FALSE" + skipNode = self._get_node(notNode["childUniqueIds"][0], evaluation["evaluationNodes"]) + assert skipNode["description"] == "Any of" + assert skipNode["status"] == "FALSE" # test one of the false partitions specific_result = execute_dagster_graphql( @@ -839,17 +840,22 @@ def test_get_evaluations_with_partitions(self, graphql_context: WorkspaceRequest ) evaluation = specific_result.data["assetConditionEvaluationForPartition"] - assert evaluation["description"] == "All of" - assert evaluation["status"] == "FALSE" - assert len(evaluation["childEvaluations"]) == 2 + assert len(evaluation["evaluationNodes"]) == 9 + + rootNode = evaluation["evaluationNodes"][0] + assert rootNode["uniqueId"] == evaluation["rootUniqueId"] + + assert rootNode["description"] == "All of" + assert rootNode["status"] == "FALSE" + assert len(rootNode["childUniqueIds"]) == 2 - not_evaluation = evaluation["childEvaluations"][1] - assert not_evaluation["description"] == "Not" - assert not_evaluation["status"] == "SKIPPED" + notNode = self._get_node(rootNode["childUniqueIds"][1], evaluation["evaluationNodes"]) + assert notNode["description"] == "Not" + assert notNode["status"] == "SKIPPED" - skip_evaluation = not_evaluation["childEvaluations"][0] - assert skip_evaluation["description"] == "Any of" - assert skip_evaluation["status"] == "SKIPPED" + skipNode = self._get_node(notNode["childUniqueIds"][0], evaluation["evaluationNodes"]) + assert skipNode["description"] == "Any of" + assert skipNode["status"] == "SKIPPED" def _test_current_evaluation_id(self, graphql_context: WorkspaceRequestContext): graphql_context.instance.daemon_cursor_storage.set_cursor_values(