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

Orm #1942

Merged
merged 12 commits into from
Oct 22, 2024
Merged

Orm #1942

merged 12 commits into from
Oct 22, 2024

Conversation

PooyaRaki
Copy link
Contributor

@PooyaRaki PooyaRaki commented Sep 23, 2024

Summary

This pull request introduces TypeORM as the Object-Relational Mapping (ORM) solution for the project. TypeORM simplifies database interactions and enhances code maintainability by mapping database tables to application entities.

Benefits

Reduces boilerplate code and simplifies database operations.
Enhances code readability and maintainability.
Provides built-in support for migrations and schema management.
Improves error handling and validation through TypeORM features.

Changes

Integrated TypeORM into the project.
Updated database connection configuration to support TypeORM.
Created entity models corresponding to database tables.
Updated unit tests to ensure compatibility with TypeORM.

Next Steps

Explore additional features like eager loading and query optimizations in future iterations.

@PooyaRaki PooyaRaki marked this pull request as ready for review September 27, 2024 10:55
@PooyaRaki PooyaRaki requested a review from a team as a code owner September 27, 2024 10:55
@coveralls
Copy link

coveralls commented Sep 27, 2024

Pull Request Test Coverage Report for Build 11070730341

Details

  • 29 of 116 (25.0%) changed or added relevant lines in 23 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.7%) to 90.21%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/domain/accounts/counterfactual-safes/entities/counterfactual-safe.entity.ts 0 1 0.0%
migrations/1726754508107-notification_types.ts 0 3 0.0%
src/datasources/db/v2/postgres-database.module.ts 0 3 0.0%
src/config/entities/orm.config.ts 0 4 0.0%
src/datasources/notifications/entities/notification-type.entity.ts 0 8 0.0%
src/datasources/notifications/entities/notification-subscription-notification-type.entity.ts 0 10 0.0%
src/datasources/db/v2/postgres-database.service.ts 0 13 0.0%
src/datasources/notifications/entities/notification-devices.entity.ts 0 13 0.0%
migrations/1726752966034-notification.ts 0 16 0.0%
src/datasources/notifications/entities/notification-subscription.entity.ts 0 16 0.0%
Totals Coverage Status
Change from base Build 11055227805: -0.7%
Covered Lines: 8439
Relevant Lines: 9001

💛 - Coveralls

imports: [ConfigModule],
useFactory: (configService: ConfigService) => {
return {
...{ autoLoadEntities: true, manualInitialization: true },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would there be any benefit in moving these to the configuration, e.g. should we be able to change these on the fly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered it as well, but for now, I think it's too much. Since the app heavily relies on manual initialization, it seems better to hardcode it here. For both cases, since they shouldn't be changed, hardcoding seems like the best approach IMO. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of it being centralised, e.g. if we hardcoded these values in our configuration file but I am equally impartial. If it makes the most sense to have them here, we can keep it as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of it being centralised
💯
Done ✅
adf7bf4

src/config/entities/postgres.config.ts Show resolved Hide resolved

@Entity('push_notification_devices')
@Unique('device_uuid', ['device_uuid'])
@Check('device_type', 'device_type IN ("ANDROID", "IOS", "WEB")')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we set this to the values of the enum via TypeORM?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean we should dynamically create the string? TypeOrm Check only accepts string. I wouldn't dynamically create the string as that kills the readability here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to somehow have them linked. We aren't otherwise certain that our enum and this are the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing the field type in the database to ENUM? We can handle that in a separate PR.
P.S. I didn't modify the database fields, as it was beyond the scope of this PR.

type: 'varchar',
length: 255,
})
device_type!: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can use the enum in the Check decorator, this would then be typed that of the enum.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, The best solution is to define this field as an enum in the database. But, that's outside the scope of this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be preferable. If it's any benefit, we already have the DeviceType enum in the project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you agree with me that it should be refactored in another PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's fine with me.

Comment on lines +11 to +20
@Unique('name', ['name'])
export class NotificationType {
@PrimaryGeneratedColumn()
id!: number;

@Column({
type: 'varchar',
length: 255,
})
name!: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the device, could we ensure that the name is of the NotificationType enum?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can make it an ENUM in the database. I think it should be fixed in another PR. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. We already have a reference enum in the project - NotificationType.

@Entity('push_notification_devices')
@Unique('device_uuid', ['device_uuid'])
@Check('device_type', 'device_type IN ("ANDROID", "IOS", "WEB")')
export class NotificationDevice {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be done in a follow up, but I would be in favour of (on the domain level) validating these entities and, as such, we could then implement the type here, e.g.

// Datasource
export class NotificationDevice implements z.infer<NotificationDeviceSchema> { ... }

// Domain
function example() {
  const deviceFromDatabase = // ...
  return NotificationDeviceSchema.parse(device)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea, but let's do it in the notification PR.

Comment on lines +34 to +45
@Column({
type: 'varchar',
length: 42,
})
safe_address!: string;

@Column({
type: 'varchar',
nullable: true,
length: 42,
})
signer_address!: string | null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the refinement functionality to call viem's getAddress, ensuring that these addresses are checksummed. We can then set the type to 0x${string} as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be addressed in a separate PR focused on notifications.

@@ -131,11 +131,13 @@ export default () => ({
apiKey: process.env.INFURA_API_KEY,
},
},
typeorm: { autoLoadEntities: true, manualInitialization: true },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I've move these under the db property.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, a better approach than the current one would be to use db.orm and Array<db.databases>, allowing us the flexibility to add multiple databases in the future and easily iterate over them. Do you believe we should move Typeorm under db?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db.orm sounds good to me. I wouldn't create and array out of them for now though as we don't have more than one. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

db.orm also sounds good to me. Regarding the array, no strong opinion, but I'd slightly prefer not having it until it's needed. It can be easily added later if we need to add another db.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@iamacook @hectorgomezv What do you think about moving orm under db and placing postgres under db.connection? My concern is that having orm and postgres under the same parent could lead to ambiguity. For now, db.connection will remain an object, but in the future, we can convert it to an array and rename it to db.connections(add an s to make it plural).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me @PooyaRaki, thanks! 👍

password: postgresEnvConfig.password,
database: postgresEnvConfig.database,
migrations: ['dist/migrations/*.js'],
// logging: !isCIContext,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't have CI logging, I'd remove this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say let's keep it, it's like a TODO. I should have been more clear by adding a TODO.

@iamacook
Copy link
Member

To keep track of our discussion, we need to consider automatic migrations across multiple instances.

src/app.module.ts Outdated Show resolved Hide resolved
@PooyaRaki
Copy link
Contributor Author

PooyaRaki commented Oct 17, 2024

To keep track of our discussion, we need to consider automatic migrations across multiple instances.

@iamacook
This has been implemented in #1988

@PooyaRaki PooyaRaki merged commit c95a038 into main Oct 22, 2024
20 checks passed
@PooyaRaki PooyaRaki deleted the orm branch October 22, 2024 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants