@medyll/idae-machine 0.124.0 → 0.125.0

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 (36) hide show
  1. package/dist/form/CreateUpdate.svelte +2 -1
  2. package/dist/index.d.ts +18 -11
  3. package/dist/index.js +18 -11
  4. package/dist/main/machine/IDbCollection.d.ts +71 -0
  5. package/dist/main/machine/IDbCollection.js +102 -0
  6. package/dist/main/machine/IDbCollectionFieldForge.d.ts +42 -0
  7. package/dist/main/machine/IDbCollectionFieldForge.js +74 -0
  8. package/dist/main/machine/IDbCollectionFieldValues.d.ts +57 -0
  9. package/dist/main/machine/IDbCollectionFieldValues.js +82 -0
  10. package/dist/main/machine/IDbCollectionValues.d.ts +78 -0
  11. package/dist/main/machine/IDbCollectionValues.js +203 -0
  12. package/dist/main/machine/IDbError.d.ts +6 -0
  13. package/dist/main/machine/IDbError.js +61 -0
  14. package/dist/main/machine/IDbFormValidate.d.ts +55 -0
  15. package/dist/main/machine/IDbFormValidate.js +183 -0
  16. package/dist/main/machine/IDbValidationError.d.ts +19 -0
  17. package/dist/main/machine/IDbValidationError.js +24 -0
  18. package/dist/main/machineDb.d.ts +18 -222
  19. package/dist/main/machineDb.js +60 -653
  20. package/dist/main/machineForge.d.ts +57 -0
  21. package/dist/main/machineForge.js +105 -0
  22. package/dist/{form → ui}/CollectionButton.svelte +2 -2
  23. package/dist/{form → ui}/CollectionButton.svelte.d.ts +1 -1
  24. package/dist/{form → ui}/CollectionFks.svelte +3 -5
  25. package/dist/{form → ui}/CollectionList.svelte +1 -1
  26. package/dist/{form → ui}/CollectionListMenu.svelte +3 -2
  27. package/package.json +3 -3
  28. package/dist/form/DataList.svelte +0 -60
  29. package/dist/form/DataList.svelte.d.ts +0 -10
  30. /package/dist/{form → ui}/CollectionFieldGuess.svelte +0 -0
  31. /package/dist/{form → ui}/CollectionFieldGuess.svelte.d.ts +0 -0
  32. /package/dist/{form → ui}/CollectionFks.svelte.d.ts +0 -0
  33. /package/dist/{form → ui}/CollectionList.svelte.d.ts +0 -0
  34. /package/dist/{form → ui}/CollectionListMenu.svelte.d.ts +0 -0
  35. /package/dist/{form → ui}/CollectionReverseFks.svelte +0 -0
  36. /package/dist/{form → ui}/CollectionReverseFks.svelte.d.ts +0 -0
@@ -0,0 +1,203 @@
1
+ import { MachineDb } from '../machineDb.js';
2
+ import {} from '../machineForge.js';
3
+ import { IDbError } from './IDbError.js';
4
+ /**
5
+ * IDbCollectionValues
6
+ *
7
+ * This class provides utilities to display, format, and introspect field values for a given collection, using the schema and provided data.
8
+ * It is designed for dynamic UI rendering, presentation logic, and metadata extraction for form generation in schema-driven applications.
9
+ *
10
+ * Main responsibilities:
11
+ * - Holds a reference to the collection name and the schema (IDbBase).
12
+ * - Provides methods to format field values according to their type (number, text, array, object, etc.).
13
+ * - Supplies presentation logic for displaying records (e.g., presentation string, index value).
14
+ * - Offers input attribute generation for forms (inputDataSet).
15
+ * - Supports iteration over array/object fields for advanced UI layouts.
16
+ * - Enables access to field metadata for validation and rendering.
17
+ *
18
+ * Usage:
19
+ * const values = new IDbCollectionValues('agents');
20
+ * const display = values.presentation(agentData); // formatted display string
21
+ * const index = values.indexValue(agentData); // index field value
22
+ * const formatted = values.format('name', agentData); // formatted field value
23
+ * const attrs = values.getInputDataSet('name', agentData); // input attributes for forms
24
+ *
25
+ * This class is typically used via IDbBase.getCollectionValues for shared instance management.
26
+ * @template T - The type of the data object for the collection.
27
+ */
28
+ export class IDbCollectionValues {
29
+ /**
30
+ * The IDbBase instance used for schema introspection.
31
+ */
32
+ idbBase;
33
+ /**
34
+ * The collection name this instance operates on.
35
+ */
36
+ collectionName;
37
+ /**
38
+ * Create a new IDbCollectionValues instance for a given collection.
39
+ * @param collectionName The collection name.
40
+ */
41
+ constructor(collectionName, idbBase) {
42
+ this.collectionName = collectionName;
43
+ this.idbBase = idbBase ?? new MachineDb();
44
+ }
45
+ presentation(data) {
46
+ try {
47
+ this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
48
+ const presentation = this.idbBase.collection(this.collectionName).getPresentation();
49
+ this.#checkError(!presentation, 'Presentation template not found', 'TEMPLATE_NOT_FOUND');
50
+ const fields = presentation.split(' ');
51
+ return fields
52
+ .map((field) => {
53
+ const value = data[field];
54
+ return value !== null && value !== undefined ? String(value) : '';
55
+ })
56
+ .join(' ');
57
+ }
58
+ catch (error) {
59
+ IDbError.handleError(error);
60
+ return '';
61
+ }
62
+ }
63
+ /**
64
+ * Get the value of the index field for a data object.
65
+ * @param data The data object.
66
+ * @returns The value of the index field, or null if not found.
67
+ */
68
+ indexValue(data) {
69
+ try {
70
+ this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
71
+ const indexName = this.idbBase.collection(this.collectionName).getIndexName();
72
+ this.#checkError(!indexName, 'Index not found for collection', 'INDEX_NOT_FOUND');
73
+ this.#checkError(!(indexName in data), `Index field ${indexName} not found in data`, 'FIELD_NOT_FOUND');
74
+ return data[indexName];
75
+ }
76
+ catch (error) {
77
+ IDbError.handleError(error);
78
+ return null;
79
+ }
80
+ }
81
+ /**
82
+ * Format a field value for display, using the field type and schema.
83
+ * @param fieldName The field name.
84
+ * @param data The data object.
85
+ * @returns The formatted value as a string.
86
+ */
87
+ format(fieldName, data) {
88
+ try {
89
+ this.#checkError(!this.#checkAccess(), 'Access denied', 'ACCESS_DENIED');
90
+ this.#checkError(!(fieldName in data), `Field ${String(fieldName)} not found in data`, 'FIELD_NOT_FOUND');
91
+ const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
92
+ this.#checkError(!fieldInfo, `Field ${String(fieldName)} not found in collection`, 'FIELD_NOT_FOUND');
93
+ switch (fieldInfo?.fieldType) {
94
+ case 'number':
95
+ return this.#formatNumberField(data[fieldName]);
96
+ case 'text':
97
+ case 'text-tiny':
98
+ case 'text-short':
99
+ case 'text-medium':
100
+ case 'text-long':
101
+ case 'text-giant':
102
+ return this.#formatTextField(data[fieldName], fieldInfo.fieldType);
103
+ default:
104
+ return String(data[fieldName]);
105
+ }
106
+ }
107
+ catch (error) {
108
+ IDbError.handleError(error);
109
+ return '';
110
+ }
111
+ }
112
+ /**
113
+ * Get a set of data-* attributes for a field, for use in form generation or UI.
114
+ * @param fieldName The field name.
115
+ * @param data The data object.
116
+ * @returns An object with data-* attributes for the field.
117
+ */
118
+ getInputDataSet(fieldName, data) {
119
+ const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
120
+ const fieldType = fieldInfo?.fieldType ?? '';
121
+ const fieldArgs = fieldInfo?.fieldArgs?.join(' ') ?? '';
122
+ const indexName = this.idbBase.collection(this.collectionName).getIndexName();
123
+ return {
124
+ 'data-collection': this.collectionName,
125
+ 'data-collectionId': indexName && data?.[indexName] !== undefined ? String(data?.[indexName]) : '',
126
+ 'data-fieldName': String(fieldName),
127
+ 'data-fieldType': fieldType,
128
+ 'data-fieldArgs': fieldArgs
129
+ };
130
+ }
131
+ /**
132
+ * Iterate over an array field and return an array of IDbForge objects for each element.
133
+ * @param fieldName The field name.
134
+ * @param data The array data.
135
+ * @returns An array of IDbForge objects.
136
+ */
137
+ iterateArrayField(fieldName, data) {
138
+ const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
139
+ if (fieldInfo?.is !== 'array' || !Array.isArray(data)) {
140
+ return [];
141
+ }
142
+ return data.map((_, idx) => ({ ...fieldInfo, fieldName: `${String(fieldName)}[${idx}]` }));
143
+ }
144
+ /**
145
+ * Iterate over an object field and return an array of IDbForge objects for each property.
146
+ * @param fieldName The field name.
147
+ * @param data The object data.
148
+ * @returns An array of IDbForge objects.
149
+ */
150
+ iterateObjectField(fieldName, data) {
151
+ const fieldInfo = this.idbBase.parseCollectionFieldName(this.collectionName, fieldName);
152
+ if (fieldInfo?.is !== 'object' || typeof data !== 'object' || data === null) {
153
+ return [];
154
+ }
155
+ return Object.keys(data).map((key) => ({ ...fieldInfo, fieldName: `${String(fieldName)}.${key}` }));
156
+ }
157
+ /**
158
+ * Internal: Format a number field for display.
159
+ * @param value The number value.
160
+ * @returns The formatted string.
161
+ */
162
+ #formatNumberField(value) {
163
+ // Implement number formatting logic here
164
+ return value.toString();
165
+ }
166
+ /**
167
+ * Internal: Format a text field for display, with length limits by type.
168
+ * @param value The string value.
169
+ * @param type The text type (e.g. 'text-short').
170
+ * @returns The formatted string.
171
+ */
172
+ #formatTextField(value, type) {
173
+ const lengths = {
174
+ 'text-tiny': 10,
175
+ 'text-short': 20,
176
+ 'text-medium': 30,
177
+ 'text-long': 40,
178
+ 'text-giant': 50
179
+ };
180
+ const str = typeof value === 'string' ? value : String(value ?? '');
181
+ const maxLength = lengths[type] || str.length;
182
+ return str.substring(0, maxLength);
183
+ }
184
+ /**
185
+ * Internal: Check if access is allowed (override for custom logic).
186
+ * @returns True if access is allowed.
187
+ */
188
+ #checkAccess() {
189
+ // Implement access check logic here
190
+ return true;
191
+ }
192
+ /**
193
+ * Internal: Throw an error if a condition is met.
194
+ * @param condition The condition to check.
195
+ * @param message The error message.
196
+ * @param code The error code.
197
+ */
198
+ #checkError(condition, message, code) {
199
+ if (condition) {
200
+ IDbError.throwError(message, code);
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,6 @@
1
+ export declare class IDbError extends Error {
2
+ readonly code: string;
3
+ constructor(message: string, code: string);
4
+ static throwError(message: string, code: string): void;
5
+ static handleError(error: unknown): void;
6
+ }
@@ -0,0 +1,61 @@
1
+ /*
2
+ renamed from DbCollectionError to IDbErrors
3
+ */
4
+ export class IDbError extends Error {
5
+ code;
6
+ constructor(message, code) {
7
+ super(message);
8
+ this.code = code;
9
+ this.name = 'DbCollectionError';
10
+ }
11
+ static throwError(message, code) {
12
+ throw new IDbError(message, code);
13
+ }
14
+ static handleError(error) {
15
+ if (error instanceof IDbError) {
16
+ console.error(`${error.name}: ${error.message} (Code: ${error.code})`);
17
+ /**
18
+ * IDbError
19
+ *
20
+ * Custom error class for collection-related errors.
21
+ *
22
+ * Usage:
23
+ * throw new IDbError('Message', 'ERROR_CODE');
24
+ * IDbError.handleError(error);
25
+ */
26
+ export class IDbError extends Error {
27
+ code;
28
+ /**
29
+ * Create a new IDbError instance.
30
+ * @param message The error message.
31
+ * @param code The error code.
32
+ */
33
+ constructor(message, code) {
34
+ super(message);
35
+ this.code = code;
36
+ this.name = 'DbCollectionError';
37
+ }
38
+ /**
39
+ * Throw a new IDbError.
40
+ * @param message The error message.
41
+ * @param code The error code.
42
+ */
43
+ static throwError(message, code) {
44
+ throw new IDbError(message, code);
45
+ }
46
+ /**
47
+ * Handle an error, logging details if it's an IDbError.
48
+ * @param error The error to handle.
49
+ */
50
+ static handleError(error) {
51
+ if (error instanceof IDbError) {
52
+ console.error(`${error.name}: ${error.message} (Code: ${error.code})`);
53
+ }
54
+ else {
55
+ console.error('Unexpected error:', error);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,55 @@
1
+ import type { TplCollectionName, TplFields } from '@medyll/idae-idbql';
2
+ import { MachineDb } from '../machineDb.js';
3
+ /**
4
+ * IDbFormValidate
5
+ *
6
+ * Provides validation utilities for form fields in a collection.
7
+ *
8
+ * Main responsibilities:
9
+ * - Holds a reference to the collection and schema.
10
+ * - Validates field values according to type and arguments.
11
+ * - Supports custom validation for email, URL, phone, and date/time fields.
12
+ *
13
+ * Usage:
14
+ * const validator = new IDbFormValidate('agents');
15
+ * const result = validator.validateField('email', value);
16
+ */
17
+ export declare class IDbFormValidate {
18
+ #private;
19
+ private collection;
20
+ private idbCollections;
21
+ /**
22
+ * Create a new IDbFormValidate instance.
23
+ * @param collection The collection name.
24
+ * @param idbCollections Optional MachineDb instance.
25
+ */
26
+ constructor(collection: TplCollectionName, idbCollections?: MachineDb);
27
+ /**
28
+ * Validate a field value for the collection.
29
+ * @param fieldName The field name.
30
+ * @param value The value to validate.
31
+ * @returns An object with isValid and optional error.
32
+ */
33
+ validateField(fieldName: keyof TplFields, value: any): {
34
+ isValid: boolean;
35
+ error?: string;
36
+ };
37
+ /**
38
+ * Validate a single field value for a collection.
39
+ * @param fieldName The field name.
40
+ * @param value The value to validate.
41
+ * @returns True if valid, false otherwise.
42
+ */
43
+ validateFieldValue(fieldName: keyof TplFields, value: any): boolean;
44
+ validateForm(formData: Record<string, any>, options?: {
45
+ ignoreFields?: string[] | undefined;
46
+ }): {
47
+ isValid: boolean;
48
+ errors: Record<string, string>;
49
+ invalidFields: string[];
50
+ };
51
+ private validateEmail;
52
+ private validateUrl;
53
+ private validatePhone;
54
+ private validateDateTime;
55
+ }
@@ -0,0 +1,183 @@
1
+ import { MachineDb, enumPrimitive } from '../machineDb.js';
2
+ import { IDbValidationError } from './IDbValidationError.js';
3
+ /**
4
+ * IDbFormValidate
5
+ *
6
+ * Provides validation utilities for form fields in a collection.
7
+ *
8
+ * Main responsibilities:
9
+ * - Holds a reference to the collection and schema.
10
+ * - Validates field values according to type and arguments.
11
+ * - Supports custom validation for email, URL, phone, and date/time fields.
12
+ *
13
+ * Usage:
14
+ * const validator = new IDbFormValidate('agents');
15
+ * const result = validator.validateField('email', value);
16
+ */
17
+ export class IDbFormValidate {
18
+ collection;
19
+ idbCollections;
20
+ /**
21
+ * Create a new IDbFormValidate instance.
22
+ * @param collection The collection name.
23
+ * @param idbCollections Optional MachineDb instance.
24
+ */
25
+ constructor(collection, idbCollections) {
26
+ this.collection = collection;
27
+ this.idbCollections = idbCollections ?? new MachineDb();
28
+ }
29
+ /**
30
+ * Validate a field value for the collection.
31
+ * @param fieldName The field name.
32
+ * @param value The value to validate.
33
+ * @returns An object with isValid and optional error.
34
+ */
35
+ validateField(fieldName, value) {
36
+ try {
37
+ const fieldInfo = this.idbCollections.parseCollectionFieldName(this.collection, fieldName);
38
+ if (!fieldInfo) {
39
+ return { isValid: false, error: `Field ${String(fieldName)} not found in collection` };
40
+ }
41
+ // Type checking
42
+ if (!this.#validateType(value, fieldInfo.fieldType)) {
43
+ return this.#returnError(fieldName, fieldInfo.fieldType);
44
+ }
45
+ // Check field arguments (required, etc.)
46
+ if (fieldInfo.fieldArgs) {
47
+ for (const arg of fieldInfo.fieldArgs) {
48
+ if (arg === 'required' && (value === undefined || value === null || value === '')) {
49
+ return this.#returnError(fieldName, 'required');
50
+ }
51
+ }
52
+ }
53
+ // Specific validations according to field type
54
+ switch (fieldInfo.fieldType) {
55
+ case enumPrimitive.email:
56
+ if (!this.validateEmail(value)) {
57
+ return this.#returnError(fieldName, fieldInfo.fieldType);
58
+ }
59
+ break;
60
+ case enumPrimitive.url:
61
+ if (!this.validateUrl(value)) {
62
+ return this.#returnError(fieldName, fieldInfo.fieldType);
63
+ }
64
+ break;
65
+ case enumPrimitive.phone:
66
+ if (!this.validatePhone(value)) {
67
+ return this.#returnError(fieldName, fieldInfo.fieldType);
68
+ }
69
+ break;
70
+ case enumPrimitive.date:
71
+ case enumPrimitive.datetime:
72
+ case enumPrimitive.time:
73
+ if (!this.validateDateTime(value, fieldInfo.fieldType)) {
74
+ return this.#returnError(fieldName, fieldInfo.fieldType);
75
+ }
76
+ break;
77
+ // Add other specific cases here
78
+ }
79
+ return { isValid: true };
80
+ }
81
+ catch (error) {
82
+ if (error instanceof IDbValidationError) {
83
+ return { isValid: false, error: error.message };
84
+ }
85
+ throw error;
86
+ }
87
+ }
88
+ /**
89
+ * Validate a single field value for a collection.
90
+ * @param fieldName The field name.
91
+ * @param value The value to validate.
92
+ * @returns True if valid, false otherwise.
93
+ */
94
+ validateFieldValue(fieldName, value) {
95
+ const result = this.validateField(fieldName, value);
96
+ return !!result.isValid;
97
+ }
98
+ validateForm(formData, options = {}) {
99
+ const errors = {};
100
+ const invalidFields = [];
101
+ let isValid = true;
102
+ const fields = this.idbCollections.collection(this.collection).getTemplate().fields;
103
+ if (!fields) {
104
+ return {
105
+ isValid: false,
106
+ errors: { general: 'Collection template not found' },
107
+ invalidFields: ['general']
108
+ };
109
+ }
110
+ for (const [fieldName, fieldRule] of Object.entries(fields)) {
111
+ // Ignorer les champs spécifiés dans options.ignoreFields
112
+ if (options.ignoreFields && options.ignoreFields.includes(fieldName)) {
113
+ continue;
114
+ }
115
+ const result = this.validateField(fieldName, formData[fieldName]);
116
+ if (!result.isValid) {
117
+ errors[fieldName] = result.error || 'Invalid field';
118
+ invalidFields.push(fieldName);
119
+ isValid = false;
120
+ }
121
+ }
122
+ return { isValid, errors, invalidFields };
123
+ }
124
+ #validateType(value, type) {
125
+ switch (type) {
126
+ case enumPrimitive.number:
127
+ return typeof value === 'number' && !isNaN(value);
128
+ case enumPrimitive.boolean:
129
+ return typeof value === 'boolean';
130
+ case enumPrimitive.text:
131
+ case enumPrimitive.email:
132
+ case enumPrimitive.url:
133
+ case enumPrimitive.phone:
134
+ case enumPrimitive.password:
135
+ return typeof value === 'string';
136
+ case enumPrimitive.date:
137
+ case enumPrimitive.datetime:
138
+ case enumPrimitive.time:
139
+ return value instanceof Date || typeof value === 'string';
140
+ case enumPrimitive.any:
141
+ return true;
142
+ default:
143
+ return true; // Pour les types non gérés, on considère que c'est valide
144
+ }
145
+ }
146
+ #returnError(fieldName, enumCode) {
147
+ throw new IDbValidationError(String(fieldName), enumCode ?? 'unknown', `Invalid format for field ${String(fieldName)}. Cause "${enumCode}" `);
148
+ }
149
+ validateEmail(email) {
150
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
151
+ return emailRegex.test(email);
152
+ }
153
+ validateUrl(url) {
154
+ try {
155
+ new URL(url);
156
+ return true;
157
+ }
158
+ catch {
159
+ return false;
160
+ }
161
+ }
162
+ validatePhone(phone) {
163
+ // Ceci est un exemple simple. Vous pouvez ajuster selon vos besoins spécifiques
164
+ const phoneRegex = /^\+?[\d\s-]{10,}$/;
165
+ return phoneRegex.test(phone);
166
+ }
167
+ validateDateTime(value, type) {
168
+ const date = value instanceof Date ? value : new Date(value);
169
+ if (isNaN(date.getTime()))
170
+ return false;
171
+ switch (type) {
172
+ case enumPrimitive.date:
173
+ return true; // La conversion en Date a déjà validé le format
174
+ case enumPrimitive.time:
175
+ // Vérifiez si la chaîne contient uniquement l'heure
176
+ return /^([01]\d|2[0-3]):([0-5]\d)(:([0-5]\d))?$/.test(value);
177
+ case enumPrimitive.datetime:
178
+ return true; // La conversion en Date a déjà validé le format
179
+ default:
180
+ return false;
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * IDbValidationError
3
+ *
4
+ * Custom error class for validation errors on form fields.
5
+ *
6
+ * Usage:
7
+ * throw new IDbValidationError('email', 'INVALID_EMAIL', 'Invalid email address');
8
+ */
9
+ export declare class IDbValidationError extends Error {
10
+ field: string;
11
+ code: string;
12
+ /**
13
+ * Create a new IDbValidationError instance.
14
+ * @param field The field name.
15
+ * @param code The error code.
16
+ * @param message The error message.
17
+ */
18
+ constructor(field: string, code: string, message: string);
19
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * IDbValidationError
3
+ *
4
+ * Custom error class for validation errors on form fields.
5
+ *
6
+ * Usage:
7
+ * throw new IDbValidationError('email', 'INVALID_EMAIL', 'Invalid email address');
8
+ */
9
+ export class IDbValidationError extends Error {
10
+ field;
11
+ code;
12
+ /**
13
+ * Create a new IDbValidationError instance.
14
+ * @param field The field name.
15
+ * @param code The error code.
16
+ * @param message The error message.
17
+ */
18
+ constructor(field, code, message) {
19
+ super(message);
20
+ this.field = field;
21
+ this.code = code;
22
+ this.name = 'IDbValidationError';
23
+ }
24
+ }