Repository navigation
Render Integer display width directly after the type - #185
Merged
simon-mundy merged 5 commits intoSep 28, 2026
Merged
Conversation
The "length" option was concatenated onto the specification string after Column::getExpressionData() had already appended NOT NULL and DEFAULT, so the display width landed after the column attributes and MySQL rejected the statement with error 1064. It was also the only column attribute to reach SQL by string concatenation rather than as an Argument. Insert "(%s)" directly after the type and splice the width in as a Literal, matching AbstractLengthColumn. The option accepts an int or a string of digits and anything else throws InvalidArgumentException, so no raw option value reaches the SQL. setOption() now accepts int, as the constructor options array and the documentation already did. Fixes php-db#178 Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
CI installs the newest Mago, and 1.47.5 changed how the analyzer handles nested array shapes: prepareDataHierarchy() re-binds a reference into the MetadataData shape on every loop iteration, which no longer completes in useful time. Re-type the reference as a plain array so the shape is not re-derived per iteration, and adjust the expected findings accordingly. Regenerate the analyzer baseline for the reworded findings in Select, PredicateSet, Profiler and AbstractSql (the issues are unchanged, the messages are not), and reduce the continuation indent of two multi-line conditions in AbstractTableGateway to match the 1.47.4+ formatter. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
The tests declare their covered units with CoversMethod, so the private helper added to Integer was executed but credited to nothing, and codecov reported the patch as 40% covered. Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
tyrsson
previously approved these changes
Sep 28, 2026
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 28, 2026
All 55 throw sites in src/Sql now call a named constructor. Message text is byte-identical, verified template by template against the original literals. - Add Sql\Predicate\Exception with its own ExceptionInterface, InvalidArgumentException and RuntimeException, holding the 10 templates the predicate classes use, so the messages sit with the classes that raise them rather than concentrating on one component catalogue - Add 24 templates and factories to Sql\Exception\InvalidArgumentException and 6 to Sql\Exception\RuntimeException, the last four covering the Ddl column and check constraint messages added by php-db#183, php-db#184 and php-db#185 - Collapse nine duplicated messages onto one template each, five of which the audit on php-db#189 had missed: the four "intended to work with only the table" copies in Sql, the two parameter-count copies in AbstractSql, the two column key copies in Insert, the two read-only copies in Select, and the subject messages shared by Platform and AbstractPlatform - Fix a copy-paste bug in Platform::getSqlString(), which reported prepareStatement() as the method with no effect - Retype Between's \LogicException and AbstractSql's \ValueError to the package types, so both reach the marker interface - Declare the @throws Predicate::unnest() and Predicate::__get() never had - Cover every factory with a template test, and derive the 46 Sql message assertions from the templates rather than restating them - Re-attribute the two baselined sprintf argument-type entries to the factories that now receive those arguments, and baseline the three halstead readings the refactor shifts - Exclude src/Sql/Exception/ from too-many-methods in mago.toml. The threshold is 10 and a catalogue holds one template per condition a component can report, so the count tracks failure modes rather than anything a split would improve Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
This was referenced Sep 28, 2026
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 28, 2026
All 55 throw sites in src/Sql now call a named constructor. Message text is byte-identical, verified template by template against the original literals. - Add Sql\Predicate\Exception with its own ExceptionInterface, InvalidArgumentException and RuntimeException, holding the 10 templates the predicate classes use, so the messages sit with the classes that raise them rather than concentrating on one component catalogue, and register both concrete classes in ExceptionHierarchyTest's EXCEPTION_CLASSES map - Add 24 templates and factories to Sql\Exception\InvalidArgumentException and 6 to Sql\Exception\RuntimeException, the last four covering the Ddl column and check constraint messages added by php-db#183, php-db#184 and php-db#185 - Collapse nine duplicated messages onto one template each, five of which the audit on php-db#189 had missed: the four "intended to work with only the table" copies in Sql, the two parameter-count copies in AbstractSql, the two column key copies in Insert, the two read-only copies in Select, and the subject messages shared by Platform and AbstractPlatform - Fix a copy-paste bug in Platform::getSqlString(), which reported prepareStatement() as the method with no effect - Retype Between's \LogicException and AbstractSql's \ValueError to the package types, so both reach the marker interface - Declare the @throws Predicate::unnest() and Predicate::__get() never had - Cover every factory with a template test, and derive the 46 Sql message assertions from the templates rather than restating them - Re-attribute the two baselined sprintf argument-type entries to the factories that now receive those arguments, and baseline the three halstead readings the refactor shifts - Exclude src/Sql/Exception/ from too-many-methods in mago.toml. The threshold is 10 and a catalogue holds one template per condition a component can report, so the count tracks failure modes rather than anything a split would improve Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 29, 2026
All 55 throw sites in src/Sql now call a named constructor. Message text is byte-identical, verified template by template against the original literals. - Add Sql\Predicate\Exception with an InvalidArgumentException and a RuntimeException holding the 10 templates the predicate classes use, so the messages sit with the classes that raise them rather than concentrating on one component catalogue, and register both in ExceptionHierarchyTest's EXCEPTION_CLASSES map. The namespace deliberately has no ExceptionInterface of its own: both classes extend their Sql\Exception counterparts, so they are already caught by Sql\Exception\ExceptionInterface, and a narrower marker would only collapse the same InvalidArgument and Runtime split a second time - Add 24 templates and factories to Sql\Exception\InvalidArgumentException and 6 to Sql\Exception\RuntimeException, the last four covering the Ddl column and check constraint messages added by php-db#183, php-db#184 and php-db#185 - Collapse nine duplicated messages onto one template each, five of which the audit on php-db#189 had missed: the four "intended to work with only the table" copies in Sql, the two parameter-count copies in AbstractSql, the two column key copies in Insert, the two read-only copies in Select, and the subject messages shared by Platform and AbstractPlatform - Fix a copy-paste bug in Platform::getSqlString(), which reported prepareStatement() as the method with no effect - Retype Between's \LogicException and AbstractSql's \ValueError to the package types, so both reach the marker interface - Declare the @throws Predicate::unnest() and Predicate::__get() never had - Cover every factory with a template test, and derive the 46 Sql message assertions from the templates rather than restating them - Re-attribute the two baselined sprintf argument-type entries to the factories that now receive those arguments, and baseline the three halstead readings the refactor shifts - Exclude src/Sql/Exception/ from too-many-methods in mago.toml. The threshold is 10 and a catalogue holds one template per condition a component can report, so the count tracks failure modes rather than anything a split would improve Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
simon-mundy
added a commit
to simon-mundy/phpdb
that referenced
this pull request
Sep 29, 2026
All 55 throw sites in src/Sql now call a named constructor. Message text is byte-identical, verified template by template against the original literals. - Add Sql\Predicate\Exception with an InvalidArgumentException and a RuntimeException holding the 10 templates the predicate classes use, so the messages sit with the classes that raise them rather than concentrating on one component catalogue, and register both in ExceptionHierarchyTest's EXCEPTION_CLASSES map. Neither namespace declares an ExceptionInterface: the package has one marker, PhpDb\Exception\ExceptionInterface, and every class here implements it by inheritance - Add 24 templates and factories to Sql\Exception\InvalidArgumentException and 6 to Sql\Exception\RuntimeException, the last four covering the Ddl column and check constraint messages added by php-db#183, php-db#184 and php-db#185 - Collapse nine duplicated messages onto one template each, five of which the audit on php-db#189 had missed: the four "intended to work with only the table" copies in Sql, the two parameter-count copies in AbstractSql, the two column key copies in Insert, the two read-only copies in Select, and the subject messages shared by Platform and AbstractPlatform - Fix a copy-paste bug in Platform::getSqlString(), which reported prepareStatement() as the method with no effect - Retype Between's \LogicException and AbstractSql's \ValueError to the package types, so both reach the marker interface - Declare the @throws Predicate::unnest() and Predicate::__get() never had - Cover every factory with a template test, and derive the 46 Sql message assertions from the templates rather than restating them - Re-attribute the two baselined sprintf argument-type entries to the factories that now receive those arguments, and baseline the three halstead readings the refactor shifts - Exclude src/Sql/Exception/ from too-many-methods in mago.toml. The threshold is 10 and a catalogue holds one template per condition a component can report, so the count tracks failure modes rather than anything a split would improve Signed-off-by: Simon Mundy <simon.mundy@peptolab.com>
simon-mundy
added a commit
that referenced
this pull request
Sep 29, 2026
Escaped mutants drop from 79 to 11 and Covered MSI rises from 97% to 99%. The largest cluster was one root cause: AbstractSourceTest seeds the data property by reflection before calling a getter, so the getter's own loader call is unobservable and Infection deletes it for free. LazyRecordingSource seeds only inside loadXData(), delegates to its parent (which keeps the parent's protected visibility observable from a subclass) and records each call, so dropping a loader call from a getter now empties the result. That plus two genuine gaps in the same file - constraint keys matching on only half the table/constraint pair, and the hierarchy builder auto-vivifying nulls - accounts for 33 of them. Elsewhere: Values and Identifiers had no test file at all; the predicates round-tripped setSpecification() without checking getExpressionData() honoured it; the length columns never covered a value long enough for the array_splice insert to displace anything; and Integer's display width, new in #185, never saw a zero width or a values array long enough to notice a removal. Twelve mutants are verified equivalents rather than gaps and are ignored in infection.json5.dist with reasons: the six loader guards short-circuit an idempotent prepareDataHierarchy(), getColumns() delegates to getColumnNames() which reloads the same data, implode() discards the keys array_fill() sets, a RowGatewayInterface is caught by the next guard anyway, and stopPropagation() has an empty body. The 11 remaining escapes are all exception-message concatenation. Killing them means pinning exact wording, which buys brittleness rather than safety, so they are left visible rather than suppressed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integer::getExpressionData()now inserts(%s)directly after the type and splices the display width in at index 2 as aLiteral, sonew Integer('i', false, null, ['length' => 11])renders"i" INTEGER(11) NOT NULLand a nullable column with a default rendersBIGINT(20) NULL DEFAULT '7'.BigIntegerandSmallIntegerinherit it. Nothing underIntegerconcatenates an option value into the spec any more.The
lengthoption accepts anintor a string of digits; anything else throwsSql\Exception\InvalidArgumentException, since the value goes out as a rawLiteral.Column::setOption()is widened tobool|int|stringsosetOption('length', 11)works understrict_types, as the constructor$optionsarray andcolumns.mdalready allowed. Overlaps #169.columns.mdnotes that MySQL deprecated integer display width in 8.0.17 and that the MySQL decorator will drop the attribute (phpdb-mysql#81); other platforms keep rendering it.Same render-time approach as #183, implemented separately so the two PRs don't depend on each other. Worth hoisting into a shared hook on
Columnonce both are in.IntegerTestasserts the full rendered string rather than containment,setOption('length', 11)is covered inColumnTestand through rendering, invalid option values are covered by a data provider, andBigIntegerTest/SmallIntegerTesteach get a rendering test.Fixes #178