@jrmc/adonis-attachment
Version:
Turn any field on your Lucid model to an attachment data type
94 lines (93 loc) • 3.65 kB
JavaScript
/**
* @jrmc/adonis-attachment
*
* @license MIT
* @copyright Jeremy Chaufourier <jeremy@chaufourier.fr>
*/
import attachmentManager from '../../services/main.js';
import { optionsSym } from '../utils/symbols.js';
import { defaultOptionsDecorator } from '../utils/default_values.js';
import { afterFindHook, afterFetchHook, beforeSaveHook, afterSaveHook, beforeDeleteHook, } from '../utils/hooks.js';
import { defaultStateAttributeMixin } from '../utils/default_values.js';
export const bootModel = (model) => {
model.boot();
model.$attachments = structuredClone(defaultStateAttributeMixin);
/**
* Registering all hooks only once
*/
if (!model.$hooks.has('find', afterFindHook)) {
model.after('find', afterFindHook);
}
if (!model.$hooks.has('fetch', afterFetchHook)) {
model.after('fetch', afterFetchHook);
}
if (!model.$hooks.has('paginate', afterFetchHook)) {
model.after('paginate', afterFetchHook);
}
if (!model.$hooks.has('save', beforeSaveHook)) {
model.before('save', beforeSaveHook);
}
if (!model.$hooks.has('save', afterSaveHook)) {
model.after('save', afterSaveHook);
}
if (!model.$hooks.has('delete', beforeDeleteHook)) {
model.before('delete', beforeDeleteHook);
}
};
const makeColumnOptions = (options) => {
const { disk, folder, variants, meta, rename, ...columnOptions } = {
...defaultOptionsDecorator,
...options,
};
return {
consume: (value) => {
if (value) {
const attachment = attachmentManager.createFromDbResponse(value);
attachment?.setOptions({ disk, folder, variants });
if (options && options?.meta !== undefined) {
attachment?.setOptions({ meta: options.meta });
}
if (options && options?.rename !== undefined) {
attachment?.setOptions({ rename: options.rename });
}
if (options && options?.preComputeUrl !== undefined) {
attachment?.setOptions({ preComputeUrl: options.preComputeUrl });
}
return attachment;
}
else {
return null;
}
},
prepare: (value) => (value ? JSON.stringify(value.toObject()) : null),
serialize: options?.serialize !== undefined ? options?.serialize : (value) => (value ? value.toJSON() : null),
...columnOptions,
};
};
const makeAttachmentDecorator = (columnOptionsTransformer) => (options) => {
return function (target, attributeName) {
if (!target[optionsSym]) {
target[optionsSym] = {};
}
target[optionsSym][attributeName] = options;
const Model = target.constructor;
bootModel(Model);
const columnOptions = makeColumnOptions(options);
const transformedColumnOptions = columnOptionsTransformer
? columnOptionsTransformer(columnOptions)
: columnOptions;
Model.$addColumn(attributeName, transformedColumnOptions);
};
};
export const attachment = makeAttachmentDecorator();
export const attachments = makeAttachmentDecorator((columnOptions) => ({
consume: (value) => {
if (value) {
const data = typeof value === 'string' ? JSON.parse(value) : value;
return data.map(columnOptions.consume);
}
return null;
},
prepare: (value) => value ? JSON.stringify(value.map((v) => v.toObject())) : null,
serialize: (value) => (value ? value.map(columnOptions.serialize) : null),
}));