Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@
INTERVALS,
isFloat,
} from "@rilldata/web-common/lib/duckdb-data-types";
import { QueryServiceColumnNumericHistogramHistogramMethod } from "@rilldata/web-common/runtime-client";
import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import {
createQueryServiceColumnDescriptiveStatistics,
createQueryServiceColumnRugHistogram,
} from "@rilldata/web-common/runtime-client";
import { useRuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import { getPriorityForColumn } from "@rilldata/web-common/runtime-client/v2/request-priorities";
import { derived } from "svelte/store";
import ColumnProfileIcon from "../ColumnProfileIcon.svelte";
Expand All @@ -25,6 +24,8 @@
import NumericPlot from "./details/NumericPlot.svelte";
import NullPercentageSpark from "./sparks/NullPercentageSpark.svelte";
import NumericSpark from "./sparks/NumericSpark.svelte";
import { HistogramMethod } from "@rilldata/web-common/proto/gen/rill/runtime/v1/queries_pb.ts";
import { getOneofValue } from "@rilldata/web-common/lib/proto-utils.ts";

export let connector: string;
export let database: string;
Expand Down Expand Up @@ -61,7 +62,7 @@
databaseSchema,
objectName,
columnName,
QueryServiceColumnNumericHistogramHistogramMethod.HISTOGRAM_METHOD_DIAGNOSTIC,
HistogramMethod.DIAGNOSTIC,
enableProfiling,
);
let fdHistogram;
Expand All @@ -73,7 +74,7 @@
databaseSchema,
objectName,
columnName,
QueryServiceColumnNumericHistogramHistogramMethod.HISTOGRAM_METHOD_FD,
HistogramMethod.FD,
enableProfiling,
);
}
Expand Down Expand Up @@ -104,7 +105,11 @@
{
query: {
select($query) {
return $query?.numericSummary?.numericOutliers?.outliers;
return getOneofValue(
$query?.numericSummary,
"case",
"numericOutliers",
)?.outliers;
},
enabled: enableProfiling,
},
Expand Down Expand Up @@ -138,7 +143,11 @@
},
),
($query) => {
return $query?.data?.numericSummary?.numericStatistics;
return getOneofValue(
$query?.data?.numericSummary,
"case",
"numericStatistics",
);
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
isFetching,
} from "../queries";
import NullPercentageSpark from "./sparks/NullPercentageSpark.svelte";
import { FromProtoTimeGrainMap } from "@rilldata/web-common/features/dashboards/proto-state/enum-maps.ts";
import { TimeGrain } from "@rilldata/web-common/proto/gen/rill/runtime/v1/time_grain_pb.ts";

export let connector: string;
export let database: string;
Expand Down Expand Up @@ -110,8 +112,13 @@
height={timestampDetailHeight}
{data}
{spark}
rollupTimeGrain={$timeSeries?.estimatedRollupInterval?.interval}
estimatedSmallestTimeGrain={$timeSeries?.smallestTimegrain}
rollupTimeGrain={FromProtoTimeGrainMap[
$timeSeries?.estimatedRollupInterval?.interval ??
TimeGrain.UNSPECIFIED
]}
estimatedSmallestTimeGrain={FromProtoTimeGrainMap[
$timeSeries?.smallestTimegrain ?? TimeGrain.UNSPECIFIED
]}
/>
{/if}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
// Since the topk query is in a reactive statement with `enable`, `topK` can be undefined.
// This leads to unexpected issues when paired with transition
$: topKCopy = topK ?? topKCopy;
$: topKNormalised = topKCopy?.map((k) => k.toJSON());

function ensureSpaces(str: string, n = 6) {
const sanitized = DOMPurify.sanitize(str, { ALLOWED_TAGS: [] });
Expand Down Expand Up @@ -77,9 +78,9 @@
/** handle LISTs and STRUCTs */
</script>

{#if topKCopy && totalRows}
{#if topKNormalised && totalRows}
<div transition:slide={{ duration: LIST_SLIDE_DURATION }}>
{#each topKCopy.slice(0, k) as item (item.value)}
{#each topKNormalised.slice(0, k) as item (item.value)}
{@const negligiblePercentage = item.count / totalRows < 0.0002}
{@const percentage = negligiblePercentage
? "<.01%"
Expand Down
39 changes: 29 additions & 10 deletions web-common/src/features/column-profile/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import {
createQueryServiceColumnTimeSeries,
createQueryServiceColumnTopK,
createQueryServiceTableCardinality,
QueryServiceColumnNumericHistogramHistogramMethod,
type V1ProfileColumn,
type V1TableColumnsResponse,
type V1TimeSeriesValue,
} from "@rilldata/web-common/runtime-client";
import type { RuntimeClient } from "@rilldata/web-common/runtime-client/v2";
import { getPriorityForColumn } from "@rilldata/web-common/runtime-client/v2/request-priorities";
Expand All @@ -19,6 +17,14 @@ import {
type QueryObserverResult,
} from "@tanstack/query-core";
import { derived, type Readable, writable } from "svelte/store";
import {
getOneofValue,
valueAsNumber,
} from "@rilldata/web-common/lib/proto-utils.ts";
import type {
HistogramMethod,
TimeSeriesValue,
} from "@rilldata/web-common/proto/gen/rill/runtime/v1/queries_pb.ts";

export function isFetching(...queries) {
return queries.some((query) => query?.isFetching);
Expand Down Expand Up @@ -81,7 +87,11 @@ export function getSummaries(
return {
...col,
nullCount: nullValues?.data?.count,
cardinality: cardinality?.data?.categoricalSummary?.cardinality,
cardinality: getOneofValue(
cardinality?.data?.categoricalSummary,
"case",
"cardinality",
),
isFetching:
profileColumnResponse.isFetching ||
nullValues?.isFetching ||
Expand Down Expand Up @@ -181,7 +191,11 @@ export function getCountDistinct(
[cardinalityQuery, totalRowsQuery],
([cardinality, totalRows]) => {
return {
cardinality: cardinality?.data?.categoricalSummary?.cardinality,
cardinality: getOneofValue(
cardinality?.data?.categoricalSummary,
"case",
"cardinality",
),
// SAFETY: if the V1TableCardinalityResponse exists in `totalRows`,
// then `.cardinality` should presumably always exist in the
// cardinality query response, so we should be able to cast it to
Expand Down Expand Up @@ -222,15 +236,16 @@ export function getTopK(
},
);
return derived(topKQuery, ($topKQuery) => {
return $topKQuery?.data?.categoricalSummary?.topK?.entries;
return getOneofValue($topKQuery?.data?.categoricalSummary, "case", "topK")
?.entries;
});
}

function convertPoint(point: V1TimeSeriesValue) {
function convertPoint(point: TimeSeriesValue) {
const next = {
...point,
count: point?.records?.count as number,
ts: point.ts ? new Date(point.ts) : new Date(0),
count: valueAsNumber(point?.records?.fields?.count),
ts: point.ts?.toDate() ?? new Date(0),
};
if (next.count == null || !isFinite(next.count)) {
next.count = 0;
Expand Down Expand Up @@ -329,7 +344,7 @@ export function getNumericHistogram(
databaseSchema: string,
objectName: string,
columnName: string,
histogramMethod: QueryServiceColumnNumericHistogramHistogramMethod,
histogramMethod: HistogramMethod,
enabled = true,
) {
return createQueryServiceColumnNumericHistogram(
Expand All @@ -346,7 +361,11 @@ export function getNumericHistogram(
{
query: {
select(query) {
return query?.numericSummary?.numericHistogramBins?.bins;
return getOneofValue(
query?.numericSummary,
"case",
"numericHistogramBins",
)?.bins;
},
enabled,
},
Expand Down
42 changes: 42 additions & 0 deletions web-common/src/lib/proto-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Value } from "node_modules/@bufbuild/protobuf/dist/esm/google/protobuf/struct_pb";

/** A protobuf-es oneof field as generated for a `case` selector. */
type OneofSelector =
| { case: string; value: unknown }
| { case: undefined; value?: undefined };
/** Keys of `M` whose value is a protobuf-es oneof selector. */
type OneofKeys<M> = {
[K in keyof M]: NonNullable<M[K]> extends OneofSelector ? K : never;
}[keyof M];
/** The set of case names available on the oneof selector `O`. */
type OneofCase<O> = O extends { case: infer C extends string } ? C : never;
/** The value type carried by the `C` case of the oneof selector `O`. */
type OneofValueForCase<O, C> = O extends { case: C; value: infer V }
? V
: never;

/**
* Returns the value of a protobuf-es oneof field for the requested case, or
* undefined if the oneof is unset or set to a different case. `oneofKey` selects
* the oneof field (e.g. "case" on a CategoricalSummary, "resource" on a
* Resource) and the return type is narrowed to the value type of that case.
*/
export function getOneofValue<
M extends object,
K extends OneofKeys<M>,
C extends OneofCase<NonNullable<M[K]>>,
>(
message: M | undefined,
oneofKey: K,
caseName: C,
): OneofValueForCase<NonNullable<M[K]>, C> | undefined {
const oneof = message?.[oneofKey] as OneofSelector | undefined;
if (oneof?.case !== caseName) {
return undefined;
}
return oneof.value as OneofValueForCase<NonNullable<M[K]>, C>;
}

export function valueAsNumber(val: Value | undefined) {
return getOneofValue(val, "kind", "numberValue") ?? 0;
}
Loading
Loading