Skip to content

Commit baa0a49

Browse files
committed
fix: serialize data
1 parent 07cd660 commit baa0a49

9 files changed

+85
-26
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jrmc/adonis-attachment",
3-
"version": "2.1.0",
3+
"version": "2.1.1-1",
44
"type": "module",
55
"description": "Turn any field on your Lucid model to an attachment data type",
66
"engines": {
@@ -82,7 +82,7 @@
8282
"prettier": "@adonisjs/prettier-config",
8383
"publishConfig": {
8484
"access": "public",
85-
"tag": "latest"
85+
"tag": "beta"
8686
},
8787
"volta": {
8888
"node": "20.17.0"

src/attachment_manager.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import type { LoggerService } from '@adonisjs/core/types'
99
import type { DriveService } from '@adonisjs/drive/types'
1010
import type { MultipartFile } from '@adonisjs/core/bodyparser'
11-
import type { AttachmentBase } from './types/attachment.js'
11+
import type { AttachmentBase, Attachment as AttachmentType } from './types/attachment.js'
1212
import type { ResolvedAttachmentConfig } from './types/config.js'
1313

1414
import { Exception } from '@poppinss/utils'
@@ -83,6 +83,33 @@ export class AttachmentManager {
8383
}
8484
}
8585

86+
async computeUrl(attachment: AttachmentType) {
87+
if (attachment.options?.preComputeUrl === false) {
88+
return
89+
}
90+
91+
const disk = attachment.getDisk()
92+
const fileVisibility = await disk.getVisibility(attachment.path!)
93+
94+
if (fileVisibility === 'private') {
95+
attachment.url = await attachment.getSignedUrl()
96+
} else {
97+
attachment.url = await attachment.getUrl()
98+
}
99+
100+
if (attachment.variants) {
101+
for (const key in attachment.variants) {
102+
if (Object.prototype.hasOwnProperty.call(attachment.variants, key)) {
103+
if (fileVisibility === 'private') {
104+
attachment.variants[key].url = await attachment.getSignedUrl(attachment.variants[key].key)
105+
} else {
106+
attachment.variants[key].url = await attachment.getUrl(attachment.variants[key].key)
107+
}
108+
}
109+
}
110+
}
111+
}
112+
86113
async save(attachment: AttachmentBase) {
87114
const destinationPath = attachment.path!
88115

src/attachments/attachment.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -120,27 +120,26 @@ export class Attachment extends AttachmentBase implements AttachmentInterface {
120120
}
121121
}
122122

123-
async toJSON(): Promise<Object> {
123+
toJSON(): Object {
124124
const data: any = {
125125
name: this.name,
126126
originalName: this.originalName,
127127
size: this.size,
128128
extname: this.extname,
129129
mimetype: this.mimeType,
130130
meta: this.meta,
131-
url: await this.getUrl(),
132-
signedUrl: await this.getSignedUrl(),
133131
}
134132

135-
if (this.variants) {
136-
await Promise.allSettled(
133+
if (this.url) {
134+
data.url = this.url
135+
136+
if (this.variants) {
137137
this.variants!.map(async (v) => {
138138
data[v.key] = {
139-
url: await this.getUrl(v.key),
140-
signedUrl: await this.getSignedUrl(v.key)
139+
url: v.url,
141140
}
142141
})
143-
)
142+
}
144143
}
145144

146145
return data

src/attachments/attachment_base.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class AttachmentBase implements AttachmentBaseInterface {
2828
meta?: Exif
2929
folder?: string
3030
path?: string
31+
url?: string
3132

3233
options?: LucidOptions
3334

@@ -83,11 +84,14 @@ export class AttachmentBase implements AttachmentBaseInterface {
8384
}
8485
}
8586

86-
async toJSON(): Promise<Object> {
87-
return {
88-
...this.toObject(),
89-
url: await this.getUrl(),
90-
signedUrl: await this.getSignedUrl(),
87+
toJSON(): Object {
88+
if (this.url) {
89+
return {
90+
...this.toObject(),
91+
url: this.url
92+
}
9193
}
94+
95+
return this.toObject()
9296
}
9397
}

src/decorators/attachment.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const attachment = (options?: LucidOptions) => {
5252
}
5353
},
5454
prepare: (value) => (value ? JSON.stringify(value.toObject()) : null),
55-
serialize: async (value) => (value ? await value.toJSON() : null),
55+
serialize: (value) => (value ? value.toJSON() : null),
5656
...columnOptions,
5757
})
5858
}

src/mixins/attachmentable.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import type { BaseModel } from '@adonisjs/lucid/orm'
99
import type { NormalizeConstructor } from '@adonisjs/core/types/helpers'
1010
import type { AttributeOfModelWithAttachment } from '../types/mixin.js'
1111

12-
import { beforeSave, afterSave, beforeDelete } from '@adonisjs/lucid/orm'
13-
import { persistAttachment, commit, rollback, generateVariants } from '../utils/actions.js'
12+
import { beforeSave, afterSave, beforeDelete, afterFind, afterFetch, afterPaginate } from '@adonisjs/lucid/orm'
13+
import { persistAttachment, commit, rollback, generateVariants, computeUrl } from '../utils/actions.js'
1414
import { clone, getAttachmentAttributeNames } from '../utils/helpers.js'
1515
import { defaultStateAttributeMixin } from '../utils/default_values.js'
1616

@@ -20,6 +20,23 @@ export const Attachmentable = <Model extends NormalizeConstructor<typeof BaseMod
2020
class ModelWithAttachment extends superclass {
2121
$attachments: AttributeOfModelWithAttachment = clone(defaultStateAttributeMixin)
2222

23+
@afterFind()
24+
static async afterFindHook(modelInstance: ModelWithAttachment) {
25+
const attachmentAttributeNames = getAttachmentAttributeNames(modelInstance)
26+
27+
await Promise.all(
28+
attachmentAttributeNames.map((attributeName) => {
29+
return computeUrl(modelInstance, attributeName)
30+
})
31+
)
32+
}
33+
34+
@afterFetch()
35+
@afterPaginate()
36+
static async afterFetchHook(modelInstances: ModelWithAttachment[]) {
37+
await Promise.all(modelInstances.map((row) => this.afterFindHook(row)))
38+
}
39+
2340
@beforeSave()
2441
static async beforeSaveHook(modelInstance: ModelWithAttachment) {
2542
const attachmentAttributeNames = getAttachmentAttributeNames(modelInstance)

src/types/attachment.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type AttachmentBase = {
2222
meta?: Exif
2323
folder?: string
2424
path?: string
25+
url?: string
2526

2627
options?: LucidOptions
2728

@@ -32,7 +33,7 @@ export type AttachmentBase = {
3233
setOptions(options: LucidOptions): AttachmentBase
3334

3435
toObject(): AttachmentBaseAttributes
35-
toJSON(): Promise<Object>
36+
toJSON(): Object
3637
}
3738

3839
export type Attachment = AttachmentBase & {
@@ -56,6 +57,7 @@ export type Variant = AttachmentBase & {
5657
export type LucidOptions = {
5758
disk?: string
5859
folder?: string
60+
preComputeUrl?: boolean
5961
variants?: string[]
6062
rename?: boolean
6163
meta?: boolean

src/utils/actions.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ export async function rollback(modelInstance: ModelWithAttachment) {
3535
}
3636

3737
/**
38-
* Persist attachment for a given attachment property
38+
* Persist attachment for a given attachment attributeName
3939
*/
40-
export async function persistAttachment(modelInstance: ModelWithAttachment, property: string) {
41-
const existingFile = modelInstance.$original[property] as Attachment
42-
const newFile = modelInstance.$attributes[property] as Attachment
43-
const options = getOptions(modelInstance, property)
40+
export async function persistAttachment(modelInstance: ModelWithAttachment, attributeName: string) {
41+
const existingFile = modelInstance.$original[attributeName] as Attachment
42+
const newFile = modelInstance.$attributes[attributeName] as Attachment
43+
const options = getOptions(modelInstance, attributeName)
4444

4545
/**
46-
* Skip when the attachment property hasn't been updated
46+
* Skip when the attachment attributeName hasn't been updated
4747
*/
4848
if (existingFile === newFile) {
4949
return
@@ -84,6 +84,15 @@ export async function persistAttachment(modelInstance: ModelWithAttachment, prop
8484
}
8585
}
8686

87+
export async function computeUrl(modelInstance: ModelWithAttachment, attributeName: string) {
88+
const attachment = modelInstance.$attributes[attributeName] as Attachment
89+
const options = getOptions(modelInstance, attributeName)
90+
91+
attachment.setOptions(options)
92+
93+
return attachmentManager.computeUrl(attachment)
94+
}
95+
8796
/**
8897
* Launch converter by variant option
8998
*/

src/utils/default_values.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
export const defaultOptionsDecorator = {
99
disk: undefined,
1010
folder: 'uploads',
11+
preComputeUrl: false,
1112
variants: [],
1213
rename: true,
1314
meta: true

0 commit comments

Comments
 (0)