Skip to content

Commit

Permalink
Improve inferred types for _raw property (#820)
Browse files Browse the repository at this point in the history
This PR makes improvements regarding the `_raw` property of `Document`
instances (which also impacts `Model` since it extends `Document`).

The following changes are included:
- `DocumentData` will now include the `_raw` property if the schema is
null
- `DocumentCompositeValue` will now include the `_raw` property if the
schema is null
- `InferDocumentObject` now accepts a `null` schema in its generic. If
the schema is `null` then the `_raw` property will be included on the
inferred output
- `InferModelObject` now accepts a `null` schema in its generic. If the
schema is `null` then the `_raw` property will be included on the
inferred output
  • Loading branch information
shawnmcknight authored Oct 29, 2024
1 parent 4b04f2e commit bbdaef6
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 21 deletions.
11 changes: 5 additions & 6 deletions src/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import type { DbServerDelimiters, DeepOptionalNullable, MvRecord } from './types

// #region Types
/** Type of data property for constructing a document dependent upon the schema */
export type DocumentData<TSchema extends Schema | null> = TSchema extends Schema
? DeepOptionalNullable<InferDocumentObject<TSchema>>
: never;
export type DocumentData<TSchema extends Schema | null> = DeepOptionalNullable<
InferDocumentObject<TSchema>
>;

export interface DocumentConstructorOptions<TSchema extends Schema | null> {
data?: DocumentData<TSchema>;
Expand All @@ -27,9 +27,8 @@ export interface BuildForeignKeyDefinitionsResult {
* An intersection type that combines the `Document` class instance with the
* inferred shape of the document object based on the schema definition.
*/
export type DocumentCompositeValue<TSchema extends Schema | null> = TSchema extends Schema
? Document<TSchema> & InferDocumentObject<TSchema>
: Document<TSchema>;
export type DocumentCompositeValue<TSchema extends Schema | null> = Document<TSchema> &
InferDocumentObject<TSchema>;
// #endregion

/** A document object */
Expand Down
7 changes: 4 additions & 3 deletions src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type {
ISOCalendarDateTime,
ISOTime,
MarkRequired,
MvRecord,
Remap,
} from './types';

Expand Down Expand Up @@ -152,17 +153,17 @@ type InferSchemaType<TSchemaTypeDefinition, TConstraint> =
*
* Allows a constraint to be specified to filter the output to only include properties of a specific type
*/
export type InferDocumentObject<TSchema extends Schema, TConstraint = SchemaTypeDefinition> =
export type InferDocumentObject<TSchema extends Schema | null, TConstraint = SchemaTypeDefinition> =
TSchema extends Schema<infer TSchemaDefinition>
? {
[K in keyof TSchemaDefinition as TSchemaDefinition[K] extends TConstraint
? K
: never]: InferSchemaType<TSchemaDefinition[K], TConstraint>;
}
: never;
: { _raw: MvRecord };

/** Infer the shape of a `Model` instance based upon the Schema it was instantiated with */
export type InferModelObject<TSchema extends Schema> = Remap<
export type InferModelObject<TSchema extends Schema | null> = Remap<
InferDocumentObject<TSchema> & RequiredModelMeta
>;

Expand Down
5 changes: 5 additions & 0 deletions src/__tests__/Document.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1133,5 +1133,10 @@ describe('utility types', () => {
> = true;
expect(test1).toBe(true);
});

test('should have a _raw property if schema is null', () => {
const test1: Equals<DocumentData<null>, { _raw: MvRecord }> = true;
expect(test1).toBe(true);
});
});
});
25 changes: 19 additions & 6 deletions src/__tests__/Schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
NumberType,
StringType,
} from '../schemaType';
import type { Equals, ISOCalendarDate, ISOCalendarDateTime, ISOTime } from '../types';
import type { Equals, ISOCalendarDate, ISOCalendarDateTime, ISOTime, MvRecord } from '../types';

describe('constructor', () => {
describe('errors', () => {
Expand Down Expand Up @@ -828,6 +828,13 @@ describe('utility types', () => {
expect(test1).toBe(true);
});
});

describe('null schema', () => {
test('should have the _raw property', () => {
const test1: Equals<InferDocumentObject<null>, { _raw: MvRecord }> = true;
expect(test1).toBe(true);
});
});
});

describe('InferModelObject', () => {
Expand Down Expand Up @@ -931,11 +938,7 @@ describe('utility types', () => {
const schema1 = new Schema({ isoTimeProp: { type: 'ISOTime', path: '1' } });
const test1: Equals<
InferModelObject<typeof schema1>,
{
_id: string;
__v: string;
isoTimeProp: ISOTime | null;
}
{ _id: string; __v: string; isoTimeProp: ISOTime | null }
> = true;
expect(test1).toBe(true);

Expand Down Expand Up @@ -1250,6 +1253,16 @@ describe('utility types', () => {
expect(test1).toBe(true);
});
});

describe('null schema', () => {
test('should have the _raw property', () => {
const test1: Equals<
InferModelObject<null>,
{ _id: string; __v: string; _raw: MvRecord }
> = true;
expect(test1).toBe(true);
});
});
});

describe('FlattenDocument', () => {
Expand Down
12 changes: 6 additions & 6 deletions src/compileModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ export type ModelConstructor<TSchema extends Schema | null> = ReturnType<

export type Model<TSchema extends Schema | null> = InstanceType<ModelConstructor<TSchema>>;

/** Used as an intersection type to make _id & __v properties required */
export interface RequiredModelMeta {
_id: string;
__v: string;
}
type RequiredModelMetaProperties = '_id' | '__v';
/** Used as an intersection type to make specific model properties required */
export type RequiredModelMeta = {
[K in RequiredModelMetaProperties]: NonNullable<Model<Schema>[K]>;
};

/**
* An intersection type that combines the `Model` class instance with the
* inferred shape of the model object based on the schema definition.
*/
export type ModelCompositeValue<TSchema extends Schema | null> = Remap<
Model<TSchema> & (TSchema extends Schema ? InferModelObject<TSchema> : RequiredModelMeta)
Model<TSchema> & InferModelObject<TSchema>
>;

export interface ModelFindAndCountResult<TSchema extends Schema | null> {
Expand Down

0 comments on commit bbdaef6

Please sign in to comment.