diff --git a/src/Translators/Rules.php b/src/Translators/Rules.php index 350385d7..27763dda 100644 --- a/src/Translators/Rules.php +++ b/src/Translators/Rules.php @@ -80,6 +80,18 @@ public static function fromColumn(string $context, Column $column) array_push($rules, 'unique:' . $context . ',' . $column->name()); } + if (Str::contains($column->dataType(), 'decimal')) { + array_push($rules, self::betweenRuleForNumericTypes($column, 'decimal')); + } + + if (Str::contains($column->dataType(), 'float')) { + array_push($rules, self::betweenRuleForNumericTypes($column, 'float')); + } + + if (Str::contains($column->dataType(), 'double')) { + array_push($rules, self::betweenRuleForNumericTypes($column, 'double')); + } + return $rules; } @@ -94,4 +106,32 @@ private static function overrideStringRuleForSpecialNames($name) return 'string'; } + + + private static function betweenRuleForNumericTypes(Column $column, $numericType) + { + $parameters = explode(",", Str::between($column->dataType(), "$numericType:", " ")); + + if (count($parameters) === 1) { + return; + } + + [$precision, $scale] = $parameters; + + $max = substr_replace(str_pad("", $precision, '9'), ".", $precision - $scale, 0); + $min = "-" . $max; + + if (intval($scale) === 0) { + $min = trim($min, "."); + $max = trim($max, "."); + } + + if (Str::contains($column->dataType(), 'unsigned')) { + $min = '0'; + } + + $betweenRule = 'between:' . $min . ',' . $max; + + return $betweenRule; + } } diff --git a/tests/Feature/Translators/RulesTest.php b/tests/Feature/Translators/RulesTest.php index bb4f96ff..b8b18d64 100644 --- a/tests/Feature/Translators/RulesTest.php +++ b/tests/Feature/Translators/RulesTest.php @@ -168,6 +168,156 @@ public function forColumn_return_json_rule_for_the_json_type() $this->assertContains('json', Rules::fromColumn('context', $column)); } + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_decimal_without_precion_and_scale() + { + $column = new Column('column', "decimal"); + + $this->assertNotContains("between", Rules::fromColumn('context', $column)); + } + + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_unsigned_decimal_without_precion_and_scale() + { + $unsignedBeforeDecimalColumn = new Column('column', "unsigned decimal"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedBeforeDecimalColumn)); + + $unsignedAfterDecimalColumn = new Column('column', "decimal unsigned"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedAfterDecimalColumn)); + } + + /** + * @test + * @dataProvider numericDataProvider + */ + public function forColumn_return_between_rule_for_decimal($precision, $scale, $interval) + { + $column = new Column('column', "decimal:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $column)); + } + + /** + * @test + * @dataProvider unsignedNumericDataProvider + */ + public function forColumn_return_between_rule_for_unsigned_decimal($precision, $scale, $interval) + { + $unsignedBeforeDecimalColumn = new Column('column', "unsigned decimal:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedBeforeDecimalColumn)); + + $unsignedAfterDecimalColumn = new Column('column', "decimal:$precision,$scale unsigned"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedAfterDecimalColumn)); + } + + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_float_without_precion_and_scale() + { + $column = new Column('column', "float"); + + $this->assertNotContains("between", Rules::fromColumn('context', $column)); + } + + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_unsigned_float_without_precion_and_scale() + { + $unsignedBeforeFloatColumn = new Column('column', "unsigned float"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedBeforeFloatColumn)); + + $unsignedAfterFloatColumn = new Column('column', "float unsigned"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedAfterFloatColumn)); + } + + /** + * @test + * @dataProvider numericDataProvider + */ + public function forColumn_return_between_rule_for_float($precision, $scale, $interval) + { + $column = new Column('column', "float:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $column)); + } + + /** + * @test + * @dataProvider unsignedNumericDataProvider + */ + public function forColumn_return_between_rule_for_unsigned_float($precision, $scale, $interval) + { + $unsignedBeforeFloatColumn = new Column('column', "unsigned float:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedBeforeFloatColumn)); + + $unsignedAfterFloatColumn = new Column('column', "float:$precision,$scale unsigned"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedAfterFloatColumn)); + } + + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_double_without_precion_and_scale() + { + $column = new Column('column', "double"); + + $this->assertNotContains("between", Rules::fromColumn('context', $column)); + } + + /** + * @test + */ + public function forColumn_does_not_return_between_rule_for_unsigned_double_without_precion_and_scale() + { + $unsignedBeforeDoubleColumn = new Column('column', "unsigned double"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedBeforeDoubleColumn)); + + $unsignedAfterDoubleColumn = new Column('column', "double unsigned"); + + $this->assertNotContains("between", Rules::fromColumn('context', $unsignedAfterDoubleColumn)); + } + + /** + * @test + * @dataProvider numericDataProvider + */ + public function forColumn_return_between_rule_for_double($precision, $scale, $interval) + { + $column = new Column('column', "double:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $column)); + } + + /** + * @test + * @dataProvider unsignedNumericDataProvider + */ + public function forColumn_return_between_rule_for_unsigned_double($precision, $scale, $interval) + { + $unsignedBeforeDoubleColumn = new Column('column', "unsigned double:$precision,$scale"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedBeforeDoubleColumn)); + + $unsignedAfterDoubleColumn = new Column('column', "double:$precision,$scale unsigned"); + + $this->assertContains("between:$interval", Rules::fromColumn('context', $unsignedAfterDoubleColumn)); + } + public function stringDataTypesProvider() { return [ @@ -225,4 +375,36 @@ public function relationshipColumnProvider() ['sheep_id', 'sheep'], ]; } + + public function numericDataProvider() + { + return [ + ['10', '0', '-9999999999,9999999999'], + ['10', '1', '-999999999.9,999999999.9'], + ['10', '2', '-99999999.99,99999999.99'], + ['10', '3', '-9999999.999,9999999.999'], + ['10', '4', '-999999.9999,999999.9999'], + ['10', '5', '-99999.99999,99999.99999'], + ['10', '6', '-9999.999999,9999.999999'], + ['10', '7', '-999.9999999,999.9999999'], + ['10', '8', '-99.99999999,99.99999999'], + ['10', '9', '-9.999999999,9.999999999'], + ]; + } + + public function unsignedNumericDataProvider() + { + return [ + ['10', '0', '0,9999999999'], + ['10', '1', '0,999999999.9'], + ['10', '2', '0,99999999.99'], + ['10', '3', '0,9999999.999'], + ['10', '4', '0,999999.9999'], + ['10', '5', '0,99999.99999'], + ['10', '6', '0,9999.999999'], + ['10', '7', '0,999.9999999'], + ['10', '8', '0,99.99999999'], + ['10', '9', '0,9.999999999'], + ]; + } }