Form-Sensible-Reflector-MySQL

 view release on metacpan or  search on metacpan

lib/Form/Sensible/Reflector/MySQL.pm  view on Meta::CPAN

	}
	else {
		@rv =  keys %{ $self->{table_metadata}->{ $form->{name} } };
	}
	
	return @rv;
}


# Should numbers be allowed to contain commas?
sub get_field_definition { 
	my ($self, $form, $dbh, $fieldname) = @_;
	my $mysql_type = $self->{table_metadata}->{ $form->{name} }->{$fieldname}->{Type};
	DEBUG $fieldname .': '.$mysql_type;
	my $f = { 
		name => $fieldname,
		field_class => 'Number'
	};

	# db defaults - not no_db_defaults
	if ( not( $self->no_db_defaults )
		and $self->{table_metadata}->{ $form->{name} }->{$fieldname}->{Default}
		and $mysql_type ne 'timestamp' # avoid a value of CURRENT_TIMESTAMP
	){
		$self->{defaults}->{$fieldname} =
			$self->{table_metadata}->{ $form->{name} }->{$fieldname}->{Default};
		DEBUG "Set $fieldname to default ", $self->{defaults}->{$fieldname};
	}

	# Numeric types - http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html
	# NB display width with zero-padding for INT(M) -
	# Cf http://alexander.kirk.at/2007/08/24/what-does-size-in-intsize-of-mysql-mean/
	if ($mysql_type =~ /^tinyint/){
		$f->{integer_only} = 1;
		$f->{lower_bound} = $mysql_type =~ /unsigned/? 0 : -128;
		$f->{upper_bound} = $mysql_type =~ /unsigned/? 255 : 127;
	}
	elsif ($mysql_type =~ /^smallint/){
		$f->{integer_only} = 1;
		$f->{lower_bound} = $mysql_type =~ /unsigned/? 0 : -32768;
		$f->{upper_bound} = $mysql_type =~ /unsigned/? 65535 : 32767;
	}
	elsif ($mysql_type =~ /^mediumint/){
		$f->{integer_only} = 1;
		$f->{lower_bound} = $mysql_type =~ /unsigned/? 0 : -8388608;
		$f->{upper_bound} = $mysql_type =~ /unsigned/? 16777215 : 8388607;
	}
	elsif ($mysql_type =~ /^int/){
		$f->{integer_only} = 1;
		$f->{lower_bound} = $mysql_type =~ /unsigned/? 0 : -2147483648;
		$f->{upper_bound} = $mysql_type =~ /unsigned/? 4294967295 : 2147483647;
	}
	
	# Treat massive integers as strings or nothing works
	elsif ($mysql_type =~ /^bigint/){
		$f->{field_type} = 'Text';
		$f->{validation} = { code => $mysql_type =~ /unsigned/ ?
			sub { 
				use Math::BigInt;
				my $n = Math::BigInt->new( $_[0] );
				# return '_FIELDNAME_ is an invalid unsigned big integer' if $n eq 'NaN';
				return $self->i18n->{ubigint}->{nan} if $n eq 'NaN';
				return $self->i18n->{ubigint}->{not_int} if not $n->is_int;
				return $self->i18n->{ubigint}->{too_high} if $n > 8446744073709551615;
				return $self->i18n->{ubigint}->{too_low} if $n < 0;
				return 0;
			}
		:	sub { 
				use Math::BigInt ':constant';
				my $n = Math::BigInt->new( $_[0] );
				return $self->i18n->{sbigint}->{nan} if $n eq 'NaN';
				return $self->i18n->{sbigint}->{not_int} if not $n->is_int;
				return $self->i18n->{sbigint}->{too_high} if $n > 9223372036854775807;
				return $self->i18n->{sbigint}->{too_low} if $n < -9223372036854775808;
				return 0;
			}
		};
	}

	elsif ($mysql_type =~ /^(double|real)/){
		$f->{field_type} = 'Text';
		$f->{validation} = { code => sub {
				use Math::BigFloat ':constant';
				my $n = Math::BigFloat->new( $_[0] );
				return $self->i18n->{double}->{nan} if $n eq 'NaN';
				return $self->i18n->{double}->{oob}
					if ($n <= -1.7976931348623157E+308 and $n >= -2.2250738585072014E-308)
						or $n== 0
						or ($n <= 2.2250738585072014E-308 and $n >= 1.7976931348623157E+3080);
				return 0;
			}
		};
	}
	
	elsif ($mysql_type =~ /^(decimal|numeric) (?: \((\d+) (?:,(\d+))? \) )?$/x ){
		my ($m, $d) = ($2, $3);
		# $m apprently includes the decimal point:
		$m = 0 if $m < 0;
		$m ||= 65; # But not in 5.0.3-5.0.5, when is 64
		$d ||= 0;
		$f->{field_type} = 'Text';
		$f->{validation} = { code => sub {
				# Naively assume it's a nice decimal/number
				my ($mym, $myd) = $_[0] =~ /^(\d+) (?: \. (\d+) )?$/x;
				$mym ||= 0; 
				$myd ||= 0;
				return $self->i18n->{decimal}->{nan}
					if not $mym and not $myd and $_[0] !~ /^0*(\.0+)?$/x;
				return $self->i18n->{decimal}->{too_long}.$m
					if (length($mym) + length($myd)) > $m;
				return $self->i18n->{decimal}->{post_point}.$d
					if length($myd) > $d;
				return 0;
			}
		};
	}
	
	# Floating-Point (Approximate-Value) Types
	# Defaut range desc at http://help.scibit.com/mascon/masconMySQL_Field_Types.html
	# and Fixed-Point (Exact-Value) Types 		
	elsif ($mysql_type =~ /^(float|double precision)/){
		my ($d, $e);

		if ($mysql_type =~ /\((\d+),(\d+)\)/){
			($d, $e) = ($1, $2);
		}
		elsif ( $mysql_type =~ /^(numeric|decimal)(\((\d+)\))?/	){
			($d, $e) = ($2, undef);
		}
		
		if (defined $d){
			my $valid_re = $e?
			qr/^-?\d{1,$d}(\.\d{0,$e})?$/
			: qr/^-?\d{1,$d}$/;
			$f->{validation} = {
				code => sub { 
					return $self->i18n->{float}->{nan} unless $_[0] =~ $NUMBER_RE;
					return $self->i18n->{float}->{invalid}.$d if $_[0] !~ $valid_re;
					return 0;
				}
			};
			my $max = '9' x $d;
			$max .= '.' . ('9' x $e) if $e;
			$f->{upper_bound} = $max;
			if ($mysql_type =~ /unsigned/){



( run in 1.268 second using v1.01-cache-2.11-cpan-39bf76dae61 )