Skip to content

Commit

Permalink
add computed properties to REST API responses
Browse files Browse the repository at this point in the history
  • Loading branch information
ghackenberg committed May 2, 2024
1 parent f5c366a commit 09ed712
Show file tree
Hide file tree
Showing 20 changed files with 148 additions and 79 deletions.
4 changes: 2 additions & 2 deletions packages/backend/scripts/src/functions/emit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { ProductMessageData, UserMessageData, compileProductMessage, compileUser
import { MqttAPI } from "../mqtt"

export async function emitUserMessage(userId: string, data: UserMessageData) {
const message = compileUserMessage(data);
const message = await compileUserMessage(data);
(await MqttAPI).publish(`/users/${userId}`, JSON.stringify(message))
}
export async function emitProductMessage(productId: string, data: ProductMessageData) {
const message = compileProductMessage(data);
const message = await compileProductMessage(data);
(await MqttAPI).publish(`/products/${productId}`, JSON.stringify(message))
}
2 changes: 1 addition & 1 deletion packages/backend/scripts/src/functions/pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const materialsFileName = 'LDConfig.ldr'

const materialsFilePath = path.join(ldrawPath, materialsFileName)

let materialsContent: string = null
let materialsContent: string = null // Set upon first pack call

export function packLDrawText(text: string) {
const fileName = `${shortid()}.ldr`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ export class AttachmentService implements AttachmentREST<AttachmentCreate, Attac
async findAttachments(productId: string): Promise<AttachmentRead[]> {
const where = { productId, deleted: IsNull() }
const result: AttachmentRead[] = []
for (const attachment of await Database.get().attachmentRepository.findBy(where))
result.push(convertAttachment(attachment))
for (const attachment of await Database.get().attachmentRepository.findBy(where)) {
result.push(await convertAttachment(attachment))
}
return result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ export class CommentService implements CommentREST {
async findComments(productId: string, issueId: string): Promise<CommentRead[]> {
const where = { productId, issueId, deleted: IsNull() }
const result: CommentRead[] = []
for (const comment of await Database.get().commentRepository.findBy(where))
result.push(convertComment(comment))
for (const comment of await Database.get().commentRepository.findBy(where)) {
result.push(await convertComment(comment))
}
return result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ export class IssueService implements IssueREST {
async findIssues(productId: string) {
const where = { productId, deleted: IsNull() }
const result: IssueRead[] = []
for (const issue of await Database.get().issueRepository.findBy(where))
result.push(convertIssue(issue))
for (const issue of await Database.get().issueRepository.findBy(where)) {
result.push(await convertIssue(issue))
}
return result.sort((a, b) => a.created - b.created)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ export class MemberService implements MemberREST {
async findMembers(productId: string): Promise<MemberRead[]> {
const where = { productId, deleted: IsNull() }
const result: MemberRead[] = []
for (const member of await Database.get().memberRepository.findBy(where))
result.push(convertMember(member))
for (const member of await Database.get().memberRepository.findBy(where)) {
result.push(await convertMember(member))
}
return result
}

Expand All @@ -46,7 +47,7 @@ export class MemberService implements MemberREST {
}

async getMember(productId: string, memberId: string): Promise<MemberRead> {
const member = await Database.get().memberRepository.findOneByOrFail({ productId, memberId })
const member = await Database.get().memberRepository.findOneByOrFail({ productId, memberId })
return convertMember(member)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ export class MilestoneService implements MilestoneREST {
async findMilestones(productId: string): Promise<MilestoneRead[]> {
const where = { productId, deleted: IsNull() }
const result: MilestoneRead[] = []
for (const milestone of await Database.get().milestoneRepository.findBy(where))
result.push(convertMilestone(milestone))
for (const milestone of await Database.get().milestoneRepository.findBy(where)) {
result.push(await convertMilestone(milestone))
}
return result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,29 @@ export class ProductService implements ProductREST {
let where: FindOptionsWhere<ProductEntity> | FindOptionsWhere<ProductEntity>[]
if (this.request.user) {
const userId = this.request.user.userId
if (_public == 'true')
if (_public == 'true') {
where = { public: true, deleted: IsNull() }
else if (_public == 'false')
} else if (_public == 'false') {
where = { public: false, members: [ { userId, deleted: IsNull() } ], deleted: IsNull() }
else
} else {
where = [
{ public: true, deleted: IsNull() },
{ public: false, members: [ { userId, deleted: IsNull() } ], deleted: IsNull() }
]
]
}
} else {
if (_public == 'true')
if (_public == 'true') {
where = { public: true, deleted: IsNull() }
else if (_public == 'false')
} else if (_public == 'false') {
return []
else
} else {
where = { public: true, deleted: IsNull() }
}
}
const result: ProductRead[] = []
for (const product of await Database.get().productRepository.find({ where, order: { updated: 'DESC' }, take: 50 }))
result.push(convertProduct(product))
for (const product of await Database.get().productRepository.find({ where, order: { updated: 'DESC' }, take: 50 })) {
result.push(await convertProduct(product))
}
return result
}

Expand Down
12 changes: 7 additions & 5 deletions packages/backend/scripts/src/modules/rest/users/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,23 @@ export class UserService implements UserREST<UserUpdate, Express.Multer.File> {

async findUsers(productId?: string, query?: string) : Promise<UserRead[]> {
let where: FindOptionsWhere<UserEntity>
if (query)
if (query) {
where = { name: Raw(alias => `LOWER(${alias}) LIKE LOWER('%${query}%')`), deleted: IsNull() }
else
where = { deleted: IsNull() }
} else {
where = { deleted: IsNull() }
}
const result: UserRead[] = []
for (const user of await Database.get().userRepository.find({ where, order: { updated: 'DESC' }, take: 50 }))
for (const user of await Database.get().userRepository.find({ where, order: { updated: 'DESC' }, take: 50 })) {
try {
if (productId) {
await getMemberOrFail({ productId, userId: user.userId, deleted: IsNull() }, Error)
} else {
throw new Error()
}
} catch (error) {
result.push(convertUser(user, this.request.user && this.request.user.userId == user.userId))
result.push(await convertUser(user, this.request.user && this.request.user.userId == user.userId))
}
}
return result
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ export class VersionService implements VersionREST<VersionCreate, VersionUpdate,
async findVersions(productId: string) : Promise<VersionRead[]> {
const where = { productId, deleted: IsNull() }
const result: VersionRead[] = []
for (const version of await Database.get().versionRepository.findBy(where))
result.push(convertVersion(version))
for (const version of await Database.get().versionRepository.findBy(where)) {
result.push(await convertVersion(version))
}
return result
}

Expand Down
4 changes: 2 additions & 2 deletions packages/broker/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ async function boot() {
// Schedule initialization
setTimeout(async () => {
const users = await Database.get().userRepository.findBy({ userId, deleted: IsNull() })
const message = compileUserMessage({ type: 'state', users })
const message = await compileUserMessage({ type: 'state', users })
client.publish({
cmd: 'publish',
dup: false,
Expand Down Expand Up @@ -157,7 +157,7 @@ async function boot() {
const comments = await Database.get().commentRepository.findBy({ productId, deleted: IsNull() })
const milestones = await Database.get().milestoneRepository.findBy({ productId, deleted: IsNull() })
const versions = await Database.get().versionRepository.findBy({ productId, deleted: IsNull() })
const message = compileProductMessage({ type: 'state', products, members, issues, comments, milestones, versions })
const message = await compileProductMessage({ type: 'state', products, members, issues, comments, milestones, versions })
client.publish({
cmd: 'publish',
dup: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/common/src/data/attachment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export class AttachmentCreate extends AttachmentUpdate {
}

export class AttachmentRead extends AttachmentCreate {
@ApiProperty()
userId: string
@ApiProperty()
productId: string
@ApiProperty()
attachmentId: string
@ApiProperty()
userId: string

@ApiProperty()
created: number
Expand Down
4 changes: 2 additions & 2 deletions packages/common/src/data/comment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ export class CommentCreate extends CommentUpdate {
}

export class CommentRead extends CommentCreate {
@ApiProperty()
userId: string
@ApiProperty()
productId: string
@ApiProperty()
issueId: string
@ApiProperty()
commentId: string
@ApiProperty()
userId: string

@ApiProperty()
created: number
Expand Down
9 changes: 9 additions & 0 deletions packages/common/src/data/issue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,13 @@ export class IssueRead extends IssueCreate {
number: number
@ApiProperty()
state: 'open' | 'closed'

// Computed properties

@ApiProperty()
commentCount?: number
@ApiProperty()
attachmentCount?: number
@ApiProperty()
partCount?: number
}
8 changes: 7 additions & 1 deletion packages/common/src/data/milestone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export class MilestoneCreate extends MilestoneUpdate {
}

export class MilestoneRead extends MilestoneCreate {
@ApiProperty()
userId: string
@ApiProperty()
productId: string
@ApiProperty()
Expand All @@ -26,6 +28,10 @@ export class MilestoneRead extends MilestoneCreate {
@ApiProperty()
deleted: number

// Computed properties

@ApiProperty()
userId: string
openIssueCount?: number
@ApiProperty()
closedIssueCount?: number
}
14 changes: 13 additions & 1 deletion packages/common/src/data/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export class ProductCreate extends ProductUpdate {
}

export class ProductRead extends ProductCreate {
@ApiProperty()
userId: string
@ApiProperty()
productId: string

Expand All @@ -23,6 +25,16 @@ export class ProductRead extends ProductCreate {
@ApiProperty()
deleted: number

// Computed properties

@ApiProperty()
userId: string
versionCount?: number
@ApiProperty()
openIssueCount?: number
@ApiProperty()
closedIssueCount?: number
@ApiProperty()
milestoneCount?: number
@ApiProperty()
memberCount?: number
}
5 changes: 2 additions & 3 deletions packages/common/src/data/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export class UserCreate extends UserUpdate {
export class UserRead extends UserCreate {
@ApiProperty()
userId: string
@ApiProperty()
pictureId: string

@ApiProperty()
created: number
Expand All @@ -26,7 +28,4 @@ export class UserRead extends UserCreate {

@ApiProperty()
email: string

@ApiProperty()
pictureId: string
}
5 changes: 2 additions & 3 deletions packages/common/src/data/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export class VersionCreate extends VersionUpdate {
}

export class VersionRead extends VersionCreate {
@ApiProperty()
userId: string
@ApiProperty()
productId: string
@ApiProperty()
Expand All @@ -32,9 +34,6 @@ export class VersionRead extends VersionCreate {
updated: number
@ApiProperty()
deleted: number

@ApiProperty()
userId: string

@ApiProperty()
modelType: ModelType
Expand Down
28 changes: 16 additions & 12 deletions packages/database/src/compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,29 @@ export type ProductMessageData = {
versions?: VersionEntity[]
}

function process<T extends { created: number }, S extends { created: number }>(array: T[], value: (data: T) => S) {
return array && array.map(item => value(item)).sort((a, b) => a.created - b.created)
async function process<T extends { created: number }, S extends { created: number }>(array: T[], value: (data: T) => Promise<S>) {
const result: S[] = []
for (const item of array || []) {
result.push(await value(item))
}
return result.sort((a, b) => a.created - b.created)
}

export function compileUserMessage(data: UserMessageData): UserMessage {
export async function compileUserMessage(data: UserMessageData): Promise<UserMessage> {
return {
type: data.type,
users: process(data.users, user => convertUser(user, false))
users: await process(data.users, user => convertUser(user, false))
}
}
export function compileProductMessage(data: ProductMessageData): ProductMessage {
export async function compileProductMessage(data: ProductMessageData): Promise<ProductMessage> {
return {
type: data.type,
products: process(data.products, convertProduct),
members: process(data.members, convertMember),
issues: process(data.issues, convertIssue),
comments: process(data.comments, convertComment),
attachments: process(data.attachments, convertAttachment),
milestones: process(data.milestones, convertMilestone),
versions: process(data.versions, convertVersion)
products: await process(data.products, convertProduct),
members: await process(data.members, convertMember),
issues: await process(data.issues, convertIssue),
comments: await process(data.comments, convertComment),
attachments: await process(data.attachments, convertAttachment),
milestones: await process(data.milestones, convertMilestone),
versions: await process(data.versions, convertVersion)
}
}
Loading

0 comments on commit 09ed712

Please sign in to comment.