package Fey::Literal::Function; use strict; use warnings; use Scalar::Util qw( blessed ); use Moose::Policy 'MooseX::Policy::SemiAffordanceAccessor'; use MooseX::StrictConstructor; use Moose::Util::TypeConstraints; extends 'Fey::Literal'; with 'Fey::Role::Comparable', 'Fey::Role::Selectable', 'Fey::Role::Orderable', 'Fey::Role::Groupable'; has 'function' => ( is => 'ro', isa => 'Str', required => 1, ); subtype 'Fey.Type.FunctionArg' => as 'Object' => where { $_->does('Fey::Role::Selectable') }; coerce 'Fey.Type.FunctionArg' => from 'Undef' => via { Fey::Literal::Null->new() } => from 'Value' => via { Fey::Literal->new_from_scalar($_) }; { my $constraint = find_type_constraint('Fey.Type.FunctionArg'); subtype 'Fey.Type.ArrayRefOfFunctionArgs' => as 'ArrayRef' => where { for my $arg ( @{$_} ) { $constraint->check($arg) || return; } 1; }; coerce 'Fey.Type.ArrayRefOfFunctionArgs' => from 'ArrayRef' => via { [ map { $constraint->coerce($_) } @{ $_ } ] }; } has 'args' => ( is => 'ro', isa => 'Fey.Type.ArrayRefOfFunctionArgs', default => sub { [] }, coerce => 1, ); has 'alias_name' => ( is => 'rw', isa => 'Str', writer => 'set_alias_name', ); sub BUILDARGS { my $class = shift; return { function => shift, args => [ @_ ], }; } sub sql { my $sql = $_[0]->function(); $sql .= '('; $sql .= ( join ', ', map { $_->sql( $_[1] ) } @{ $_[0]->args() } ); $sql .= ')'; } sub sql_with_alias { $_[0]->_make_alias() unless $_[0]->alias_name(); my $sql = $_[0]->sql( $_[1] ); $sql .= ' AS '; $sql .= $_[1]->quote_identifier( $_[0]->alias_name() ); return $sql; } { my $Number = 0; sub _make_alias { my $self = shift; $self->set_alias_name( 'FUNCTION' . $Number++ ); } } sub sql_or_alias { return $_[1]->quote_identifier( $_[0]->alias_name() ) if $_[0]->alias_name(); return $_[0]->sql( $_[1] ); } sub is_groupable { $_[0]->alias_name() ? 1 : 0 } no Moose; no Moose::Util::TypeConstraints; __PACKAGE__->meta()->make_immutable(); 1; __END__ =head1 NAME Fey::Literal::Function - Represents a literal function in a SQL statement =head1 SYNOPSIS my $function = Fey::Literal::Function->new( 'LENGTH', $column ); =head1 DESCRIPTION This class represents a literal function in a SQL statement, such as C or C. =head1 INHERITANCE This module is a subclass of C. =head1 METHODS This class provides the following methods: =head2 Fey::Literal::Function->new( $function, @args ) This method creates a new C object. It requires at least one argument, which is the name of the SQL function that this literal represents. It can accept any number of additional optional arguments. These arguments must be either scalars, literals, or columns which belong to a table. Any scalars passed in as arguments will be passed in turn to C<< Fey::Literal->new_from_scalar() >>. =head2 $function->set_alias_name($alias) Use this to explicitly set a function's alias name for use in SQL. If you don't set this it will be autogenerated as needed. =head2 $function->function() The function's name, as passed to the constructor. =head2 $function->args() Returns an array reference of the function's arguments, as passed to the constructor. =head2 $function->sql() =head2 $function->sql_with_alias() =head2 $function->sql_or_alias() Returns the appropriate SQL snippet. Calling C<< $function->sql_with_alias() >> causes a unique alias for the function to be created. =head1 ROLES This class does the C, C, C, and C roles. This class overrides the C and C methods so that they only return true if the C<< $function->sql_with_alias() >> has been called previously. This function is called when a function is used in the C in order to be used in a C or C clause. =head1 AUTHOR Dave Rolsky, =head1 BUGS See L for details on how to report bugs. =head1 COPYRIGHT & LICENSE Copyright 2006-2008 Dave Rolsky, All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut