@pattern-stack/codegen 0.7.2 → 0.7.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.
package/package.json
CHANGED
|
@@ -64,6 +64,12 @@ export const <%= entityNamePlural %> = pgTable(
|
|
|
64
64
|
deletedAt: timestamp('deleted_at'),
|
|
65
65
|
<%_ } _%>
|
|
66
66
|
},
|
|
67
|
+
<%_ if (hasExternalIdTracking) { _%>
|
|
68
|
+
(t) => [
|
|
69
|
+
// external_id_tracking behavior — ON CONFLICT target for syncUpsert
|
|
70
|
+
uniqueIndex('uq_<%= entityNamePlural %>_provider_external_id').on(t.provider, t.externalId),
|
|
71
|
+
],
|
|
72
|
+
<%_ } _%>
|
|
67
73
|
);
|
|
68
74
|
<%_ if (clpHasRelationsBlock) { _%>
|
|
69
75
|
<%_ const needsMany = typeof clpExistingHasMany !== 'undefined' && clpExistingHasMany.length > 0; _%>
|
|
@@ -105,6 +105,38 @@ export function resolvePatternBaseClasses(entity) {
|
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Resolve the behaviors implied by an entity's declared pattern(s).
|
|
110
|
+
*
|
|
111
|
+
* A pattern (e.g. `Synced`) may declare `impliedBehaviors` — behaviors the
|
|
112
|
+
* entity gets for free without re-declaring them in its `behaviors:` array.
|
|
113
|
+
* Walks every declared pattern (both the `pattern: X` and `patterns: [...]`
|
|
114
|
+
* shapes), unions their `impliedBehaviors`, and returns a deduped list.
|
|
115
|
+
* Unknown patterns are skipped silently — composition validation surfaces
|
|
116
|
+
* those separately (src/patterns/validate-composition.ts).
|
|
117
|
+
*
|
|
118
|
+
* @param {object} entity - the entity block from the parsed YAML
|
|
119
|
+
* @returns {string[]} deduped implied behavior names
|
|
120
|
+
*/
|
|
121
|
+
export function resolveImpliedBehaviors(entity) {
|
|
122
|
+
const names = [];
|
|
123
|
+
if (typeof entity.pattern === 'string' && entity.pattern) {
|
|
124
|
+
names.push(entity.pattern);
|
|
125
|
+
}
|
|
126
|
+
if (Array.isArray(entity.patterns)) {
|
|
127
|
+
names.push(...entity.patterns);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const implied = new Set();
|
|
131
|
+
for (const name of names) {
|
|
132
|
+
const def = getPattern(name);
|
|
133
|
+
for (const b of def?.impliedBehaviors ?? []) {
|
|
134
|
+
implied.add(b);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return Array.from(implied);
|
|
138
|
+
}
|
|
139
|
+
|
|
108
140
|
// ============================================================================
|
|
109
141
|
// Helper utilities
|
|
110
142
|
// ============================================================================
|
|
@@ -441,10 +473,13 @@ function collectDrizzleImports(processedFields, belongsTo, hasTimestamps, hasSof
|
|
|
441
473
|
imports.add('timestamp');
|
|
442
474
|
}
|
|
443
475
|
|
|
444
|
-
// external_id_tracking behavior injects varchar + jsonb columns
|
|
476
|
+
// external_id_tracking behavior injects varchar + jsonb columns plus a
|
|
477
|
+
// unique index over (provider, external_id) — the ON CONFLICT target the
|
|
478
|
+
// sync sink's syncUpsert relies on.
|
|
445
479
|
if (hasExternalIdTracking) {
|
|
446
480
|
imports.add('varchar');
|
|
447
481
|
imports.add('jsonb');
|
|
482
|
+
imports.add('uniqueIndex');
|
|
448
483
|
}
|
|
449
484
|
|
|
450
485
|
if (belongsTo.length > 0 || hasMany.length > 0) {
|
|
@@ -787,8 +822,20 @@ export function buildCleanLitePsLocals(definition, baseLocals) {
|
|
|
787
822
|
// Process entity fields
|
|
788
823
|
const processedFields = processFields(fields);
|
|
789
824
|
|
|
790
|
-
// Behavior flags (re-read from behaviors array for clean-lite-ps use)
|
|
791
|
-
|
|
825
|
+
// Behavior flags (re-read from behaviors array for clean-lite-ps use).
|
|
826
|
+
//
|
|
827
|
+
// Fold in the resolved pattern's `impliedBehaviors` (ADR-031): an entity
|
|
828
|
+
// declaring e.g. `pattern: Synced` need not re-declare the
|
|
829
|
+
// `external_id_tracking` behavior — the pattern contributes it. Deduped
|
|
830
|
+
// with any explicit `behaviors:` entries, explicit-first so order is
|
|
831
|
+
// stable for pre-existing fixtures. Mirrors the dedup in
|
|
832
|
+
// src/patterns/validate-composition.ts.
|
|
833
|
+
const explicitBehaviorNames = behaviors.map((b) => (typeof b === 'string' ? b : b.name));
|
|
834
|
+
const impliedBehaviorNames = resolveImpliedBehaviors(entity);
|
|
835
|
+
const behaviorNames = [
|
|
836
|
+
...explicitBehaviorNames,
|
|
837
|
+
...impliedBehaviorNames.filter((b) => !explicitBehaviorNames.includes(b)),
|
|
838
|
+
];
|
|
792
839
|
const hasTimestamps = behaviorNames.includes('timestamps');
|
|
793
840
|
const hasSoftDelete = behaviorNames.includes('soft_delete');
|
|
794
841
|
const hasUserTracking = behaviorNames.includes('user_tracking');
|