Skip to content

v0.16.0 — Internal refactor, namespace re-shape, test/doc round-3/4/5

Choose a tag to compare

@Vusys Vusys released this 29 May 22:16
· 103 commits to master since this release
ddba21b

⚠️ Breaking change — namespace re-shape (#141)

The flat Vusys\NestedSet\Aggregates\* and Vusys\NestedSet\Events\* namespaces are split by responsibility, and two user-implementable interfaces are promoted to Contracts\ (Laravel convention). No class_alias shims — use statements and Event::listen(::class) calls must be updated. Pre-1.0 polish-phase window.

Aggregates — most-likely-imported renames (full mapping in the PR #141 body):

Before After
Aggregates\AggregateDefinition Aggregates\Definitions\AggregateDefinition
Aggregates\ListenerAggregateDefinition Aggregates\Definitions\ListenerAggregateDefinition
Aggregates\CompanionSpec Aggregates\Definitions\CompanionSpec
Aggregates\CompanionSourceOrigin / CompanionSourceTransform Aggregates\Definitions\…
Aggregates\FilterPredicate / FilterPredicateKind / FilterValueQuoter Aggregates\Filters\…
Aggregates\AggregateRegistry Aggregates\Registry\AggregateRegistry
Aggregates\AggregateSqlEmitter / DerivedAggregateFragments / VarianceSqlFragments / SqliteBitwiseAggregates Aggregates\Sql\…
Aggregates\TreeAggregateListener Contracts\TreeAggregateListener
Aggregates\AggregateDefinitionContract Contracts\AggregateDefinitionContract

Public API roots — Aggregate, ListenerAggregate, AggregateFunction, AggregateFixResult — stay at Vusys\NestedSet\Aggregates\.

Events — by lifecycle phase:

Sub-namespace Events
Events\Mutation\ NodeMoved, NodePromotedToRoot, NodesSwapped
Events\Subtree\ SubtreeMoving, SubtreeMoved, SubtreeForceDeleting, SubtreeForceDeleted
Events\SoftDelete\ SubtreeSoftDeleting, SubtreeSoftDeleted, SubtreeRestoring, SubtreeRestored, SoftDeleteMarkerCaptured
Events\BulkInsert\ BulkInsertTreeStarting, BulkInsertTreePlanned, BulkInsertNodeSaved, BulkInsertTreeSaved, BulkInsertTreeCompleted
Events\Aggregates\ NodeAggregatesRecomputed, AggregateDriftDetected, AggregateMaintenanceFailed, DeferredMaintenanceStarting, DeferredAggregateMaintenanceCompleted, FixAggregatesChunkCompleted, FixAggregatesCompleted, FixAggregatesJobDispatched
Events\Repair\ FixTreeCompleted, TreeIntegrityChecked
Events\Diagnostics\ ScopeViolationDetected

Events\EventDispatcher stays at the namespace root.

Upgrade: ripgrep use Vusys\\NestedSet\\Aggregates\\ and use Vusys\\NestedSet\\Events\\ across your app and rewrite to the new FQCNs. The new locations are searchable in the docs site under §6.1 and §6.2.

v0.16.0 — Internal refactor, namespace re-shape, test/doc round-3/4/5

Pre-1.0 polish release: the round-3/4/5 sweeps. One BC-affecting namespace reshape (callout above), three internal-only refactors that split large files into focused classes by responsibility, a doc-coherence pass covering the M3–M5 features and the NodeTrait surface, and a test-reshuffle that mirrors tests/ to src/ and fills genuinely-reachable coverage gaps.

Refactor

  • Split Aggregates and Events into sub-namespaces (§6.1, §6.2) (#141). BC — see callout above.
  • Round-5 §7 code-smell consolidations (#142): AggregateRegistry *CompanionsFor() dedupe → shared findFirstCompanion(); TreeAggregateBuilder chain-fold tower → ChainFoldAccumulator value object; HasNestedSetAggregates numeric helpers → Vusys\NestedSet\Aggregates\Numeric; HasTreeRelations::requireTreeBuilder() helper.
  • Split TreeAggregateBuilder (2 710 LoC) into four focused classes under Query\Aggregates\ (§6.5) (#143) — AggregateValueComparator, AggregateSqlFragments, AggregateDiffer, FreshAggregateProjector. Pure motion; the original class is deleted (internal-only).
  • Extract listener PHP fix path to Vusys\NestedSet\Aggregates\Listeners\ListenerMaintenance (§6.4) (#144) — HasNestedSetAggregates trait drops 341 LoC; mutation hooks, public maintenance API, anchor/scope plumbing stay in the trait and delegate.

Tests

  • Round-4 coverage gaps + broken-assertion fixes + marathon-test splits (#140). Replaces bare addToAssertionCount(1) placeholders with real before/after snapshots; pins the documented countErrors() cycle-detection gap so it fails loudly if ever fixed. New coverage for cross-scope parent_id corruption (ScopedCorruptionRecoveryTest), Median/Percentile × fixAggregates interaction, MeanArea structural moves, WeightedAvg edge cases (weight→0, negative weight, zero-total NULL), FixAggregatesJob serialisation + failure, bulkInsertTree × withDeferredAggregateMaintenance nesting, and parallel appendToNode on the same parent (AppendToNodeConcurrencyTest, multi-writer-CI only). Three marathon scripted-scenario suites broken into focused regression-class names sharing seed helpers.
  • Namespace tests/ to mirror src/ (#145). 100+ files reorganised across three independently-green commits: Unit/ re-nested into Aggregates/{Definitions,Filters,Registry,Sql}, Attributes/, Events/, Query/; Feature/ gains Mutation/, SoftDelete/, BulkInsert/, Events/, Scoping/, Fuzzers/; Feature/Aggregates/ further split into Maintenance/, Integrity/, Functions/, Listeners/, Repair/, Collections/. The EdgeCasesTest catch-all decomposed so each concern owns its edge cases. PSR-4 path→namespace rewrite verified as a no-op on the pre-refactor tree before any moves landed.
  • ChainFoldAccumulator + Aggregate coverage + data-provider adoption (#146). SQLite line coverage 86.55% → 90.01% (1 321 → 1 454 tests). New ChainFoldAccumulatorTest covers the PHP chain-fold fast path for every reachable kind (Sum/Count/Min/Max/Bit*/Avg/Variance/Stddev/WeightedAvg/BoolOr/BoolAnd/geometric+harmonic mean) plus companion source-transforms; Aggregate factory coverage 76% → 99.7%; DerivedAggregateFragments 62% → 100% via snapshot tests; NestedSetAggregate attribute validation paths driven by a DataProvider; new ScopedArea fixture (the only one combining partitioned trees with maintained aggregates) lifts the NestedSetScopeResolver + scope-predicate paths.

Documentation

  • Cover M3–M5 + rewrite setup / maintenance / deferred sections (#138). New docs/aggregates/means.md (geometric / harmonic, positivity & non-zero constraints, allowNonPositive(), the EXP(Σ LN(x) / n) precision caveat). New docs/aggregates/quantiles.md (median / percentile / percentiles([...]) / quartiles() — fresh-read-only constraint, linear-interpolation semantics, per-backend SQL shape table). Replaces the previous SUM/COUNT-only caption in setup.md with a complete 14-row type: reference (display column shape, null/default convention, auto-allocated companions, dropNestedSetAggregate('col', type: …) requirement). maintenance.md cost matrix replaced with families table covering delta-maintainable / companion-derived / extremum-recompute / chain-recompute / bitwise mixed / fresh-read-only. fix-aggregates.md expands withDeferredAggregateMaintenance with the explicit signature, scoped-model anchor requirement, re-entrancy counter, failure-safety, and observability events.

  • Round-3 coherence pass — pitfalls callout, soft-deletes rewrite, exception taxonomy (#139). 15 docs-only fixes folded into one PR. NodeTrait surface in model-setup.md updated to include bulkInsertTree, moveTo/moveBefore/moveAfter, isSiblingOf, prevSibling/nextSibling, and the HasTreeExport concern. New "Refresh after mutating a child" callout — the package only refreshes the target of a mutation, the parent reference you held goes stale (the #1 footgun). Exception taxonomy split into LogicException (programmer error) vs RuntimeException (data-state); CorruptTreeException and AggregateSourceConstraintViolationException added (were missing). soft-deletes.md rewritten from a 15-line stub to cover cascade lifecycles, microsecond timestamp matching (DATETIME(6) caveat), aggregate semantics on cascade, and scope interaction. Listener AVG companion migration example now shows the float-returning case as a decimal column (bigint default silently truncated). queries.md ordered-output examples now call defaultOrder(). bulk-insertion.md notes the silent scope-column override.