meadow-integration 1.1.0 → 1.1.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.
package/package.json
CHANGED
|
@@ -50,12 +50,29 @@ function abbreviationFor(pEntityName, pContext)
|
|
|
50
50
|
return _deriveAbbreviation(pEntityName);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* The GUID column width for an entity, or 0 (unbounded) if unknown.
|
|
55
|
+
*
|
|
56
|
+
* Prefers the live schema width (`SchemaSizes`, populated for the entity actually being imported), then
|
|
57
|
+
* falls back to the host catalog's declared `GUIDSize`. The fallback is LOAD-BEARING for JOIN compose:
|
|
58
|
+
* when a child references a parent (e.g. Product → Material), only the CHILD's schema is loaded, so
|
|
59
|
+
* `SchemaSizes` has no entry for the parent. Without the catalog width the parent's foreign-key GUID is
|
|
60
|
+
* composed unbounded (never hashed) while the parent's OWN GUID was hashed to fit its column — so a long
|
|
61
|
+
* key makes the two diverge and the cross-session match silently breaks. The catalog `GUIDSize` MUST
|
|
62
|
+
* therefore match the parent's real GUID column width for long keys to resolve.
|
|
63
|
+
*/
|
|
54
64
|
function _maxLengthFor(pEntityName, pContext)
|
|
55
65
|
{
|
|
56
66
|
const tmpSizes = (pContext && pContext.SchemaSizes) || {};
|
|
57
|
-
const
|
|
58
|
-
|
|
67
|
+
const tmpSchemaSize = Number(tmpSizes[pEntityName] || 0);
|
|
68
|
+
if (tmpSchemaSize > 0)
|
|
69
|
+
{
|
|
70
|
+
return tmpSchemaSize;
|
|
71
|
+
}
|
|
72
|
+
const tmpCatalog = (pContext && pContext.Catalog) || {};
|
|
73
|
+
const tmpEntry = tmpCatalog[pEntityName];
|
|
74
|
+
const tmpCatalogSize = tmpEntry ? Number(tmpEntry.GUIDSize || 0) : 0;
|
|
75
|
+
return (tmpCatalogSize > 0) ? tmpCatalogSize : 0;
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
/** Build a compose spec (prefix + ordered segments + length budget) for an entity's fullGUID. */
|
|
@@ -129,6 +129,38 @@ suite
|
|
|
129
129
|
}
|
|
130
130
|
);
|
|
131
131
|
test
|
|
132
|
+
(
|
|
133
|
+
'a long parent key hashes IDENTICALLY for the own GUID and a cross-session FK (catalog GUIDSize fallback)',
|
|
134
|
+
() =>
|
|
135
|
+
{
|
|
136
|
+
// Mirrors the live failure: a parent key long enough to overflow the parent's GUID column.
|
|
137
|
+
// The parent's OWN GUID is hashed to fit (its schema width is loaded during the parent import);
|
|
138
|
+
// the child is imported SEPARATELY, so only the CHILD's schema width is loaded — the parent's
|
|
139
|
+
// width has to come from the host catalog, or the FK is composed unbounded and never matches.
|
|
140
|
+
const tmpCatalog = { Material: { Abbrev: 'M', GUIDSize: 36 }, Product: { Abbrev: 'PR', GUIDSize: 96 } };
|
|
141
|
+
const tmpLongKey = 'ZZHASHKEY_' + 'A'.repeat(32); // UI_M + 42 chars overflows 36 -> must hash
|
|
142
|
+
|
|
143
|
+
// Parent import — Material's 36-char column width is present in SchemaSizes.
|
|
144
|
+
const tmpMaterialStrategy = libEngine.compileGUIDStrategy(
|
|
145
|
+
{ Prefix: 'UI', Entities: { Material: { Mode: 'prefixed', OwnKeyColumn: 'MaterialKey' } } },
|
|
146
|
+
{ Catalog: tmpCatalog, SchemaSizes: { Material: 36 } }).Strategies.Material;
|
|
147
|
+
const tmpMaterialComp = runOneEntity(newTransform(), { Entity: 'Material', GUIDName: 'GUIDMaterial', GUIDStrategy: tmpMaterialStrategy, Mappings: {} }, { MaterialKey: tmpLongKey });
|
|
148
|
+
const tmpMaterialGUID = Object.keys(tmpMaterialComp)[0];
|
|
149
|
+
Expect(tmpMaterialGUID.length, 'parent own GUID fits its 36-char column').to.be.at.most(36);
|
|
150
|
+
Expect(tmpMaterialGUID.indexOf('AAAA'), 'parent own GUID was hashed, not raw').to.equal(-1);
|
|
151
|
+
|
|
152
|
+
// Child import (separate session) — ONLY Product's width is in SchemaSizes; Material's width must
|
|
153
|
+
// come from the catalog for the FK to hash the same way.
|
|
154
|
+
const tmpProductStrategy = libEngine.compileGUIDStrategy(
|
|
155
|
+
{ Prefix: 'UI', Entities: { Product: { Mode: 'prefixed', OwnKeyColumn: 'ProductKey', Joins: [ { ParentEntity: 'Material', Mode: 'prefixed', KeyColumn: 'MaterialKey', CrossSession: true } ] } } },
|
|
156
|
+
{ Catalog: tmpCatalog, SchemaSizes: { Product: 96 } }).Strategies.Product;
|
|
157
|
+
const tmpProductComp = runOneEntity(newTransform(), { Entity: 'Product', GUIDName: 'GUIDProduct', GUIDStrategy: tmpProductStrategy, Mappings: {} }, { ProductKey: 'PRLONG1', MaterialKey: tmpLongKey });
|
|
158
|
+
const tmpProductGUID = Object.keys(tmpProductComp)[0];
|
|
159
|
+
|
|
160
|
+
Expect(tmpProductComp[tmpProductGUID]._GUIDMaterial, 'long-key FK hashes identically to the parent own GUID').to.equal(tmpMaterialGUID);
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
test
|
|
132
164
|
(
|
|
133
165
|
'a non-strategy mapping still uses the flat GUIDTemplate (no behavior change)',
|
|
134
166
|
() =>
|