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

re-export typeorm decorators in typeorm-store #265

Merged
merged 5 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@subsquid/typeorm-codegen",
"comment": "use decorators from typeorm-store package",
"type": "minor"
}
],
"packageName": "@subsquid/typeorm-codegen"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@subsquid/typeorm-store",
"comment": "re-export typeorm decorators",
"type": "minor"
}
],
"packageName": "@subsquid/typeorm-store"
}
30 changes: 0 additions & 30 deletions test/erc20-transfers/src/model/generated/marshal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,36 +127,6 @@ export function nonNull<T>(val: T | undefined | null): T {
}


export const bigintTransformer = {
to(x?: bigint) {
return x?.toString()
},
from(s?: string): bigint | undefined {
return s == null ? undefined : BigInt(s)
}
}


export const floatTransformer = {
to(x?: number) {
return x?.toString()
},
from(s?: string): number | undefined {
return s == null ? undefined : Number(s)
}
}


export const bigdecimalTransformer = {
to(x?: any) {
return x?.toString()
},
from(s?: any): any | undefined {
return s == null ? undefined : decimal.BigDecimal(s)
}
}


export function enumFromJson<E extends object>(json: unknown, enumObject: E): E[keyof E] {
assert(typeof json == 'string', 'invalid enum value')
let val = (enumObject as any)[json]
Expand Down
15 changes: 7 additions & 8 deletions test/erc20-transfers/src/model/generated/transfer.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_} from "typeorm"
import * as marshal from "./marshal"
import {Entity as Entity_, Column as Column_, PrimaryColumn as PrimaryColumn_, IntColumn as IntColumn_, DateTimeColumn as DateTimeColumn_, StringColumn as StringColumn_, BigIntColumn as BigIntColumn_} from "@subsquid/typeorm-store"

@Entity_()
export class Transfer {
Expand All @@ -10,21 +9,21 @@ export class Transfer {
@PrimaryColumn_()
id!: string

@Column_("int4", {nullable: false})
@IntColumn_({nullable: false})
blockNumber!: number

@Column_("timestamp with time zone", {nullable: false})
@DateTimeColumn_({nullable: false})
timestamp!: Date

@Column_("text", {nullable: false})
@StringColumn_({nullable: false})
tx!: string

@Column_("text", {nullable: false})
@StringColumn_({nullable: false})
from!: string

@Column_("text", {nullable: false})
@StringColumn_({nullable: false})
to!: string

@Column_("numeric", {transformer: marshal.bigintTransformer, nullable: false})
@BigIntColumn_({nullable: false})
amount!: bigint
}
72 changes: 26 additions & 46 deletions typeorm/typeorm-codegen/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
index.line(`export * from "./${toCamelCase(name)}.model"`)
const out = dir.file(`${toCamelCase(name)}.model.ts`)
const imports = new ImportRegistry(name)
imports.useTypeorm('Entity', 'Column', 'PrimaryColumn')
imports.useTypeormStore('Entity', 'Column', 'PrimaryColumn')
out.lazy(() => imports.render(model, out))
out.line()
printComment(entity, out)
entity.indexes?.forEach(index => {
if (index.fields.length < 2) return
imports.useTypeorm('Index')
imports.useTypeormStore('Index')
out.line(`@Index_([${index.fields.map(f => `"${f.name}"`).join(', ')}], {unique: ${!!index.unique}})`)
})
out.line('@Entity_()')
Expand All @@ -59,34 +59,11 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
if (key === 'id') {
out.line('@PrimaryColumn_()')
} else {
const decorator = getDecorator(prop.type.name)
imports.useTypeormStore(decorator)

addIndexAnnotation(entity, key, imports, out)
switch (prop.type.name) {
case 'BigInt':
imports.useMarshal()
out.line(
`@Column_("${getDbType(prop.type.name)}", {transformer: marshal.bigintTransformer, nullable: ${prop.nullable}})`
)
break
case 'BigDecimal':
imports.useMarshal()
out.line(
`@Column_("${getDbType(prop.type.name)}", {transformer: marshal.bigdecimalTransformer, nullable: ${prop.nullable}})`
)
break
case 'Float':
imports.useMarshal()
out.line(
`@Column_("${getDbType(prop.type.name)}", {transformer: marshal.floatTransformer, nullable: ${prop.nullable}})`
)
break
default:
out.line(
`@Column_("${getDbType(prop.type.name)}", {nullable: ${
prop.nullable
}})`
)
break
}
out.line(`@${decorator}_({nullable: ${prop.nullable}})`)
}
break
case 'enum':
Expand All @@ -100,14 +77,14 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
break
case 'fk':
if (getFieldIndex(entity, key)?.unique) {
imports.useTypeorm('OneToOne', 'Index', 'JoinColumn')
imports.useTypeormStore('OneToOne', 'Index', 'JoinColumn')
out.line(`@Index_({unique: true})`)
out.line(
`@OneToOne_(() => ${prop.type.entity}, {nullable: true})`
)
out.line(`@JoinColumn_()`)
} else {
imports.useTypeorm('ManyToOne', 'Index')
imports.useTypeormStore('ManyToOne', 'Index')
if (!entity.indexes?.some(index => index.fields[0]?.name == key && index.fields.length > 1)) {
out.line(`@Index_()`)
}
Expand All @@ -120,7 +97,7 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
case 'lookup':
break
case 'list-lookup':
imports.useTypeorm('OneToMany')
imports.useTypeormStore('OneToMany')
out.line(
`@OneToMany_(() => ${prop.type.entity}, e => e.${prop.type.field})`
)
Expand All @@ -144,8 +121,12 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
if (scalar == 'BigInt' || scalar == 'BigDecimal') {
throw new Error(`Property ${name}.${key} has unsupported type: can't generate code for native ${scalar} arrays.`)
}

const decorator = getDecorator(scalar)
imports.useTypeormStore(decorator)

out.line(
`@Column_("${getDbType(scalar)}", {array: true, nullable: ${prop.nullable}})`
`@${decorator}_({array: true, nullable: ${prop.nullable}})`
)
break
}
Expand Down Expand Up @@ -186,26 +167,25 @@ export function generateOrmModels(model: Model, dir: OutDir): void {
out.write()
}

function getDbType(scalar: string): string {
function getDecorator(scalar: string): string {
switch(scalar) {
case 'ID':
case 'String':
return 'text'
return 'StringColumn'
case 'Int':
return 'int4'
return 'IntColumn'
case 'Float':
return 'numeric'
return 'FloatColumn'
case 'Boolean':
return 'bool'
return 'BooleanColumn'
case 'DateTime':
return 'timestamp with time zone'
return 'DateTimeColumn'
case 'BigInt':
return 'BigIntColumn'
case 'BigDecimal':
return 'numeric'
return 'BigDecimalColumn'
case 'Bytes':
return 'bytea'
case 'JSON':
return 'jsonb'
return 'BytesColumn'
default:
throw unexpectedCase(scalar)
}
Expand Down Expand Up @@ -495,7 +475,7 @@ function collectVariants(model: Model): Set<string> {
function addIndexAnnotation(entity: Entity, field: string, imports: ImportRegistry, out: Output): void {
let index = getFieldIndex(entity, field)
if (index == null) return
imports.useTypeorm('Index')
imports.useTypeormStore('Index')
if (index.unique) {
out.line(`@Index_({unique: true})`)
} else {
Expand Down Expand Up @@ -531,7 +511,7 @@ class ImportRegistry {

constructor(private owner: string) {}

useTypeorm(...names: string[]): void {
useTypeormStore(...names: string[]): void {
names.forEach((name) => this.typeorm.add(name))
}

Expand Down Expand Up @@ -565,7 +545,7 @@ class ImportRegistry {
const importList = Array.from(this.typeorm).map(
(name) => name + ' as ' + name + '_'
)
out.line(`import {${importList.join(', ')}} from "typeorm"`)
out.line(`import {${importList.join(', ')}} from "@subsquid/typeorm-store"`)
}
if (this.marshal) {
out.line(`import * as marshal from "./marshal"`)
Expand Down
30 changes: 0 additions & 30 deletions typeorm/typeorm-codegen/src/marshal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,36 +127,6 @@ export function nonNull<T>(val: T | undefined | null): T {
}


export const bigintTransformer = {
to(x?: bigint) {
return x?.toString()
},
from(s?: string): bigint | undefined {
return s == null ? undefined : BigInt(s)
}
}


export const floatTransformer = {
to(x?: number) {
return x?.toString()
},
from(s?: string): number | undefined {
return s == null ? undefined : Number(s)
}
}


export const bigdecimalTransformer = {
to(x?: any) {
return x?.toString()
},
from(s?: any): any | undefined {
return s == null ? undefined : decimal.BigDecimal(s)
}
}


export function enumFromJson<E extends object>(json: unknown, enumObject: E): E[keyof E] {
assert(typeof json == 'string', 'invalid enum value')
let val = (enumObject as any)[json]
Expand Down
37 changes: 37 additions & 0 deletions typeorm/typeorm-store/src/decorators/Entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {OrderByCondition, Entity as _Entity} from 'typeorm'

export interface EntityOptions {
/**
* Table name.
* If not specified then naming strategy will generate table name from entity name.
*/
name?: string
/**
* Specifies a default order by used for queries from this table when no explicit order by is specified.
*/
orderBy?: OrderByCondition | ((object: any) => OrderByCondition | any)
/**
* Schema name.
*/
schema?: string
}

/**
* This decorator is used to mark classes that will be an entity.
* Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it.
*/
export function Entity(options?: EntityOptions): ClassDecorator

/**
* This decorator is used to mark classes that will be an entity (table or document depend on database type).
* Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it.
*/
export function Entity(name?: string, options?: EntityOptions): ClassDecorator

/**
* This decorator is used to mark classes that will be an entity (table or document depend on database type).
* Database schema will be created for all classes decorated with it, and Repository can be retrieved and used for it.
*/
export function Entity(nameOrOptions?: string | EntityOptions, maybeOptions?: EntityOptions): ClassDecorator {
return _Entity(nameOrOptions as any, maybeOptions)
}
Loading
Loading