refactor: unify source types and remove ambiguity#1194
Conversation
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
E2E Test Results✅ All tests passed • 25 passed • 3 skipped • 226s
|
| export function createSource(team: string, source: Omit<ISource, 'id'>) { | ||
| return Source.create({ ...source, team }); | ||
| switch (source.kind) { | ||
| case SourceKind.Log: | ||
| return LogSource.create({ ...source, team }); | ||
| case SourceKind.Trace: | ||
| return TraceSource.create({ ...source, team }); | ||
| case SourceKind.Metric: | ||
| return MetricSource.create({ ...source, team }); | ||
| case SourceKind.Session: | ||
| return SessionSource.create({ ...source, team }); | ||
| } |
There was a problem hiding this comment.
Mongoose will strip out any unnecessary fields, so create source must use the new broken out discriminated models
| switch (source.kind) { | ||
| case SourceKind.Log: | ||
| return LogSource.findOneAndUpdate({ _id: sourceId, team }, source, { | ||
| new: true, | ||
| }); | ||
| case SourceKind.Trace: | ||
| return TraceSource.findOneAndUpdate({ _id: sourceId, team }, source, { | ||
| new: true, | ||
| }); | ||
| case SourceKind.Metric: | ||
| return MetricSource.findOneAndUpdate({ _id: sourceId, team }, source, { | ||
| new: true, | ||
| }); | ||
| case SourceKind.Session: | ||
| return SessionSource.findOneAndUpdate({ _id: sourceId, team }, source, { | ||
| new: true, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Same, using discriminated models
| durationPrecision: Number, | ||
| parentSpanIdExpression: String, | ||
| spanNameExpression: String, | ||
| export const LogSource = Source.discriminator< |
There was a problem hiding this comment.
Broke out the mongoose models into the base model (Source) and a discriminated model for each type
| @@ -1,10 +1,10 @@ | |||
| import { SourceKind, TSourceUnion } from '@hyperdx/common-utils/dist/types'; | |||
| import { SourceKind, TSource } from '@hyperdx/common-utils/dist/types'; | |||
There was a problem hiding this comment.
TSourceUnion is renamed TSource
| export function useSource(params: { | ||
| id?: string | null; | ||
| connection?: string | null; | ||
| }): UseQueryResult<TSource | undefined>; | ||
| export function useSource<K extends TSource['kind']>(params: { | ||
| id?: string | null; | ||
| connection?: string | null; | ||
| kind: K; | ||
| }): UseQueryResult<Extract<TSource, { kind: K }> | undefined>; |
There was a problem hiding this comment.
The type signature without specifying kind returns the TSource type, but if you specify kind then the type signature understands the returned source is a particular kind. Super useful if you always know you'll be using a specific kind of source
| mutationFn: async ({ source }: { source: Omit<TSource, 'id'> }) => { | ||
| mutationFn: async ({ source }: { source: TSourceNoId }) => { |
There was a problem hiding this comment.
TS's built in Omit does not work well with discriminated unions, so it's better to construct with zod and type assert.
|
The refactoring makes me a bit nervous, as the changes affect the core of the entire app and I’m not very confident in our test coverage in this area. To minimize the risk of breaking existing behavior, I’d suggest migrating to the new sources model gradually, one source type at a time. If it’s not that easy, I’d recommend adding more unit tests for different sources. Overall, I really like these changes, which will help us catch more source type–related bugs :) |
| return LogSource.create({ ...source, team }); | ||
| case SourceKind.Trace: | ||
| return TraceSource.create({ ...source, team }); | ||
| case SourceKind.Metric: | ||
| return MetricSource.create({ ...source, team }); | ||
| case SourceKind.Session: | ||
| return SessionSource.create({ ...source, team }); |
There was a problem hiding this comment.
we should also handle default case
| export const SessionSource = Source.discriminator< | ||
| Extract<TSource, { kind: SourceKind.Session }> | ||
| >( | ||
| SourceKind.Session, | ||
| new mongoose.Schema<Extract<TSource, { kind: SourceKind.Session }>>({ | ||
| traceSourceId: String, | ||
| }), | ||
| ); |
There was a problem hiding this comment.
Will those non-public fields (e.g., ResourceAttributes) be inserted or updated?
There was a problem hiding this comment.
Let's talk about the requirements for Sessions, because ResourceAttributes isn't currently listed in the schema
There was a problem hiding this comment.
Hmm you are right. Sorry, I was thinking about the different thing. The mapping should only require a few fields
| case SourceKind.Log: | ||
| return s.toJSON({ getters: true }); | ||
| case SourceKind.Trace: | ||
| return s.toJSON({ getters: true }); | ||
| case SourceKind.Metric: | ||
| return s.toJSON({ getters: true }); | ||
| case SourceKind.Session: | ||
| return s.toJSON({ getters: true }); |
There was a problem hiding this comment.
nit: this can be
case SourceKind.Log:
case SourceKind.Trace:
case SourceKind.Metric:
case SourceKind.Session:
return s.toJSON({ getters: true });
also we need to handle default case
There was a problem hiding this comment.
For some reason Typescript gets confused about the union so that does not work, it has to be broken out like this. I'll add an error for the default case
| const { data: logSource, isLoading: isLogSourceLoading } = useSource({ | ||
| id: source, | ||
| kind: SourceKind.Log, | ||
| }); | ||
| const { data: traceSource, isLoading: isTraceSourceLoading } = useSource({ | ||
| id: source, | ||
| kind: SourceKind.Trace, | ||
| }); |
There was a problem hiding this comment.
Is there any chance we could avoid duplicate requests here? I see the point, but the source ID should already give us the right source
There was a problem hiding this comment.
Under the hood they all are using the same query key to fetch all the sources and then just running find over the elements of the array. They are using the same query key, so only one request should be generated
Unfortunately it is not easy. More unit tests makes sense, I'll seek guidance for which ones specifically we are interested in |
|
Closed due to staleness. Please re-open with updates if needed. |
Closes HDX-2468