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
Is There a Recommended Way to Create a Generic Repository in DynamoDB Toolbox? #595
Comments
Hey @hdrhmd, class GenericRepository<E extends Entity> {
constructor(
private readonly entity: E
) {}
async queryOne(pk: string, options?: QueryOptions<E>) {
const result = await this.entity.query(pk, options);
if (result?.Items?.length??0 > 0) {
return result.Items![0]
}
return undefined;
}
}
class UsersRepository {
private readonly genericRepository;
private readonly userEntity;
constructor() {
this.userEntity = new Entity({
name: 'User',
attributes: {
userId: { type: 'string', partitionKey: true },
firstName: { type: 'string' },
lastName: { type: 'string' },
},
table: myTable,
} as const);
this.genericRepository = new GenericRepository(this.userEntity);
}
async getById(userId: string, options?: QueryOptions<typeof this.userEntity>) {
return this.genericRepository.queryOne(`userId:${userId}`, options);
}
} Marking this issue as resolved but feel free to ping me if you need anything else 😎 |
Thanks for your help with the query method. Sorry to jump back into a closed issue, but your advice would be super helpful. Generic repo import type { Entity, EntityItem, PutOptions, QueryOptions } from 'dynamodb-toolbox';
abstract class DynamoDbRepository<E extends Entity> {
constructor(private readonly entity: E) {}
put<O extends PutOptions<E>>(item: EntityItem<E>, options: O) {
return this.entity.put(item, options);
}
query<O extends QueryOptions<E>>(pk: string, options: O) {
return this.entity.query(pk, options);
} Entity repo: class AuditTrailRepository extends DynamoDbRepository<typeof auditTrailEventEntity> {
constructor() {
super(auditTrailEventEntity);
}
} Entity and a table: import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
import { Entity, Table } from 'dynamodb-toolbox';
import { ulid } from 'ulid';
const DocumentClient = DynamoDBDocumentClient.from(new DynamoDBClient({ region: REGION }), {
marshallOptions: {
convertEmptyValues: false,
},
});
const auditTrailTable = new Table({
name: process.env.AUDIT_TRAIL_TABLE_NAME,
partitionKey: 'pk',
sortKey: 'sk',
DocumentClient,
});
type AuditEvent = {
userId: string;
eventId: string;
entityId: string;
entityName: string;
};
type CompositeKey = {
pk: string;
sk: string;
};
const auditTrailEventEntity = new Entity<'AuditTrailEvent', AuditEvent, CompositeKey, typeof auditTrailTable>({
name: 'AuditTrailEvent',
table: auditTrailTable,
attributes: {
pk: {
partitionKey: true,
default: ({ userId }) => userId,
dependsOn: ['accountId'],
hidden: true,
},
sk: {
sortKey: true,
default: ({ eventId, recordType }) => `audit#${eventId}`,
dependsOn: ['eventId'],
hidden: true,
},
userId: {
type: 'string',
required: true,
},
eventId: {
type: 'string',
default: () => ulid(),
},
entityId: {
type: 'string',
required: true,
},
entityName: {
type: 'string',
required: true,
},
},
} as const); |
will try to take a look a bit later/tomorrow and ping you when I have some thoughts 🙏 |
@naorpeled Cheers! Sorry for being so pushy, but perhaps you had time to look at the problem? |
@nevolgograd Feel free to ping me, all good! I'll hopefully get to digging into it tonight, there might be some missing utility type defs that I need to add 🙏 |
Hello,
I've been using DynamoDB Toolbox extensively for various projects and find it to be a robust solution for working with AWS DynamoDB. In my projects, I generally define a Model and a Repository class for each entity in my database schema. While this approach works well, I notice that there's a lot of repetitive boilerplate code in each repository class that can be shared among all repositories.
To streamline this, I've been attempting to create a generic repository that contains common methods, which can be extended or aggregated in each individual repository. While I've managed to make it work to some extent using TypeScript's
ts-ignore
and redefining the Query object, I wonder if there is a more elegant or recommended approach to achieve this goal.Here's a stripped-down example of my current implementation in TypeScript:
Would love to get the community's thoughts on this, especially if there's a more idiomatic way to achieve what I am aiming for.
Thank you in advance for your guidance!
The text was updated successfully, but these errors were encountered: