Skip to content

Instantly share code, notes, and snippets.

@jmakeig
Last active October 6, 2025 01:45
Show Gist options
  • Save jmakeig/d8db1a0c517070bc3013777242d3fa08 to your computer and use it in GitHub Desktop.
Save jmakeig/d8db1a0c517070bc3013777242d3fa08 to your computer and use it in GitHub Desktop.
Pipeline entity model
declare const IDBrand: unique symbol;
type ID = string & { [IDBrand]: void };
/**
* Allows for each property’s original type or string.
* This is useful for accepting values from HTML forms,
* which only allow string inputs.
*/
type Stringish<T> = {
[p in keyof T]: T[p] | string;
};
/**
* Exclusive or: one or the other property, but not both.
*/
type XOR<T, U> =
| (T & { [K in Exclude<keyof U, keyof T>]?: never })
| (U & { [K in Exclude<keyof T, keyof U>]?: never });
/**
* Given a static object, return a union type with any of its key-value combinations.
*/
type OneOf<T extends Record<PropertyKey, unknown>> = {
[K in keyof T]: { [P in K]: T[P] }
}[keyof T];
type Tracked = {
created_at: Date;
updated_at: Date;
}
type Pending<Entity> = {
// [P in keyof Entity]?:
// Entity[P] extends object
// ? Pending<Entity[P]>
// : Entity[P] | string | null;
[P in keyof Entity]?: Entity[P] | string | null;
};
/**
* Adds a snake_case prefix to every key.
* `as` renames the property.
*/
type Prefix<T, P extends string> = {
[K in keyof T & string as `${P}_${K}`]: T[K];
};
/*****************************************/
namespace Pipeline {
export type Customer = {
customer: ID;
label: string;
name: string;
description: string | null;
region: Region | null;
segment: Segment | null;
workloads: Omit<Workload, 'customer'>[];
events: Omit<Event, 'customer'>[];
} & Tracked;
export type Workload = {
workload: ID;
label: string;
name: string;
description: string | null;
customer: Omit<Customer, 'workloads'> ;
stage: Stage | null;
size: number | null;
engagement_lead: Participant | null;
events: Omit<Event, 'customer' | 'workload'>[];
} & Tracked;
export type Event = (
XOR<{ workload: Omit<Workload, 'events'>; } & WorkloadAction, { customer: Omit<Customer, 'events'>; }>
)
& {
happened_at: Date;
outcome: string;
notes: string | null;
team_participants: Participant[] | null;
field_participants: Participant[] | null;
};
export type WorkloadAction = Partial<Prefix<Pick<Workload, 'stage' | 'size' | 'engagement_lead'>, 'update'>>;
type Participant = {
user: string;
name: string;
}
const Regions = {
'NORTHAM': 'North America',
'EMEA': 'Europe and Middle East',
'LATAM': 'Latin America',
'JAPAC': 'Japan and Asia Pacific'
} as const;
export type Region = OneOf<typeof Regions>;
export const Stages = {
0: 'Qualify',
1: 'Refine',
2: 'Tech Eval/Solution Dev',
3: 'Proposal Negotiation',
4: 'Migration/Implementation',
5: 'Live/Production',
97: 'Qualified Out',
98: 'Stalled',
99: 'Lost',
100: 'Closed',
101: 'Deleted'
} as const;
export type Stage = OneOf<typeof Stages>;
export const Segments = {
0: 'Select',
1: 'Enterprise',
2: 'Corporate',
3: 'SMB'
} as const;
export type Segment = OneOf<typeof Segments>;
}
const segment_good : Pipeline.Segment = { 1: 'Enterprise' };
//@ts-expect-error
const segment_bad1 : Pipeline.Segment = { 0: 'Enterprise' };
//@ts-expect-error
const segment_bad2 : Pipeline.Segment = { 99: 'Other' };
const acme : Pipeline.Customer = {
customer: '123' as ID,
label: 'acme',
name: 'Acme Corp.',
description: null,
region: null,
segment: { 0: 'Select'},
workloads: [],
events: [],
created_at: new Date(),
updated_at: new Date()
}
const acme_child = {
customer: '123' as ID,
label: 'acme',
name: 'Acme Corp.',
description: null,
region: { 'LATAM': 'Latin America'},
segment: null,
// workloads: [],
events: [],
created_at: new Date(),
updated_at: new Date()
}
const new_customer : Pending<Pipeline.Customer> = {
label: 'acme',
name: 'Acme Corp.'
};
const starline : Pipeline.Workload = {
workload: 'abc' as ID,
label: 'starline',
name: 'Straline',
description: null,
customer:
{
customer: '123' as ID,
label: 'acme',
name: 'Acme Corp.',
description: null,
region: null,
segment: null,
//workloads: [], // Explicitly prohibited above
events: [],
created_at: new Date(),
updated_at: new Date()
},
stage: {0: 'Qualify'},
size: null,
engagement_lead: null,
events: [
{
outcome: 'Event nested in Workload',
happened_at: new Date(),
team_participants: null,
field_participants: null,
notes: null
}
],
created_at: new Date(),
updated_at: new Date()
};
const event_workload : Pipeline.Event = {
workload: starline,
outcome: 'asdf',
happened_at: new Date(),
notes: null,
team_participants: null,
field_participants: null
};
const event_customer : Pipeline.Event = {
customer: acme,
outcome: 'asdf',
happened_at: new Date(),
notes: null,
team_participants: null,
field_participants: null
};
//@ts-expect-error Missing one of customer or workload
const event_customer_missing : Pipeline.Event = {
outcome: 'asdf',
happened_at: new Date(),
notes: null,
team_participants: null,
field_participants: null
};
//@ts-expect-error Mismatch between customer and workload_action
const event_customer_mismatch : Pipeline.Event = {
outcome: 'asdf',
happened_at: new Date(),
notes: null,
team_participants: null,
field_participants: null,
customer: acme,
update_size: 100
};
const event_pending : Pending<Pipeline.Event> = {
workload: 'asdf',
outcome: null,
happened_at: 'today',
update_size: 100,
update_stage: '0'
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment