@adaas/a-concept 0.3.1 → 0.3.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaas/a-concept",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A-Concept is a framework of the new generation that is tailored to use AI, enabling developers to create AI-powered applications with ease. It provides a structured approach to building, managing, and deploying AI-driven solutions.",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -31,7 +31,7 @@ export class A_CONCEPT_BASE_ENV {
31
31
  * Environment of the application e.g. development, production, staging
32
32
  */
33
33
  static get A_CONCEPT_ENVIRONMENT() {
34
- return "production";
34
+ return "development";
35
35
  }
36
36
  /**
37
37
  * Runtime environment of the application e.g. browser, node
@@ -36,9 +36,9 @@ import {
36
36
  } from "@adaas/a-concept/a-entity";
37
37
  import { A_TYPES__A_StageStep } from "@adaas/a-concept/a-stage";
38
38
  import { A_TYPES__ContextEnvironment } from "./A-Context.types";
39
- import { A_TypeGuards} from "@adaas/a-concept/helpers/A_TypeGuards.helper";
40
- import { A_FormatterHelper} from "@adaas/a-concept/helpers/A_Formatter.helper";
41
- import { A_CommonHelper} from "@adaas/a-concept/helpers/A_Common.helper";
39
+ import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
40
+ import { A_FormatterHelper } from "@adaas/a-concept/helpers/A_Formatter.helper";
41
+ import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
42
42
  import { A_ContextError } from "./A-Context.error";
43
43
  import {
44
44
  A_Fragment,
@@ -684,17 +684,7 @@ export class A_Context {
684
684
  throw new A_ContextError(A_ContextError.InvalidScopeParameterError, `Invalid parameter provided to get scope. Component of type ${name} is not allowed for scope allocation.`);
685
685
 
686
686
  switch (true) {
687
- case this.isAllowedForScopeAllocation(param1):
688
-
689
- // Check if the parameter has a scope allocated
690
- if (!instance._registry.has(param1))
691
- throw new A_ContextError(
692
- A_ContextError.ScopeNotFoundError,
693
- `Invalid parameter provided to get scope. Component of type ${name} does not have a scope allocated. Make sure to allocate a scope using A_Context.allocate() method before trying to get the scope.`
694
- );
695
687
 
696
- // If the parameter is allowed for scope allocation, return the scope
697
- return instance._registry.get(param1)!;
698
688
 
699
689
  case this.isAllowedToBeRegistered(param1):
700
690
 
@@ -707,6 +697,18 @@ export class A_Context {
707
697
 
708
698
  // If the parameter is allowed to be registered, return the scope from the storage
709
699
  return instance._scopeStorage.get(param1)!;
700
+
701
+ case this.isAllowedForScopeAllocation(param1):
702
+
703
+ // Check if the parameter has a scope allocated
704
+ if (!instance._registry.has(param1))
705
+ throw new A_ContextError(
706
+ A_ContextError.ScopeNotFoundError,
707
+ `Invalid parameter provided to get scope. Component of type ${name} does not have a scope allocated. Make sure to allocate a scope using A_Context.allocate() method before trying to get the scope.`
708
+ );
709
+
710
+ // If the parameter is allowed for scope allocation, return the scope
711
+ return instance._registry.get(param1)!;
710
712
  default:
711
713
  throw new A_ContextError(A_ContextError.InvalidScopeParameterError, `Invalid parameter provided to get scope. Component of type ${name} is not allowed to be registered.`);
712
714
  }
@@ -1076,7 +1078,8 @@ export class A_Context {
1076
1078
  */
1077
1079
  static isAllowedForScopeAllocation(param: any): param is A_TYPES__ScopeLinkedComponents {
1078
1080
  return A_TypeGuards.isContainerInstance(param)
1079
- || A_TypeGuards.isFeatureInstance(param);
1081
+ || A_TypeGuards.isFeatureInstance(param)
1082
+ || A_TypeGuards.isEntityInstance(param);
1080
1083
  }
1081
1084
  /**
1082
1085
  * Type guard to check if the param is allowed to be registered in the context.
@@ -0,0 +1,90 @@
1
+
2
+ import { A_Context } from "@adaas/a-concept/a-context";
3
+ import { A_Meta } from "@adaas/a-concept/a-meta";
4
+ import { A_TYPES__ComponentMetaKey } from "@adaas/a-concept/a-component";
5
+ import { A_TYPES__ContainerMetaKey } from "@adaas/a-concept/a-container";
6
+ import { A_TYPES__A_Dependency_EntityInjectionPagination, A_TYPES__A_Dependency_EntityInjectionQuery, A_TYPES__A_Dependency_EntityResolutionConfig, A_TYPES__A_Dependency_QueryDecoratorReturn } from "./A-Dependency.types";
7
+ import { A_DependencyError } from "./A-Dependency.error";
8
+ import type { A_Entity } from "@adaas/a-concept/a-entity";
9
+ import { A_TYPES__EntityMetaKey } from "@adaas/a-concept/a-entity";
10
+ import {
11
+ A_TYPES__A_InjectDecorator_Meta,
12
+ A_TYPES__InjectableTargets
13
+ } from "@adaas/a-concept/a-inject";
14
+ import { A_TypeGuards } from "@adaas/a-concept/helpers/A_TypeGuards.helper";
15
+ import { A_CommonHelper } from "@adaas/a-concept/helpers/A_Common.helper";
16
+
17
+ /**
18
+ * Query Decorator is only applicable for Entities since Scope instance may have multiple entities but only one component or container, so there is no need for such complex resolution strategies for them, but for entities it is a common case to have multiple instances and need to specify which one(s) to inject.
19
+ *
20
+ *
21
+ * @param query
22
+ * @returns
23
+ */
24
+ export function A_Dependency_Query<T extends A_Entity = A_Entity>(
25
+ query: Partial<A_TYPES__A_Dependency_EntityInjectionQuery<T>>,
26
+ pagination?: Partial<A_TYPES__A_Dependency_EntityInjectionPagination>
27
+ ): A_TYPES__A_Dependency_QueryDecoratorReturn {
28
+
29
+ return function (
30
+ target: A_TYPES__InjectableTargets,
31
+ methodName: string | symbol | undefined,
32
+ parameterIndex: number
33
+ ) {
34
+ // for Error handling purposes
35
+ const componentName = A_CommonHelper.getComponentName(target)
36
+
37
+ if (!A_TypeGuards.isTargetAvailableForInjection(target)) {
38
+ throw new A_DependencyError(
39
+ A_DependencyError.InvalidDependencyTarget,
40
+ `A-All cannot be used on the target of type ${typeof target} (${componentName})`
41
+ );
42
+ }
43
+
44
+ // determine the method name or 'constructor' for constructor injections
45
+ const method = methodName ? String(methodName) : 'constructor';
46
+ let metaKey;
47
+
48
+ switch (true) {
49
+ case A_TypeGuards.isComponentConstructor(target) || A_TypeGuards.isComponentInstance(target):
50
+ metaKey = A_TYPES__ComponentMetaKey.INJECTIONS;
51
+ break;
52
+
53
+ case A_TypeGuards.isContainerInstance(target):
54
+ metaKey = A_TYPES__ContainerMetaKey.INJECTIONS;
55
+ break;
56
+
57
+ case A_TypeGuards.isEntityInstance(target):
58
+ metaKey = A_TYPES__EntityMetaKey.INJECTIONS;
59
+ break;
60
+ }
61
+
62
+ // get existing meta or create a new one
63
+ const existedMeta = A_Context.meta(target).get(metaKey) || new A_Meta();
64
+ // get existing injections for the method or create a new array
65
+ const paramsArray: A_TYPES__A_InjectDecorator_Meta = existedMeta.get(method) || [];
66
+
67
+ // set the parameter injection info
68
+ paramsArray[parameterIndex].resolutionStrategy = {
69
+ query: {
70
+ ...paramsArray[parameterIndex].resolutionStrategy.query,
71
+ ...query
72
+ },
73
+ pagination: {
74
+ ...paramsArray[parameterIndex].resolutionStrategy.pagination,
75
+ ...pagination
76
+ }
77
+ }
78
+
79
+ // save back the updated injections array
80
+ existedMeta.set(method, paramsArray);
81
+
82
+ // save back the updated meta info
83
+ A_Context
84
+ .meta(target)
85
+ .set(
86
+ metaKey,
87
+ existedMeta
88
+ );
89
+ }
90
+ }
@@ -14,6 +14,7 @@ import {
14
14
  } from "./A-Dependency.types";
15
15
  import { A_TYPES__Ctor } from "@adaas/a-concept/types";
16
16
  import { A_Dependency_All } from "./A-Dependency-All.decorator";
17
+ import { A_Dependency_Query } from "./A-Dependency-Query.decorator";
17
18
 
18
19
 
19
20
  export class A_Dependency<
@@ -74,6 +75,16 @@ export class A_Dependency<
74
75
  return A_Dependency_All;
75
76
  }
76
77
 
78
+ /**
79
+ * Allows to indicate that the dependency should be resolved by specific query parameters
80
+ * e.g. by ASEID, name, type, custom properties, etc.
81
+ *
82
+ * @returns
83
+ */
84
+ static get Query(): typeof A_Dependency_Query {
85
+ return A_Dependency_Query;
86
+ }
87
+
77
88
  protected _name: string;
78
89
  protected _target?: A_TYPES__Ctor<T>;
79
90
  protected _resolutionStrategy!: A_TYPES__A_DependencyResolutionStrategy;
@@ -4,7 +4,7 @@ import { A_TYPES__Ctor } from "@adaas/a-concept/types";
4
4
  import { A_Caller } from "@adaas/a-concept/a-caller";
5
5
  import { A_Component } from "@adaas/a-concept/a-component";
6
6
  import { A_Container } from "@adaas/a-concept/a-container";
7
- import { A_Entity } from "@adaas/a-concept/a-entity"
7
+ import { A_Entity, A_TYPES__Entity_Constructor } from "@adaas/a-concept/a-entity"
8
8
  import { A_Error } from "@adaas/a-concept/a-error";
9
9
  import { A_Feature } from "@adaas/a-concept/a-feature";
10
10
  import { A_Fragment } from "@adaas/a-concept/a-fragment";
@@ -163,3 +163,14 @@ export type A_TYPES__A_Dependency_AllDecoratorReturn<T = any> = (
163
163
  propertyKey: string | symbol | undefined,
164
164
  parameterIndex: number
165
165
  ) => void
166
+
167
+ export type A_TYPES__A_Dependency_QueryTarget<T extends A_Entity = A_Entity> = T
168
+ | A_TYPES__Entity_Constructor<T>
169
+ /**
170
+ * A-Dependency Query decorator return type
171
+ */
172
+ export type A_TYPES__A_Dependency_QueryDecoratorReturn<T = any> = (
173
+ target: T,
174
+ propertyKey: string | symbol | undefined,
175
+ parameterIndex: number
176
+ ) => void
@@ -13,5 +13,6 @@ export { A_Dependency_Flat } from './A-Dependency-Flat.decorator';
13
13
  export { A_Dependency_Load } from './A-Dependency-Load.decorator';
14
14
  export { A_Dependency_Parent } from './A-Dependency-Parent.decorator';
15
15
  export { A_Dependency_Require } from './A-Dependency-Require.decorator';
16
+ export { A_Dependency_Query } from './A-Dependency-Query.decorator';
16
17
 
17
18
 
@@ -179,8 +179,10 @@ export class A_Scope<
179
179
  get parent(): A_Scope | undefined {
180
180
  return this._parent;
181
181
  }
182
+
182
183
  /**
183
- * A_Scope refers to the visibility and accessibility of :
184
+ * A_Scope is a unique A-Concept Structure that allows to operate with A-Concept Primitives and Models in a specific context and with specific rules.
185
+ * It refers to the visibility and accessibility of :
184
186
  * - variables,
185
187
  * - Components,
186
188
  * - Context Fragments
@@ -89,7 +89,7 @@ export type A_TYPES__ScopeLinkedConstructors = A_TYPES__Container_Constructor |
89
89
  /**
90
90
  * A list of components that can have a scope associated with them
91
91
  */
92
- export type A_TYPES__ScopeLinkedComponents = A_Container | A_Feature;
92
+ export type A_TYPES__ScopeLinkedComponents = A_Container | A_Feature | A_Entity
93
93
  /**
94
94
  * A list of components that are dependent on a scope and do not have their own scope
95
95
  */
@@ -455,4 +455,71 @@ describe('A-Dependency tests', () => {
455
455
 
456
456
  });
457
457
 
458
+ it('Should be possible to use query decorator for A_Entities in scope', async () => {
459
+
460
+ class MyEntity_A extends A_Entity<{ name: string, group: string }> {
461
+ name!: string;
462
+ group!: string;
463
+
464
+ fromNew(newEntity: { name: string; group: string }): void {
465
+ super.fromNew(newEntity);
466
+ this.name = newEntity.name;
467
+ this.group = newEntity.group;
468
+ }
469
+ }
470
+
471
+ class MyComponent extends A_Component {
472
+ @A_Feature.Extend()
473
+ async simpleQuery(
474
+ @A_Dependency.Query<MyEntity_A>({ name: 'Entity 1' })
475
+ @A_Inject(MyEntity_A) entity: MyEntity_A,
476
+ ) {
477
+ expect(entity.name).toBe('Entity 1');
478
+ }
479
+
480
+ @A_Feature.Extend()
481
+ async andQuery(
482
+ @A_Dependency.Query<MyEntity_A>({ name: 'Entity 1', group: 'Group 1' })
483
+ @A_Inject(MyEntity_A) entity: MyEntity_A,
484
+ ) {
485
+ expect(entity.name).toBe('Entity 1');
486
+ expect(entity.group).toBe('Group 1');
487
+ }
488
+
489
+ @A_Feature.Extend()
490
+ async paginationQuery(
491
+ @A_Dependency.Query<MyEntity_A>({ name: 'Entity 1' }, { count: 2 })
492
+ @A_Inject(MyEntity_A) entities: MyEntity_A[],
493
+ ) {
494
+
495
+ expect(entities.length).toBe(2);
496
+ expect(entities[0].name).toBe('Entity 1');
497
+ expect(entities[0].group).toBe('Group 1');
498
+ expect(entities[1].name).toBe('Entity 1');
499
+ expect(entities[1].group).toBe('Group 2');
500
+ }
501
+ }
502
+
503
+ const scope = new A_Scope({
504
+ name: 'Test Scope',
505
+ components: [MyComponent],
506
+ entities: [
507
+ new MyEntity_A({ name: 'Entity 1', group: 'Group 1' }),
508
+ new MyEntity_A({ name: 'Entity 2', group: 'Group 1' }),
509
+ new MyEntity_A({ name: 'Entity 1', group: 'Group 2' }),
510
+ new MyEntity_A({ name: 'Entity 2', group: 'Group 2' }),
511
+ new MyEntity_A({ name: 'Entity 3', group: 'Group 2' }),
512
+ new MyEntity_A({ name: 'Entity 1', group: 'Group 3' }),
513
+ new MyEntity_A({ name: 'Entity 2', group: 'Group 3' }),
514
+ ]
515
+ });
516
+
517
+ const componentInstance = scope.resolve(MyComponent);
518
+
519
+ await componentInstance?.call('simpleQuery');
520
+ await componentInstance?.call('andQuery');
521
+ await componentInstance?.call('paginationQuery');
522
+
523
+ });
524
+
458
525
  });
@@ -6,6 +6,7 @@ import {
6
6
  } from "@adaas/a-concept/a-entity";
7
7
  import { A_Feature } from "@adaas/a-concept/a-feature";
8
8
  import { ASEID } from '@adaas/a-concept/aseid';
9
+ import { A_Scope } from "@adaas/a-concept/a-scope";
9
10
 
10
11
  jest.retryTimes(0);
11
12
 
@@ -21,6 +22,106 @@ describe('A-Entity tests', () => {
21
22
  expect(entity.aseid.concept).toBe('a-concept');
22
23
 
23
24
  });
25
+ it('Should handle proper types declaration', async () => {
26
+ type MyInitType = {
27
+ name: string;
28
+ customId: number;
29
+ }
30
+
31
+ type mySerializedType = {
32
+ name: string;
33
+ serializedFlag: boolean;
34
+ customId: number;
35
+ } & A_TYPES__Entity_Serialized;
36
+
37
+ class MyEntity extends A_Entity<MyInitType, mySerializedType> {
38
+ public name!: string;
39
+ public customId!: number;
40
+
41
+ fromNew(newEntity: MyInitType): void {
42
+ super.fromNew(newEntity);
43
+ this.name = newEntity.name;
44
+ this.customId = newEntity.customId;
45
+ }
46
+
47
+ fromJSON(serialized: mySerializedType): void {
48
+ this.aseid = new ASEID(serialized.aseid);
49
+ this.name = serialized.name;
50
+ this.customId = serialized.customId;
51
+ return;
52
+ }
53
+
54
+
55
+ toJSON(): mySerializedType {
56
+ return {
57
+ ...super.toJSON(),
58
+ name: this.name,
59
+ customId: this.customId,
60
+ serializedFlag: true,
61
+ };
62
+ }
63
+ }
64
+
65
+
66
+ const entityInstance = new MyEntity({
67
+ name: 'Test Entity',
68
+ customId: 42,
69
+ });
70
+
71
+ expect(entityInstance.name).toBe('Test Entity');
72
+ expect(entityInstance.customId).toBe(42);
73
+
74
+ const serialized = entityInstance.toJSON();
75
+ expect(serialized.name).toBe('Test Entity');
76
+ expect(serialized.customId).toBe(42);
77
+ expect(serialized.serializedFlag).toBe(true);
78
+
79
+ const deserializedEntity = new MyEntity(serialized);
80
+ expect(deserializedEntity.name).toBe('Test Entity');
81
+ expect(deserializedEntity.customId).toBe(42);
82
+ expect(deserializedEntity.aseid.toString()).toBe(entityInstance.aseid.toString());
83
+ });
84
+ it('Should be possible to allocate a scope for entity', async () => {
85
+
86
+ let resultScope: A_Scope | undefined = undefined;
87
+
88
+
89
+ class MyEntity extends A_Entity {
90
+
91
+ scope!: A_Scope;
92
+
93
+ fromNew(newEntity: any): void {
94
+ super.fromNew(newEntity);
95
+
96
+ resultScope = new A_Scope({ name: 'entity-scope' });
97
+
98
+ this.scope = A_Context.allocate(this, resultScope);
99
+ }
100
+
101
+ fromUndefined(): void {
102
+ super.fromUndefined();
103
+
104
+ resultScope = new A_Scope({ name: 'entity-scope' });
105
+
106
+ this.scope = A_Context.allocate(this, resultScope);
107
+ }
108
+
109
+ }
110
+
111
+
112
+ const entityInstance = new MyEntity();
113
+
114
+
115
+ const ParentScope = new A_Scope({
116
+ name: 'parent-scope',
117
+ entities: [entityInstance]
118
+ });
119
+
120
+ expect(resultScope).toBeInstanceOf(A_Scope);
121
+ expect(entityInstance.scope).toBe(resultScope);
122
+ expect(resultScope!.issuer()).toBe(entityInstance);
123
+ expect(A_Context.scope(entityInstance)).toBe(ParentScope);
124
+ });
24
125
  it('Should Allow to create an entity with overridden ASEID Scope or Concept', async () => {
25
126
  class MyEntity extends A_Entity {
26
127
  static get entity(): string {