Skip to content

Commit

Permalink
rework types
Browse files Browse the repository at this point in the history
  • Loading branch information
wesselvdv committed Oct 4, 2023
1 parent d262f40 commit 166fe5f
Show file tree
Hide file tree
Showing 5 changed files with 622 additions and 523 deletions.
177 changes: 84 additions & 93 deletions grafast/dataplan-pg/src/codecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ import {
import type { PgExecutor } from "./executor.js";
import { inspect } from "./inspect.js";
import type {
AnyPgCodec,
PgCodec,
PgCodecAttributes,
PgCodecAttributesRecord,
PgCodecExtensions,
PgCodecFromPostgres,
PgCodecPolymorphism,
PgDecode,
PgEncode,
Expand All @@ -59,10 +63,21 @@ export type PgCodecAttributeVia = string | PgCodecAttributeViaExplicit;
/** @deprecated Use DataplanPg.PgCodecAttributeExtensions instead */
export type PgCodecAttributeExtensions = DataplanPg.PgCodecAttributeExtensions;

export type AnyPgCodecAttribute = PgCodecAttribute<any, any, any>;
export type PgCodecAttributeName<U> = U extends PgCodecAttribute<
infer TName,
any,
any
>
? TName
: never;

export interface PgCodecAttribute<
TCodec extends PgCodec = PgCodec,
TNotNull extends boolean = boolean,
TName extends string,
TCodec extends AnyPgCodec,
TNotNull extends boolean,
> {
name: TName;
/**
* How to translate to/from PG and how to cast.
*/
Expand Down Expand Up @@ -129,14 +144,6 @@ export interface PgCodecAttribute<
extensions?: Partial<PgCodecAttributeExtensions>;
}

export type PgCodecAttributes<
TCodecMap extends {
[attributeName in string]: PgCodecAttribute;
} = {
[attributeName in string]: PgCodecAttribute;
},
> = TCodecMap;

/**
* Returns a PgCodec for the given builtin Postgres scalar type, optionally
* pass the following config:
Expand All @@ -160,12 +167,12 @@ function t<TFromJavaScript = any, TFromPostgres = string>(): <
options?: Cast<TFromJavaScript, TFromPostgres>,
) => PgCodec<
TName,
undefined,
never,
TFromPostgres,
TFromJavaScript,
undefined,
undefined,
undefined
never,
never,
never
> {
return (oid, type, options = {}) => {
const { castFromPg, listCastFromPg, fromPg, toPg, isBinary } = options;
Expand All @@ -174,7 +181,6 @@ function t<TFromJavaScript = any, TFromPostgres = string>(): <
sqlType: sql.identifier(...type.split(".")),
fromPg: fromPg ?? (identity as any),
toPg: toPg ?? (identity as any),
attributes: undefined,
extensions: { oid: oid },
castFromPg,
listCastFromPg,
Expand Down Expand Up @@ -318,11 +324,13 @@ function recordStringToTuple(value: string): Array<string | null> {
return tuple;
}

function realAttributeDefs<TAttributes extends PgCodecAttributes>(
attributes: TAttributes,
): Array<[string, TAttributes[keyof TAttributes]]> {
function realAttributeDefs<
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
>(
attributes: PgCodecAttributesRecord<TAttributes>,
): Array<[PgCodecAttributeName<TAttributes[number]>, TAttributes[number]]> {
const attributeDefs = Object.entries(attributes) as Array<
[string, TAttributes extends infer U ? U[keyof U] : never]
[PgCodecAttributeName<TAttributes[number]>, TAttributes[number]]
>;
return attributeDefs.filter(
([_attributeName, spec]) => !spec.expression && !spec.via,
Expand All @@ -336,8 +344,10 @@ function realAttributeDefs<TAttributes extends PgCodecAttributes>(
*
* @see {@link https://www.postgresql.org/docs/current/rowtypes.html#id-1.5.7.24.6}
*/
function makeRecordToSQLRawValue<TAttributes extends PgCodecAttributes>(
attributes: TAttributes,
function makeRecordToSQLRawValue<
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
>(
attributes: PgCodecAttributesRecord<TAttributes>,
): PgEncode<ObjectFromPgCodecAttributes<TAttributes>> {
const attributeDefs = realAttributeDefs(attributes);
return (value) => {
Expand All @@ -350,19 +360,21 @@ function makeRecordToSQLRawValue<TAttributes extends PgCodecAttributes>(
};
}

export type ObjectFromPgCodecAttributes<TAttributes extends PgCodecAttributes> =
{
[attributeName in keyof TAttributes]: TAttributes[attributeName] extends PgCodecAttribute<
infer UCodec,
infer UNonNull
>
? UCodec extends PgCodec<any, any, any, infer UFromJs, any, any, any>
? UNonNull extends true
? Exclude<UFromJs, null | undefined>
: UFromJs | null
: never
: never;
};
export type ObjectFromPgCodecAttributes<
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
> = {
[TCodecAttribute in TAttributes[number] as PgCodecAttributeName<TCodecAttribute>]: TCodecAttribute extends PgCodecAttribute<
any,
infer UCodec,
infer UNonNull
>
? UCodec extends PgCodec<any, any, any, infer UFromJs, any, any, any>
? UNonNull extends true
? Exclude<UFromJs, null | undefined>
: UFromJs | null
: never
: never;
};

/**
* Takes a list of attributes and returns a mapping function that takes a
Expand All @@ -371,8 +383,10 @@ export type ObjectFromPgCodecAttributes<TAttributes extends PgCodecAttributes> =
*
* @see {@link https://www.postgresql.org/docs/current/rowtypes.html#id-1.5.7.24.6}
*/
function makeSQLValueToRecord<TAttributes extends PgCodecAttributes>(
attributes: TAttributes,
function makeSQLValueToRecord<
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
>(
attributes: PgCodecAttributesRecord<TAttributes>,
): (value: string) => ObjectFromPgCodecAttributes<TAttributes> {
const attributeDefs = realAttributeDefs(attributes);
const attributeCount = attributeDefs.length;
Expand All @@ -390,12 +404,12 @@ function makeSQLValueToRecord<TAttributes extends PgCodecAttributes>(

export type PgRecordTypeCodecSpec<
TName extends string,
TAttributes extends PgCodecAttributes,
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
> = {
name: TName;
executor: PgExecutor;
identifier: SQL;
attributes: TAttributes;
attributes: PgCodecAttributesRecord<TAttributes>;
polymorphism?: PgCodecPolymorphism<any>;
description?: string;
extensions?: Partial<PgCodecExtensions>;
Expand All @@ -413,18 +427,18 @@ export type PgRecordTypeCodecSpec<
* isAnonymous - if true, this represents an "anonymous" type, typically the return value of a function or something like that. If this is true, then name and identifier are ignored.
*/
export function recordCodec<
const TName extends string,
const TAttributes extends PgCodecAttributes,
TName extends string,
TAttributes extends ReadonlyArray<AnyPgCodecAttribute>,
>(
config: PgRecordTypeCodecSpec<TName, TAttributes>,
): PgCodec<
TName,
TAttributes,
string,
ObjectFromPgCodecAttributes<TAttributes>,
undefined,
undefined,
undefined
never,
never,
never
> {
const {
name,
Expand Down Expand Up @@ -504,14 +518,14 @@ type CodecWithListCodec<
`${TCodec extends PgCodec<infer UName, any, any, any, any, any, any>
? UName
: never}[]`,
undefined,
never,
string,
TCodec extends PgCodec<any, any, any, infer UFromJs, undefined, any, any>
TCodec extends PgCodec<any, any, any, infer UFromJs, never, any, any>
? UFromJs[]
: any[],
TCodec,
undefined,
undefined
never,
never
>;
};

Expand All @@ -529,7 +543,7 @@ type CodecWithListCodec<
* @param identifier - a pg-sql2 fragment that represents the name of this type
*/
export function listOfCodec<
TInnerCodec extends PgCodec<string, any, any, any, undefined, any, any>,
TInnerCodec extends PgCodec<string, any, any, any, never, any, any>,
>(
listedCodec: TInnerCodec,
config?: {
Expand All @@ -542,14 +556,14 @@ export function listOfCodec<
`${TInnerCodec extends PgCodec<infer UName, any, any, any, any, any, any>
? UName
: never}[]`,
undefined, // Array has no attributes
never, // Array has no attributes
string,
TInnerCodec extends PgCodec<any, any, any, infer UFromJs, undefined, any, any>
TInnerCodec extends PgCodec<any, any, any, infer UFromJs, never, any, any>
? UFromJs[]
: any[],
TInnerCodec,
undefined,
undefined
never,
never
> {
const innerCodec: CodecWithListCodec<TInnerCodec> = listedCodec;

Expand All @@ -568,22 +582,14 @@ export function listOfCodec<
`${TInnerCodec extends PgCodec<infer UName, any, any, any, any, any, any>
? UName
: never}[]`,
undefined, // Array has no attributes
never, // Array has no attributes
string,
TInnerCodec extends PgCodec<
any,
any,
any,
infer UFromJs,
undefined,
any,
any
>
TInnerCodec extends PgCodec<any, any, any, infer UFromJs, never, any, any>
? UFromJs[]
: any[],
TInnerCodec,
undefined,
undefined
never,
never
> = {
name: `${
innerCodec.name as TInnerCodec extends PgCodec<
Expand Down Expand Up @@ -661,7 +667,7 @@ exportAs("@dataplan/pg", listOfCodec, "listOfCodec");
*/
export function domainOfCodec<
TName extends string,
TInnerCodec extends PgCodec<any, any, any, any, any, any>,
TInnerCodec extends AnyPgCodec,
>(
innerCodec: TInnerCodec,
name: TName,
Expand All @@ -673,13 +679,15 @@ export function domainOfCodec<
} = {},
): PgCodec<
TName,
TInnerCodec extends PgCodec<any, infer U, any, any, any, any> ? U : any,
TInnerCodec extends PgCodec<any, any, infer U, any, any, any> ? U : any,
undefined,
PgCodecAttributes<TInnerCodec>,
PgCodecFromPostgres<TInnerCodec>,
any,
TInnerCodec,
undefined
never,
any
> {
const { description, extensions, notNull } = config;

return {
// Generally same as underlying type:
...innerCodec,
Expand All @@ -689,7 +697,7 @@ export function domainOfCodec<
sqlType: identifier,
description,
extensions,
domainOfCodec: innerCodec.arrayOfCodec ? undefined : innerCodec,
...(innerCodec.arrayOfCodec ? {} : { domainOfCodec: innerCodec }),
notNull: Boolean(notNull),
};
}
Expand All @@ -701,7 +709,7 @@ exportAs("@dataplan/pg", domainOfCodec, "domainOfCodec");
* @internal
*/
function escapeRangeValue<
TInnerCodec extends PgCodec<any, undefined, any, any, undefined, any, any>,
TInnerCodec extends PgCodec<any, never, any, any, never, any, any>,
>(value: null | any, innerCodec: TInnerCodec): string {
if (value == null) {
return "";
Expand All @@ -727,15 +735,7 @@ interface PgRange<T> {
*/
export function rangeOfCodec<
TName extends string,
TInnerCodec extends PgCodec<
any,
undefined,
any,
any,
undefined,
any,
undefined
>,
TInnerCodec extends PgCodec<any, never, any, any, never, any, never>,
>(
innerCodec: TInnerCodec,
name: TName,
Expand All @@ -744,15 +744,7 @@ export function rangeOfCodec<
description?: string;
extensions?: Partial<PgCodecExtensions>;
} = {},
): PgCodec<
TName,
undefined,
string,
PgRange<unknown>,
undefined,
undefined,
TInnerCodec
> {
): PgCodec<TName, never, string, PgRange<unknown>, never, never, TInnerCodec> {
const { description, extensions } = config;
const needsCast = innerCodec.castFromPg;

Expand Down Expand Up @@ -1169,17 +1161,16 @@ export function getCodecByPgCatalogTypeName(pgCatalogTypeName: string) {
return null;
}

export function getInnerCodec<
TCodec extends PgCodec<any, any, any, any, any, any>,
>(
export function getInnerCodec<TCodec extends AnyPgCodec>(
codec: TCodec,
): TCodec extends PgCodec<
any,
any,
any,
infer UArray,
infer UDomain,
infer URange
infer URange,
any
>
? Exclude<UDomain | UArray | URange, undefined>
: TCodec {
Expand Down
Loading

0 comments on commit 166fe5f

Please sign in to comment.