Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix typeof Model errors throughout by using typeof Model generics #900

Merged
merged 9 commits into from
Feb 14, 2021
24 changes: 12 additions & 12 deletions src/associations/belongs-to-many/belongs-to-many-association.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import {BelongsToManyOptions as OriginBelongsToManyOptions, Model, ThroughOptions} from "sequelize";

import {BaseAssociation} from '../shared/base-association';
import {BelongsToManyOptions} from './belongs-to-many-options';
import {ModelNotInitializedError} from '../../model/shared/model-not-initialized-error';
Expand All @@ -8,44 +6,46 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {Association} from "../shared/association";
import {Sequelize} from "../../sequelize/sequelize/sequelize";
import {UnionAssociationOptions} from "../shared/union-association-options";
import {ModelType} from "../../model/model/model";
import {ThroughOptions} from "../through/through-options";

export class BelongsToManyAssociation extends BaseAssociation {
export class BelongsToManyAssociation<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough> extends BaseAssociation<TCreationAttributes, TModelAttributes> {

constructor(associatedClassGetter: ModelClassGetter,
protected options: BelongsToManyOptions) {
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
protected options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>) {
super(associatedClassGetter, options);
}

getAssociation(): Association {
return Association.BelongsToMany;
}

getSequelizeOptions(model: typeof Model,
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>,
sequelize: Sequelize): UnionAssociationOptions {
const options: OriginBelongsToManyOptions = {...this.options as any};
const options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough> = {...this.options};
const associatedClass = this.getAssociatedClass();
const throughOptions = this.getThroughOptions(sequelize);

const throughModel = typeof throughOptions === 'object' && typeof throughOptions.model !== "string" ? throughOptions.model : undefined;
options.through = throughOptions;
options.foreignKey = getForeignKeyOptions(model, throughModel, this.options.foreignKey);
options.otherKey = getForeignKeyOptions(associatedClass, throughModel, this.options.otherKey);
options.foreignKey = getForeignKeyOptions(model, throughModel as any, this.options.foreignKey);
options.otherKey = getForeignKeyOptions(associatedClass, throughModel as any, this.options.otherKey);
theoludwig marked this conversation as resolved.
Show resolved Hide resolved

return options;
}

private getThroughOptions(sequelize: Sequelize): ThroughOptions | string {
private getThroughOptions(sequelize: Sequelize): ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough> | string {
const through = this.options.through;
const throughModel = typeof through === 'object' ? through.model : through;
const throughOptions: ThroughOptions =
const throughOptions: ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough> =
typeof through === 'object' ? {...through} : {} as any;

if (typeof throughModel === 'function') {
const throughModelClass = sequelize.model(throughModel());
if (!throughModelClass.isInitialized) {
throw new ModelNotInitializedError(throughModelClass, 'Association cannot be resolved.');
}
throughOptions.model = throughModelClass;
throughOptions.model = throughModelClass as any;
} else {
return throughModel;
}
Expand Down
4 changes: 2 additions & 2 deletions src/associations/belongs-to-many/belongs-to-many-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {ThroughOptions} from "../through/through-options";


export type BelongsToManyOptions = {
export type BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough> = {
[K in keyof OriginBelongsToManyOptions]: K extends 'through'
? ModelClassGetter | string | ThroughOptions
? ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string | ThroughOptions<TCreationAttributesThrough, TModelAttributesThrough>
: OriginBelongsToManyOptions[K]
};
25 changes: 13 additions & 12 deletions src/associations/belongs-to-many/belongs-to-many.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ import {BelongsToManyAssociation} from './belongs-to-many-association';
import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {addAssociation} from "../shared/association-service";

export function BelongsToMany(associatedClassGetter: ModelClassGetter,
through: ModelClassGetter | string,
foreignKey?: string,
otherKey?: string): Function;
export function BelongsToMany(associatedClassGetter: ModelClassGetter,
options: BelongsToManyOptions): Function;
export function BelongsToMany(associatedClassGetter: ModelClassGetter,
throughOrOptions: ModelClassGetter | string | BelongsToManyOptions,
foreignKey?: string,
otherKey?: string): Function {
export function BelongsToMany<
TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
through: ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string,
foreignKey?: string,
otherKey?: string): Function;
export function BelongsToMany<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
options: BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>): Function;
export function BelongsToMany<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
throughOrOptions: ModelClassGetter<TCreationAttributesThrough, TModelAttributesThrough> | string | BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>,
foreignKey?: string,
otherKey?: string): Function {

return (target: any, propertyName: string) => {
let options: Partial<BelongsToManyOptions> = {foreignKey, otherKey};
let options: Partial<BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>> = {foreignKey, otherKey};

if (typeof throughOrOptions === 'string' ||
typeof throughOrOptions === 'function') {
Expand All @@ -28,7 +29,7 @@ export function BelongsToMany(associatedClassGetter: ModelClassGetter,

addAssociation(target, new BelongsToManyAssociation(
associatedClassGetter,
options as BelongsToManyOptions,
options as BelongsToManyOptions<TCreationAttributesThrough, TModelAttributesThrough>,
)
);
};
Expand Down
8 changes: 4 additions & 4 deletions src/associations/belongs-to/belongs-to-association.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import {BaseAssociation} from '../shared/base-association';
import {getForeignKeyOptions} from "../foreign-key/foreign-key-service";
import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {Association} from "../shared/association";
import {Model} from "../../model/model/model";
import {ModelType} from "../../model/model/model";
import {UnionAssociationOptions} from "../shared/union-association-options";

export class BelongsToAssociation extends BaseAssociation {
export class BelongsToAssociation<TCreationAttributes, TModelAttributes> extends BaseAssociation<TCreationAttributes, TModelAttributes> {

constructor(associatedClassGetter: ModelClassGetter,
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
protected options: BelongsToOptions) {
super(associatedClassGetter, options);
}
Expand All @@ -18,7 +18,7 @@ export class BelongsToAssociation extends BaseAssociation {
return Association.BelongsTo;
}

getSequelizeOptions(model: typeof Model): UnionAssociationOptions {
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>): UnionAssociationOptions {
const associatedClass = this.getAssociatedClass();
const foreignKey = getForeignKeyOptions(associatedClass, model, this.options.foreignKey);

Expand Down
6 changes: 3 additions & 3 deletions src/associations/belongs-to/belongs-to.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import {BelongsToAssociation} from './belongs-to-association';
import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";

export function BelongsTo(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;

export function BelongsTo(associatedClassGetter: ModelClassGetter, options?: BelongsToOptions): Function;
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: BelongsToOptions): Function;

export function BelongsTo(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | BelongsToOptions): Function {
export function BelongsTo<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | BelongsToOptions): Function {

return (target: any, propertyName: string) => {
const options: BelongsToOptions = getPreparedAssociationOptions(optionsOrForeignKey);
Expand Down
4 changes: 2 additions & 2 deletions src/associations/foreign-key/foreign-key-meta.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ModelClassGetter} from "../../model/shared/model-class-getter";

export interface ForeignKeyMeta {
export interface ForeignKeyMeta<TCreationAttributes, TModelAttributes> {

relatedClassGetter: ModelClassGetter;
relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>;
foreignKey: string;
}
17 changes: 9 additions & 8 deletions src/associations/foreign-key/foreign-key-service.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {ForeignKeyOptions, Model} from "sequelize";
import {ForeignKeyOptions} from "sequelize";

import {ForeignKeyMeta} from './foreign-key-meta';
import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {ModelType} from "../../model/model/model";

const FOREIGN_KEYS_KEY = 'sequelize:foreignKeys';

export function getForeignKeyOptions(relatedClass: typeof Model,
classWithForeignKey?: typeof Model,
foreignKey?: string | ForeignKeyOptions): ForeignKeyOptions {
export function getForeignKeyOptions<TCreationAttributes, TModelAttributes, TCreationAttributesThrough, TModelAttributesThrough>(relatedClass: ModelType<TCreationAttributes, TModelAttributes>,
classWithForeignKey?: ModelType<TCreationAttributesThrough, TModelAttributesThrough>,
foreignKey?: string | ForeignKeyOptions): ForeignKeyOptions {
let foreignKeyOptions: ForeignKeyOptions = {};

if (typeof foreignKey === 'string') {
Expand Down Expand Up @@ -36,9 +37,9 @@ export function getForeignKeyOptions(relatedClass: typeof Model,
/**
* Adds foreign key meta data for specified class
*/
export function addForeignKey(target: any,
relatedClassGetter: ModelClassGetter,
foreignKey: string): void {
export function addForeignKey<TCreationAttributes, TModelAttributes>(target: any,
relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
foreignKey: string): void {
let foreignKeys = getForeignKeys(target);
if (!foreignKeys) {
foreignKeys = [];
Expand All @@ -53,7 +54,7 @@ export function addForeignKey(target: any,
/**
* Returns foreign key meta data from specified class
*/
export function getForeignKeys(target: any): ForeignKeyMeta[] | undefined {
export function getForeignKeys<TCreationAttributes, TModelAttributes>(target: any): ForeignKeyMeta<TCreationAttributes, TModelAttributes>[] | undefined {
const foreignKeys = Reflect.getMetadata(FOREIGN_KEYS_KEY, target);
if (foreignKeys) {
return [...foreignKeys];
Expand Down
2 changes: 1 addition & 1 deletion src/associations/foreign-key/foreign-key.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {addForeignKey} from "./foreign-key-service";
import {ModelClassGetter} from "../../model/shared/model-class-getter";

export function ForeignKey(relatedClassGetter: ModelClassGetter): Function {
export function ForeignKey<TCreationAttributes, TModelAttributes>(relatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>): Function {
return (target: any, propertyName: string) => {
addForeignKey(target, relatedClassGetter, propertyName);
};
Expand Down
9 changes: 5 additions & 4 deletions src/associations/has/has-association.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import {HasManyOptions, HasOneOptions, Model} from 'sequelize';
import {HasManyOptions, HasOneOptions} from 'sequelize';

import {BaseAssociation} from '../shared/base-association';
import {getForeignKeyOptions} from "../foreign-key/foreign-key-service";
import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {Association} from "../shared/association";
import {UnionAssociationOptions} from "../shared/union-association-options";
import {ModelType} from '../../model/model/model';

export class HasAssociation extends BaseAssociation {
export class HasAssociation<TCreationAttributes, TModelAttributes> extends BaseAssociation<TCreationAttributes, TModelAttributes> {

constructor(associatedClassGetter: ModelClassGetter,
constructor(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>,
protected options: HasManyOptions | HasOneOptions,
private association: Association) {
super(associatedClassGetter, options);
Expand All @@ -18,7 +19,7 @@ export class HasAssociation extends BaseAssociation {
return this.association;
}

getSequelizeOptions(model: typeof Model): UnionAssociationOptions {
getSequelizeOptions(model: ModelType<TCreationAttributes, TModelAttributes>): UnionAssociationOptions {
const options = {...this.options};
const associatedClass = this.getAssociatedClass();

Expand Down
6 changes: 3 additions & 3 deletions src/associations/has/has-many.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";
import {Association} from "../shared/association";

export function HasMany(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;

export function HasMany(associatedClassGetter: ModelClassGetter, options?: HasManyOptions): Function;
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: HasManyOptions): Function;

export function HasMany(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | HasManyOptions): Function {
export function HasMany<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | HasManyOptions): Function {

return (target: any, propertyName: string) => {
const options: HasManyOptions = getPreparedAssociationOptions(optionsOrForeignKey);
Expand Down
6 changes: 3 additions & 3 deletions src/associations/has/has-one.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {ModelClassGetter} from "../../model/shared/model-class-getter";
import {addAssociation, getPreparedAssociationOptions} from "../shared/association-service";
import {Association} from "../shared/association";

export function HasOne(associatedClassGetter: ModelClassGetter, foreignKey?: string): Function;
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, foreignKey?: string): Function;

export function HasOne(associatedClassGetter: ModelClassGetter, options?: HasOneOptions): Function;
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, options?: HasOneOptions): Function;

export function HasOne(associatedClassGetter: ModelClassGetter, optionsOrForeignKey?: string | HasOneOptions): Function {
export function HasOne<TCreationAttributes, TModelAttributes>(associatedClassGetter: ModelClassGetter<TCreationAttributes, TModelAttributes>, optionsOrForeignKey?: string | HasOneOptions): Function {

return (target: any, propertyName: string) => {
const options: HasOneOptions = getPreparedAssociationOptions(optionsOrForeignKey);
Expand Down
14 changes: 7 additions & 7 deletions src/associations/shared/association-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export function getPreparedAssociationOptions(optionsOrForeignKey?: string | Non
/**
* Stores association meta data for specified class
*/
export function addAssociation(target: any,
association: BaseAssociation) {
export function addAssociation<TCreationAttributes, TModelAttributes>(target: any,
association: BaseAssociation<TCreationAttributes, TModelAttributes>) {

let associations = getAssociations(target);

Expand All @@ -42,20 +42,20 @@ export function addAssociation(target: any,
/**
* Returns association meta data from specified class
*/
export function getAssociations(target: any): BaseAssociation[] | undefined {
export function getAssociations<TCreationAttributes, TModelAttributes>(target: any): BaseAssociation<TCreationAttributes, TModelAttributes>[] | undefined {
const associations = Reflect.getMetadata(ASSOCIATIONS_KEY, target);
if (associations) {
return [...associations];
}
}

export function setAssociations(target: any, associations: BaseAssociation[]) {
export function setAssociations<TCreationAttributes, TModelAttributes>(target: any, associations: BaseAssociation<TCreationAttributes, TModelAttributes>[]) {
Reflect.defineMetadata(ASSOCIATIONS_KEY, associations, target);
}

export function getAssociationsByRelation(target: any,
relatedClass: any): BaseAssociation[] {
const associations = getAssociations(target);
export function getAssociationsByRelation<TCreationAttributes, TModelAttributes>(target: any,
relatedClass: any): BaseAssociation<TCreationAttributes, TModelAttributes>[] {
const associations = getAssociations<TCreationAttributes, TModelAttributes>(target);
return (associations || []).filter(association => {
const _relatedClass = association.getAssociatedClass();
return (
Expand Down
Loading