@almadar/runtime 1.0.0 → 1.0.1

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.
@@ -1,5 +1,5 @@
1
1
  import { Router } from 'express';
2
- import { I as IEventBus, R as RuntimeEvent, e as EventListener, U as Unsubscribe, E as EffectHandlers, d as Effect, T as TraitState } from './types-JFCKD0FU.js';
2
+ import { I as IEventBus, R as RuntimeEvent, e as EventListener, U as Unsubscribe, E as EffectHandlers, d as Effect, T as TraitState } from './types-LiBPiu-u.js';
3
3
  import { OrbitalSchema, Orbital, Trait } from '@almadar/core';
4
4
 
5
5
  /**
@@ -689,6 +689,17 @@ declare class OrbitalServerRuntime {
689
689
  * Execute effects from a transition
690
690
  */
691
691
  private executeEffects;
692
+ /**
693
+ * Populate relation fields on entities
694
+ *
695
+ * For each field in `include`, find the relation field configuration and
696
+ * fetch the related entity, attaching it to the parent entity.
697
+ *
698
+ * @param entities - Entities to populate
699
+ * @param entityType - Entity type name
700
+ * @param include - Relation field names to populate
701
+ */
702
+ private populateRelations;
692
703
  /**
693
704
  * Create Express router for orbital API endpoints
694
705
  *
@@ -1,4 +1,4 @@
1
1
  import 'express';
2
- export { n as EffectResult, L as LoaderConfig, O as OrbitalEventRequest, c as OrbitalEventResponse, o as OrbitalServerRuntime, d as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RuntimeOrbital, h as RuntimeOrbitalSchema, i as RuntimeTrait, q as RuntimeTraitTick, r as createOrbitalServerRuntime } from './OrbitalServerRuntime-COj7K1yM.js';
3
- import './types-JFCKD0FU.js';
2
+ export { n as EffectResult, L as LoaderConfig, O as OrbitalEventRequest, c as OrbitalEventResponse, o as OrbitalServerRuntime, d as OrbitalServerRuntimeConfig, P as PersistenceAdapter, R as RuntimeOrbital, h as RuntimeOrbitalSchema, i as RuntimeTrait, q as RuntimeTraitTick, r as createOrbitalServerRuntime } from './OrbitalServerRuntime-W9FnSt1J.js';
3
+ import './types-LiBPiu-u.js';
4
4
  import '@almadar/core';
@@ -2988,12 +2988,16 @@ var OrbitalServerRuntime = class {
2988
2988
  },
2989
2989
  fetch: async (fetchEntityType, options) => {
2990
2990
  try {
2991
+ let result = null;
2991
2992
  if (options?.id) {
2992
2993
  const entity = await this.persistence.getById(fetchEntityType, options.id);
2993
2994
  if (entity) {
2995
+ if (options?.include && options.include.length > 0) {
2996
+ await this.populateRelations([entity], fetchEntityType, options.include);
2997
+ }
2994
2998
  fetchedData[fetchEntityType] = [entity];
2999
+ result = entity;
2995
3000
  }
2996
- return entity;
2997
3001
  } else {
2998
3002
  let entities = await this.persistence.list(fetchEntityType);
2999
3003
  if (options?.offset && options.offset > 0) {
@@ -3002,9 +3006,13 @@ var OrbitalServerRuntime = class {
3002
3006
  if (options?.limit && options.limit > 0) {
3003
3007
  entities = entities.slice(0, options.limit);
3004
3008
  }
3009
+ if (options?.include && options.include.length > 0) {
3010
+ await this.populateRelations(entities, fetchEntityType, options.include);
3011
+ }
3005
3012
  fetchedData[fetchEntityType] = entities;
3006
- return entities;
3013
+ result = entities;
3007
3014
  }
3015
+ return result;
3008
3016
  } catch (error) {
3009
3017
  console.error(`[OrbitalRuntime] Fetch error for ${fetchEntityType}:`, error);
3010
3018
  return null;
@@ -3053,6 +3061,84 @@ var OrbitalServerRuntime = class {
3053
3061
  await executor.executeAll(effects);
3054
3062
  }
3055
3063
  // ==========================================================================
3064
+ // Relation Population
3065
+ // ==========================================================================
3066
+ /**
3067
+ * Populate relation fields on entities
3068
+ *
3069
+ * For each field in `include`, find the relation field configuration and
3070
+ * fetch the related entity, attaching it to the parent entity.
3071
+ *
3072
+ * @param entities - Entities to populate
3073
+ * @param entityType - Entity type name
3074
+ * @param include - Relation field names to populate
3075
+ */
3076
+ async populateRelations(entities, entityType, include) {
3077
+ let entityFields;
3078
+ for (const [, registered] of this.orbitals) {
3079
+ if (registered.schema.entity.name === entityType) {
3080
+ entityFields = registered.schema.entity.fields;
3081
+ break;
3082
+ }
3083
+ }
3084
+ if (!entityFields) {
3085
+ if (this.config.debug) {
3086
+ console.warn(`[OrbitalRuntime] No entity definition found for ${entityType}`);
3087
+ }
3088
+ return;
3089
+ }
3090
+ for (const includeField of include) {
3091
+ const relationField = entityFields.find((f) => {
3092
+ if (f.type !== "relation") return false;
3093
+ return f.name === includeField || f.name === `${includeField}Id` || f.name.replace(/Id$/, "") === includeField;
3094
+ });
3095
+ if (!relationField?.relation?.entity) {
3096
+ if (this.config.debug) {
3097
+ console.warn(`[OrbitalRuntime] No relation field found for '${includeField}' on ${entityType}`);
3098
+ }
3099
+ continue;
3100
+ }
3101
+ const foreignKeyField = relationField.name;
3102
+ const relatedEntityType = relationField.relation.entity;
3103
+ const cardinality = relationField.relation.cardinality || "one";
3104
+ const foreignKeyIds = /* @__PURE__ */ new Set();
3105
+ for (const entity of entities) {
3106
+ const fkValue = entity[foreignKeyField];
3107
+ if (fkValue && typeof fkValue === "string") {
3108
+ foreignKeyIds.add(fkValue);
3109
+ }
3110
+ }
3111
+ if (foreignKeyIds.size === 0) continue;
3112
+ const relatedEntities = /* @__PURE__ */ new Map();
3113
+ for (const fkId of foreignKeyIds) {
3114
+ try {
3115
+ const related = await this.persistence.getById(relatedEntityType, fkId);
3116
+ if (related) {
3117
+ relatedEntities.set(fkId, related);
3118
+ }
3119
+ } catch (error) {
3120
+ if (this.config.debug) {
3121
+ console.error(`[OrbitalRuntime] Error fetching related ${relatedEntityType}:`, error);
3122
+ }
3123
+ }
3124
+ }
3125
+ const populatedFieldName = includeField.endsWith("Id") ? includeField.slice(0, -2) : includeField;
3126
+ for (const entity of entities) {
3127
+ const fkValue = entity[foreignKeyField];
3128
+ if (fkValue && relatedEntities.has(fkValue)) {
3129
+ if (cardinality === "one") {
3130
+ entity[populatedFieldName] = relatedEntities.get(fkValue);
3131
+ } else {
3132
+ entity[populatedFieldName] = [relatedEntities.get(fkValue)];
3133
+ }
3134
+ }
3135
+ }
3136
+ if (this.config.debug) {
3137
+ console.log(`[OrbitalRuntime] Populated '${populatedFieldName}' on ${entities.length} ${entityType} entities`);
3138
+ }
3139
+ }
3140
+ }
3141
+ // ==========================================================================
3056
3142
  // Express Router
3057
3143
  // ==========================================================================
3058
3144
  /**