Scoped classes incorrectly generate GraphQL schema as JSON
Bug Report
Current Behavior
If one tries to use a scoped class in a read model/command, Metadata Booster will incorrectly generate the type as JSON, instead of the proper schema. E.g.
import * as A from './a'
@ReadModel({
authorize: 'all',
})
export class B {
public constructor(public id: UUID, readonly list: Array<A.DTO>) {}
}
Will generate a the list type as:
list: [JSON!]!
Where as if we change the import to:
import { DTO } from './a'
It will generate the type properly.
Expected behavior
Metadata Booster should be able to generate the type correctly even if the class is scoped.
Possible Solution
Probably add a case to Metadata Booster to process scoped types properly.
Additional information
Environment
- Booster version: 0.30.6
- Node version: 16.14
—
Created via Raycast
After experimenting with this for a while, it seems to me that the import (qualified or scoped) is not actually the issue. The issue is, that it seems to be mandatory to decorate the DTO classes with @ReadModel if you import it (in a qualified OR unqualified way).
// file: src/read-modles/a.ts
export class DTO_Undecorated {
public constructor(id: UUID, propPublic: string)
}
@ReadModel()
export class DTO_Decorated {
public constructor(id: UUID, propPublic: string)
}
// file: src/read-models/b.ts
import * as A from './a1'
import { DTO_Undecorated, DTO_Decorated } from './a2'
export class B1 { public constructor(x: A.DTO_Undecorated[]) } // type: JSON[]
export class B2 { public constructor(x: DTO_Undecorated[]) } // type: JSON[]
export class B3 { public constructor(x: A.DTO_Decorated[]) } // type: DTO_Decorated[]
export class B4 { public constructor(x: DTO_Decorated[]) } // type: DTO_Decorated[]
Now interestingly, it is only mandatory to decorate the class if it is imported, i.e. if the class is defined in the same file it does not have to decorated.
// file: src/read-models/b.ts
export class DTO_Undecorated {
public constructor(id: UUID, propPublic: string)
}
@ReadModel()
export class DTO_Decorated {
public constructor(id: UUID, propPublic: string)
}
export class B5 { public constructor(x: DTO_Undecorated[]) } // type: DTO_Undecorated[]
export class B6 { public constructor(x: DTO_Decorated[]) } // type: DTO_Decorated[]
BUT, this is an issue, because in practice if I have a shared class (GraphQL type) I don't want to specify that class in every file that exports a read model. At the same time I don't want to decorate this shared class with @ReadModel because it shouldn't be a table.
A possible workaround, i.e. being able to import the class from a shared file without having to decorate the class with @ReadModel, is by using a locally defined class that inherits everything from the shared, base class. For example:
// file: src/read-modles/a.ts
export class DTO_Undecorated {
public constructor(id: UUID, propPublic: string)
}
// file: src/read-models/b.ts
import * as A from './a1'
class DTO_Undecorated_B extends A.DTO_Undecorated { }
export class B7 { public constructor(x: DTO_Undecorated_B[]) } // type: DTO_Undecorated_B[]
This would also mean, that the ItemWithQuantity example in the docs [1] doesn't actually work. You would either have to decorate ItemWithQuantity with @ReadModel or create a local class that inherits everything from it.