@jrmc/adonis-attachment 5.0.0-beta.2 → 5.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/build/index.d.ts +0 -1
  2. package/build/index.d.ts.map +1 -1
  3. package/build/index.js +0 -1
  4. package/build/providers/attachment_provider.d.ts.map +1 -1
  5. package/build/providers/attachment_provider.js +10 -1
  6. package/build/services/regenerate_service.js +3 -3
  7. package/build/src/adapters/lock.d.ts +9 -0
  8. package/build/src/adapters/lock.d.ts.map +1 -0
  9. package/build/src/adapters/lock.js +21 -0
  10. package/build/src/attachment_manager.d.ts +4 -2
  11. package/build/src/attachment_manager.d.ts.map +1 -1
  12. package/build/src/attachment_manager.js +7 -1
  13. package/build/src/attachments/attachment.d.ts +1 -1
  14. package/build/src/attachments/attachment.js +1 -1
  15. package/build/src/controllers/attachments_controller.d.ts.map +1 -1
  16. package/build/src/controllers/attachments_controller.js +83 -74
  17. package/build/src/decorators/attachment.d.ts +3 -3
  18. package/build/src/decorators/attachment.d.ts.map +1 -1
  19. package/build/src/services/attachment/attachment_detachment_service.d.ts +19 -0
  20. package/build/src/services/attachment/attachment_detachment_service.d.ts.map +1 -0
  21. package/build/src/services/attachment/attachment_detachment_service.js +64 -0
  22. package/build/src/services/attachment/attachment_persister_service.d.ts +22 -0
  23. package/build/src/services/attachment/attachment_persister_service.d.ts.map +1 -0
  24. package/build/src/services/attachment/attachment_persister_service.js +93 -0
  25. package/build/src/services/attachment/attachment_recorder_service.d.ts +68 -0
  26. package/build/src/services/attachment/attachment_recorder_service.d.ts.map +1 -0
  27. package/build/src/services/attachment/attachment_recorder_service.js +119 -0
  28. package/build/src/services/attachment/attachment_transaction_service.d.ts +26 -0
  29. package/build/src/services/attachment/attachment_transaction_service.d.ts.map +1 -0
  30. package/build/src/services/attachment/attachment_transaction_service.js +43 -0
  31. package/build/src/services/attachment/attachment_utils.d.ts +35 -0
  32. package/build/src/services/attachment/attachment_utils.d.ts.map +1 -0
  33. package/build/src/services/attachment/attachment_utils.js +71 -0
  34. package/build/src/services/attachment/attachment_variant_service.d.ts +17 -0
  35. package/build/src/services/attachment/attachment_variant_service.d.ts.map +1 -0
  36. package/build/src/services/attachment/attachment_variant_service.js +72 -0
  37. package/build/src/services/attachment/index.d.ts +15 -0
  38. package/build/src/services/attachment/index.d.ts.map +1 -0
  39. package/build/src/services/attachment/index.js +15 -0
  40. package/build/src/services/attachment_service.d.ts +8 -0
  41. package/build/src/services/attachment_service.d.ts.map +1 -0
  42. package/build/src/services/attachment_service.js +7 -0
  43. package/build/src/services/variant/variant_generator_service.d.ts +24 -0
  44. package/build/src/services/variant/variant_generator_service.d.ts.map +1 -0
  45. package/build/src/services/variant/variant_generator_service.js +97 -0
  46. package/build/src/services/variant/variant_persister_service.d.ts +23 -0
  47. package/build/src/services/variant/variant_persister_service.d.ts.map +1 -0
  48. package/build/src/services/variant/variant_persister_service.js +60 -0
  49. package/build/src/services/variant/variant_purger_service.d.ts +15 -0
  50. package/build/src/services/variant/variant_purger_service.d.ts.map +1 -0
  51. package/build/src/services/variant/variant_purger_service.js +48 -0
  52. package/build/src/services/variant_service.d.ts +13 -0
  53. package/build/src/services/variant_service.d.ts.map +1 -0
  54. package/build/src/services/variant_service.js +58 -0
  55. package/build/src/types/attachment.d.ts +3 -3
  56. package/build/src/types/attachment.d.ts.map +1 -1
  57. package/build/src/types/index.d.ts +6 -0
  58. package/build/src/types/index.d.ts.map +1 -1
  59. package/build/src/types/index.js +6 -0
  60. package/build/src/types/lock.d.ts +14 -0
  61. package/build/src/types/lock.d.ts.map +1 -0
  62. package/build/src/types/lock.js +7 -0
  63. package/build/src/types/metadata.d.ts +6 -0
  64. package/build/src/types/metadata.d.ts.map +1 -1
  65. package/build/src/types/metadata.js +6 -0
  66. package/build/src/types/regenerate.d.ts +6 -0
  67. package/build/src/types/regenerate.d.ts.map +1 -1
  68. package/build/src/types/regenerate.js +6 -0
  69. package/build/src/types/service.d.ts +6 -0
  70. package/build/src/types/service.d.ts.map +1 -1
  71. package/build/src/types/service.js +6 -0
  72. package/build/src/utils/hooks.js +5 -5
  73. package/build/stubs/config.stub +102 -4
  74. package/build/tsconfig.tsbuildinfo +1 -1
  75. package/package.json +27 -22
  76. package/build/src/converter_manager.d.ts +0 -13
  77. package/build/src/converter_manager.d.ts.map +0 -1
  78. package/build/src/converter_manager.js +0 -121
  79. package/build/src/services/record_with_attachment.d.ts +0 -33
  80. package/build/src/services/record_with_attachment.d.ts.map +0 -1
  81. package/build/src/services/record_with_attachment.js +0 -303
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jrmc/adonis-attachment",
3
- "version": "5.0.0-beta.2",
3
+ "version": "5.0.0-beta.4",
4
4
  "type": "module",
5
5
  "description": "Turn any field on your Lucid model to an attachment data type",
6
6
  "engines": {
@@ -65,51 +65,56 @@
65
65
  "./attachment_provider": "./build/providers/attachment_provider.js"
66
66
  },
67
67
  "dependencies": {
68
- "@poppinss/defer": "^1.1.1",
68
+ "@poppinss/defer": "^1.1.2",
69
+ "@verrou/core": "^0.5.1",
69
70
  "blurhash": "^2.0.5",
70
71
  "execa": "^9.6.0",
71
- "exifreader": "^4.26.0",
72
- "file-type": "^19.6.0",
73
- "mime-types": "^2.1.35"
72
+ "exifreader": "^4.31.1",
73
+ "file-type": "^21.0.0",
74
+ "mime-types": "^3.0.1"
74
75
  },
75
76
  "devDependencies": {
76
77
  "@adonisjs/assembler": "^7.8.2",
77
- "@adonisjs/core": "^6.17.1",
78
- "@adonisjs/drive": "^3.2.0",
79
- "@adonisjs/lucid": "^21.6.0",
80
- "@adonisjs/prettier-config": "^1.4.0",
81
- "@adonisjs/tsconfig": "^1.4.0",
78
+ "@adonisjs/core": "^6.19.0",
79
+ "@adonisjs/drive": "^3.4.1",
80
+ "@adonisjs/lock": "^1.1.1",
81
+ "@adonisjs/lucid": "^21.7.0",
82
+ "@adonisjs/prettier-config": "^1.4.5",
83
+ "@adonisjs/tsconfig": "^1.4.1",
82
84
  "@japa/assert": "^4.0.1",
83
85
  "@japa/expect-type": "^2.0.3",
84
86
  "@japa/file-system": "^2.3.2",
85
- "@japa/plugin-adonisjs": "^4.0.0",
86
87
  "@japa/runner": "^4.1.0",
87
88
  "@poppinss/utils": "^6.9.2",
88
- "@swc/core": "^1.10.7",
89
- "@types/luxon": "^3.4.2",
90
- "@types/mime-types": "^2.1.4",
91
- "@types/node": "^22.10.7",
92
- "@types/sinon": "^17.0.3",
93
- "better-sqlite3": "^11.8.0",
89
+ "@swc/core": "^1.12.9",
90
+ "@types/luxon": "^3.6.2",
91
+ "@types/mime-types": "^3.0.1",
92
+ "@types/node": "^24.0.10",
93
+ "@types/sinon": "^17.0.4",
94
+ "better-sqlite3": "^12.2.0",
94
95
  "c8": "^10.1.3",
95
96
  "copyfiles": "^2.4.1",
96
97
  "del-cli": "^6.0.0",
97
- "flydrive": "^1.1.0",
98
- "luxon": "^3.5.0",
98
+ "flydrive": "^1.3.0",
99
+ "luxon": "^3.6.1",
99
100
  "prettier": "^3.4.2",
100
- "sharp": "^0.33.5",
101
- "sinon": "^19.0.2",
101
+ "sharp": "^0.34.2",
102
+ "sinon": "^21.0.0",
102
103
  "ts-node": "^10.9.2",
103
- "typescript": "^5.7.3",
104
+ "typescript": "^5.3.3",
104
105
  "vitepress": "^1.5.0"
105
106
  },
106
107
  "peerDependencies": {
107
108
  "@adonisjs/core": "^6.12.1",
108
109
  "@adonisjs/drive": "^3.2.0",
110
+ "@adonisjs/lock": "^1.1.1",
109
111
  "@adonisjs/lucid": "^20.6.0 || ^21.0.0",
110
112
  "sharp": "^0.33.0"
111
113
  },
112
114
  "peerDependenciesMeta": {
115
+ "@adonisjs/lock": {
116
+ "optional": true
117
+ },
113
118
  "sharp": {
114
119
  "optional": true
115
120
  }
@@ -1,13 +0,0 @@
1
- import type { Converter, ConverterInitializeAttributes } from './types/converter.js';
2
- import type { Attachment, Variant } from './types/attachment.js';
3
- export declare class ConverterManager {
4
- #private;
5
- constructor({ record, attributeName, options, filters }: ConverterInitializeAttributes);
6
- run(): Promise<void>;
7
- static generate({ key, attachment, converter }: {
8
- key: string;
9
- attachment: Attachment;
10
- converter: Converter;
11
- }): Promise<Variant | undefined>;
12
- }
13
- //# sourceMappingURL=converter_manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"converter_manager.d.ts","sourceRoot":"","sources":["../../src/converter_manager.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAA;AACpF,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAgB,MAAM,uBAAuB,CAAA;AAS9E,qBAAa,gBAAgB;;gBAQf,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,6BAA6B;IAOhF,GAAG;WAyCI,QAAQ,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,EAAG;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE;CA6FrH"}
@@ -1,121 +0,0 @@
1
- import logger from '@adonisjs/core/services/logger';
2
- import string from '@adonisjs/core/helpers/string';
3
- import db from '@adonisjs/lucid/services/db';
4
- import attachmentManager from '../services/main.js';
5
- import { streamToTempFile } from './utils/helpers.js';
6
- export class ConverterManager {
7
- #record;
8
- #attributeName;
9
- #options;
10
- #filters;
11
- constructor({ record, attributeName, options, filters }) {
12
- this.#record = record;
13
- this.#attributeName = attributeName;
14
- this.#options = options;
15
- this.#filters = filters;
16
- }
17
- async run() {
18
- const attachments = this.#record.getAttachments({
19
- attributeName: this.#attributeName,
20
- });
21
- const variants = [];
22
- await this.#purge(attachments);
23
- if (!attachments || !this.#options.variants || !this.#options.variants.length) {
24
- return;
25
- }
26
- for await (const key of this.#options.variants) {
27
- if (this.#filters?.variants !== undefined && !this.#filters?.variants?.includes(key)) {
28
- continue;
29
- }
30
- const converter = (await attachmentManager.getConverter(key));
31
- if (converter) {
32
- for await (const attachment of attachments) {
33
- const variant = await ConverterManager.generate({
34
- key,
35
- attachment,
36
- converter
37
- });
38
- if (variant) {
39
- variants.push(variant);
40
- }
41
- }
42
- }
43
- }
44
- return this.#commit(attachments, () => {
45
- for (let i = 0; i < variants.length; i++) {
46
- attachmentManager.remove(variants[i]);
47
- }
48
- });
49
- }
50
- static async generate({ key, attachment, converter }) {
51
- let input = attachment.input;
52
- if (!input) {
53
- input = await streamToTempFile(await attachment.getStream());
54
- }
55
- const output = await converter.handle({
56
- input,
57
- options: converter.options,
58
- });
59
- if (output === undefined) {
60
- // throw new errors.E_CANNOT_PATH_BY_CONVERTER()
61
- return;
62
- }
63
- const variant = await attachment.createVariant(key, output);
64
- if (converter.options.blurhash) {
65
- if ((typeof converter.options.blurhash !== 'boolean' &&
66
- converter.options.blurhash.enabled === true) ||
67
- converter.options.blurhash === true) {
68
- try {
69
- const options = typeof converter.options.blurhash !== 'boolean'
70
- ? converter.options.blurhash
71
- : undefined;
72
- await variant.generateBlurhash(options);
73
- }
74
- catch (error) {
75
- logger.error(error.message);
76
- }
77
- }
78
- }
79
- await attachmentManager.write(variant);
80
- return variant;
81
- }
82
- async #commit(attachments, rollback) {
83
- const Model = this.#record.row.constructor;
84
- const id = this.#record.row.$attributes['id'];
85
- const data = {};
86
- const index = string.snakeCase(this.#attributeName);
87
- if (Array.isArray(this.#record.row.$original[this.#attributeName])) {
88
- data[index] = JSON.stringify(attachments.map((att) => att.toObject()));
89
- }
90
- else {
91
- data[index] = JSON.stringify(attachments[0].toObject());
92
- }
93
- const trx = await db.transaction();
94
- trx.after('rollback', rollback);
95
- try {
96
- await trx.query().from(Model.table).where('id', id).update(data);
97
- return trx.commit();
98
- }
99
- catch (error) {
100
- return trx.rollback();
101
- }
102
- }
103
- async #purge(attachments) {
104
- return Promise.all(attachments.map(async (attachment) => {
105
- if (attachment.variants) {
106
- await Promise.all(attachment.variants.map(async (variant) => {
107
- if (this.#filters?.variants !== undefined && !this.#filters?.variants?.includes(variant.key)) {
108
- return;
109
- }
110
- return attachmentManager.remove(variant);
111
- }));
112
- if (this.#filters?.variants !== undefined) {
113
- attachment.variants = await attachment.variants.filter((variant) => !this.#filters?.variants?.includes(variant.key));
114
- }
115
- else {
116
- attachment.variants = [];
117
- }
118
- }
119
- }));
120
- }
121
- }
@@ -1,33 +0,0 @@
1
- import type { RowWithAttachment } from '../types/mixin.js';
2
- import type { Attachment as AttachmentType } from '../types/attachment.js';
3
- import type { RecordWithAttachment as RecordWithAttachmentImplementation } from '../types/service.js';
4
- import type { RegenerateOptions } from '../types/regenerate.js';
5
- export default class RecordWithAttachment implements RecordWithAttachmentImplementation {
6
- #private;
7
- constructor(row: RowWithAttachment);
8
- /**
9
- * During commit, we should cleanup the old detached files
10
- */
11
- commit(): Promise<void>;
12
- /**
13
- * During rollback we should remove the attached files.
14
- */
15
- rollback(): Promise<void>;
16
- persist(): Promise<void>;
17
- transaction(options?: {
18
- enabledRollback: boolean;
19
- }): Promise<void>;
20
- preComputeUrl(): Promise<void>;
21
- setKeyId(): Promise<void>;
22
- generateVariants(): Promise<void>;
23
- regenerateVariants(options?: RegenerateOptions): Promise<void>;
24
- detach(): Promise<PromiseSettledResult<void>[]>;
25
- detachAll(): Promise<PromiseSettledResult<void>[]>;
26
- get row(): RowWithAttachment;
27
- getAttachments(options: {
28
- attributeName: string;
29
- requiredOriginal?: boolean;
30
- requiredDirty?: boolean;
31
- }): AttachmentType[];
32
- }
33
- //# sourceMappingURL=record_with_attachment.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"record_with_attachment.d.ts","sourceRoot":"","sources":["../../../src/services/record_with_attachment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAgB,MAAM,wBAAwB,CAAA;AACxF,OAAO,KAAK,EAAE,oBAAoB,IAAI,kCAAkC,EAAE,MAAM,qBAAqB,CAAA;AACrG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAW/D,MAAM,CAAC,OAAO,OAAO,oBAAqB,YAAW,kCAAkC;;gBAGzE,GAAG,EAAE,iBAAiB;IAWlC;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ7B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDxB,WAAW,CAAC,OAAO;;KAA4B,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB/D,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB9B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BzB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BjC,kBAAkB,CAAC,OAAO,GAAE,iBAAsB;IAmClD,MAAM;IA2CN,SAAS;IAkBf,IAAI,GAAG,sBAEN;IAED,cAAc,CAAC,OAAO,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE;CAwEvG"}
@@ -1,303 +0,0 @@
1
- import logger from '@adonisjs/core/services/logger';
2
- import encryption from '@adonisjs/core/services/encryption';
3
- import attachmentManager from '../../services/main.js';
4
- import { defaultStateAttributeMixin } from '../utils/default_values.js';
5
- import { Attachment } from '../attachments/attachment.js';
6
- import { optionsSym } from '../utils/symbols.js';
7
- import { ConverterManager } from '../converter_manager.js';
8
- import { E_CANNOT_CREATE_VARIANT } from '../errors.js';
9
- export default class RecordWithAttachment {
10
- #row;
11
- constructor(row) {
12
- this.#row = row;
13
- if (!this.#row.$attachments) {
14
- /**
15
- * Empty previous $attachments
16
- */
17
- this.#row.$attachments = structuredClone(defaultStateAttributeMixin);
18
- }
19
- }
20
- /**
21
- * During commit, we should cleanup the old detached files
22
- */
23
- async commit() {
24
- await Promise.allSettled(this.#row.$attachments.detached.map((attachment) => attachmentManager.remove(attachment)));
25
- }
26
- /**
27
- * During rollback we should remove the attached files.
28
- */
29
- async rollback() {
30
- await Promise.allSettled(this.#row.$attachments.attached.map((attachment) => attachmentManager.remove(attachment)));
31
- }
32
- async persist() {
33
- const attachmentAttributeNames = this.#getDirtyAttributeNamesOfAttachment();
34
- /**
35
- * Persist attachments before saving the row to the database. This
36
- * way if file saving fails we will not write anything to the
37
- * database
38
- */
39
- await Promise.all(attachmentAttributeNames.map(async (name) => {
40
- const originalAttachments = this.#getOriginalAttachmentsByAttributeName(name);
41
- const newAttachments = this.#getAttachmentsByAttributeName(name);
42
- const options = this.#getOptionsByAttributeName(name);
43
- /**
44
- * Skip when the attachment attributeName hasn't been updated
45
- */
46
- if (!originalAttachments && !newAttachments) {
47
- return;
48
- }
49
- /**
50
- * memorise attribute name for generate variants
51
- */
52
- this.#row.$attachments.dirtied.push(name);
53
- for (let i = 0; i < newAttachments.length; i++) {
54
- if (originalAttachments.includes(newAttachments[i])) {
55
- continue;
56
- }
57
- /**
58
- * If there is a new file and its local then we must save this
59
- * file.
60
- */
61
- if (newAttachments[i]) {
62
- newAttachments[i].setOptions(options).makeFolder(this.#row);
63
- this.#row.$attachments.attached.push(newAttachments[i]);
64
- /**
65
- * Also write the file to the disk right away
66
- */
67
- await attachmentManager.write(newAttachments[i]);
68
- }
69
- }
70
- }));
71
- }
72
- async transaction(options = { enabledRollback: true }) {
73
- try {
74
- if (this.#row.$trx) {
75
- this.#row.$trx.after('commit', () => this.commit());
76
- if (options.enabledRollback) {
77
- this.#row.$trx.after('rollback', () => this.rollback());
78
- }
79
- }
80
- else {
81
- await this.commit();
82
- }
83
- }
84
- catch (error) {
85
- if (options.enabledRollback) {
86
- await this.rollback();
87
- }
88
- throw error;
89
- }
90
- }
91
- async preComputeUrl() {
92
- const attachmentAttributeNames = this.#getAttributeNamesOfAttachment();
93
- await Promise.all(attachmentAttributeNames.map(async (name) => {
94
- const options = this.#getOptionsByAttributeName(name);
95
- if (this.#row.$attributes[name]) {
96
- const attachments = this.#getAttachmentsByAttributeName(name);
97
- for (let i = 0; i < attachments.length; i++) {
98
- attachments[i].setOptions(options);
99
- await attachmentManager.preComputeUrl(attachments[i]);
100
- }
101
- }
102
- }));
103
- }
104
- async setKeyId() {
105
- const attachmentAttributeNames = this.#getAttributeNamesOfAttachment();
106
- await Promise.all(attachmentAttributeNames.map(async (name) => {
107
- if (this.#row.$attributes[name]) {
108
- const attachments = this.#getAttachmentsByAttributeName(name);
109
- for (let i = 0; i < attachments.length; i++) {
110
- const { disk, folder, meta, rename } = attachments[i].options;
111
- const model = this.#row.constructor;
112
- const key = encryption.encrypt({
113
- model: model.table,
114
- id: this.#row.$attributes['id'],
115
- attribute: name,
116
- options: {
117
- disk,
118
- folder,
119
- meta,
120
- rename
121
- }
122
- });
123
- attachments[i].setKeyId(key);
124
- }
125
- }
126
- }));
127
- }
128
- async generateVariants() {
129
- /* this.#row.$dirty is not avalable in afterSave hooks */
130
- const attachmentAttributeNames = this.#row.$attachments.dirtied;
131
- /**
132
- * For all properties Attachment
133
- * Launch async generation variants
134
- */
135
- for await (const name of attachmentAttributeNames) {
136
- const record = this;
137
- attachmentManager.queue.push({
138
- name: `${this.#row.constructor.name}-${name}`,
139
- async run() {
140
- const converterManager = new ConverterManager({
141
- record,
142
- attributeName: name,
143
- options: record.#getOptionsByAttributeName(name),
144
- });
145
- await converterManager.run();
146
- },
147
- })
148
- .onError = function (error) {
149
- if (error.message) {
150
- logger.error(error.message);
151
- }
152
- else {
153
- throw new E_CANNOT_CREATE_VARIANT([error]);
154
- }
155
- };
156
- }
157
- }
158
- async regenerateVariants(options = {}) {
159
- let attachmentAttributeNames;
160
- if (options.attributes?.length) {
161
- attachmentAttributeNames = options.attributes;
162
- }
163
- else {
164
- attachmentAttributeNames = this.#getAttributeNamesOfAttachment();
165
- }
166
- for await (const name of attachmentAttributeNames) {
167
- const record = this;
168
- attachmentManager.queue.push({
169
- name: `${this.#row.constructor.name}-${name}`,
170
- async run() {
171
- const converterManager = new ConverterManager({
172
- record,
173
- attributeName: name,
174
- options: record.#getOptionsByAttributeName(name),
175
- filters: {
176
- variants: options.variants
177
- }
178
- });
179
- await converterManager.run();
180
- },
181
- })
182
- .onError = function (error) {
183
- if (error.message) {
184
- logger.error(error.message);
185
- }
186
- else {
187
- throw new E_CANNOT_CREATE_VARIANT([error]);
188
- }
189
- };
190
- }
191
- }
192
- async detach() {
193
- const attachmentAttributeNames = this.#getDirtyAttributeNamesOfAttachment();
194
- /**
195
- * Mark all original attachments for deletion
196
- */
197
- return Promise.allSettled(attachmentAttributeNames.map((name) => {
198
- let attachments = [];
199
- const options = this.#getOptionsByAttributeName(name);
200
- if (this.#row.$dirty[name] === null) {
201
- attachments = this.#getOriginalAttachmentsByAttributeName(name);
202
- }
203
- else {
204
- const originalAttachments = this.#getOriginalAttachmentsByAttributeName(name);
205
- const newAttachments = this.#getAttachmentsByAttributeName(name);
206
- /**
207
- * Clean Attachments changed
208
- */
209
- for (let i = 0; i < originalAttachments.length; i++) {
210
- if (newAttachments.includes(originalAttachments[i])) {
211
- continue;
212
- }
213
- /**
214
- * If there was an existing file, then we must get rid of it
215
- */
216
- if (originalAttachments[i]) {
217
- originalAttachments[i].setOptions(options);
218
- attachments.push(originalAttachments[i]);
219
- }
220
- }
221
- }
222
- for (let i = 0; i < attachments.length; i++) {
223
- attachments[i].setOptions(options);
224
- this.#row.$attachments.detached.push(attachments[i]);
225
- }
226
- }));
227
- }
228
- async detachAll() {
229
- const attachmentAttributeNames = this.#getAttributeNamesOfAttachment();
230
- /**
231
- * Mark all attachments for deletion
232
- */
233
- return Promise.allSettled(attachmentAttributeNames.map((name) => {
234
- const options = this.#getOptionsByAttributeName(name);
235
- const attachments = this.#getAttachmentsByAttributeName(name);
236
- for (let i = 0; i < attachments.length; i++) {
237
- attachments[i].setOptions(options);
238
- this.#row.$attachments.detached.push(attachments[i]);
239
- }
240
- }));
241
- }
242
- get row() {
243
- return this.#row;
244
- }
245
- getAttachments(options) {
246
- let attachments;
247
- if (options.requiredOriginal) {
248
- attachments = this.#getOriginalAttachmentsByAttributeName(options.attributeName);
249
- }
250
- else if (options.requiredDirty) {
251
- attachments = this.#getDirtyAttachmentsByAttributeName(options.attributeName);
252
- }
253
- else {
254
- attachments = this.#getAttachmentsByAttributeName(options.attributeName);
255
- }
256
- const opts = this.#getOptionsByAttributeName(options.attributeName);
257
- attachments.map((attachment) => attachment.setOptions(opts).makeFolder(this.#row));
258
- return attachments;
259
- }
260
- #getAttachmentsByAttributeName(name) {
261
- if (Array.isArray(this.#row.$attributes[name])) {
262
- return this.#row.$attributes[name];
263
- }
264
- return [this.#row.$attributes[name]];
265
- }
266
- #getOriginalAttachmentsByAttributeName(name) {
267
- if (Array.isArray(this.#row.$original[name])) {
268
- return this.#row.$original[name];
269
- }
270
- return [this.#row.$original[name]];
271
- }
272
- #getDirtyAttachmentsByAttributeName(name) {
273
- if (Array.isArray(this.#row.$dirty[name])) {
274
- return this.#row.$dirty[name];
275
- }
276
- return [this.#row.$dirty[name]];
277
- }
278
- #getOptionsByAttributeName(name) {
279
- return this.#row.constructor.prototype[optionsSym]?.[name];
280
- }
281
- #getAttributeNamesOfAttachment() {
282
- return Object.keys(this.#row.$attributes).filter((name) => {
283
- const value = this.#row.$attributes[name];
284
- return (value instanceof Attachment ||
285
- (Array.isArray(value) && value.every((item) => item instanceof Attachment)));
286
- });
287
- }
288
- #getDirtyAttributeNamesOfAttachment() {
289
- return Object.keys(this.#row.$dirty).filter((name) => {
290
- const dirtyValue = this.#row.$dirty[name];
291
- const originalValue = this.#row.$original[name]; // if dirtyValue is null, check original type
292
- const isDirtyAttachment = dirtyValue instanceof Attachment ||
293
- (Array.isArray(dirtyValue) &&
294
- dirtyValue.length &&
295
- dirtyValue.every((item) => item instanceof Attachment));
296
- const isOriginalAttachment = originalValue instanceof Attachment ||
297
- (Array.isArray(originalValue) &&
298
- originalValue.length &&
299
- originalValue.every((item) => item instanceof Attachment));
300
- return isDirtyAttachment || isOriginalAttachment;
301
- });
302
- }
303
- }