Create ArrayAST, HashAST and AST types in a type library so that some constructs...
[dbsrgits/SQL-Abstract-2.0-ish.git] / lib / SQL / Abstract.pm
CommitLineData
a0185af2 1use MooseX::Declare;
a0185af2 2
3
4class SQL::Abstract {
5
6 use Carp qw/croak/;
7 use Data::Dump qw/pp/;
8
9 use Moose::Util::TypeConstraints;
3e63a4d5 10 use MooseX::Types -declare => [qw/NameSeparator/];
0c371882 11 use MooseX::Types::Moose qw/ArrayRef Str Int HashRef CodeRef/;
4769c837 12 use MooseX::AttributeHelpers;
cbcfedc1 13 use SQL::Abstract::Types qw/NameSeparator AST ArrayAST/;
4769c837 14
c314b35d 15 clean;
a0185af2 16
a0185af2 17 our $VERSION = '2.000000';
18
19 our $AST_VERSION = '1';
20
3e63a4d5 21 # Operator precedence for bracketing
22 our %PRIO = (
23 and => 10,
24 or => 50
25 );
26
0bf8a8c4 27 our %BINOP_MAP = (
3e63a4d5 28 '>' => '>',
29 '<' => '<',
30 '==' => '=',
31 '!=' => '!=',
0bf8a8c4 32 # LIKE is always "field LIKE <value>"
33 '-like' => 'IN',
34 '-not_like' => 'NOT LIKE',
3e63a4d5 35 );
36
0bf8a8c4 37 has where_dispatch_table => (
38 is => 'ro',
39 lazy_build => 1,
0c371882 40 isa => HashRef[CodeRef],
41 metaclass => 'Collection::ImmutableHash',
42 provides => {
43 get => 'lookup_where_dispatch'
44 }
0bf8a8c4 45 );
46
47 has binop_map => (
48 is => 'ro',
49 lazy_build => 1,
50 isa => HashRef,
51 metaclass => 'Collection::ImmutableHash',
52 provides => {
53 exists => 'is_valid_binop',
54 get => 'binop_mapping',
55 keys => 'binary_operators'
56 }
57 );
58
59 sub _build_binop_map { return {%BINOP_MAP} };
60
61 method _build_where_dispatch_table {
0c371882 62 my $binop = $self->can('_binop') or croak "InternalError: $self can't do _binop!";
0bf8a8c4 63 return {
64 map { $_ => $binop } $self->binary_operators
65 }
66 }
67
c314b35d 68 has ast_version => (
69 is => 'ro',
70 isa => Int,
71 required => 1
72 );
73
a0185af2 74 has name_separator => (
75 is => 'rw',
76 isa => NameSeparator,
77 default => sub { ['.'] },
78 coerece => 1,
79 required => 1,
80 );
81
82 has list_separator => (
83 is => 'rw',
84 isa => Str,
85 default => ', ',
86 required => 1,
87 );
88
4769c837 89 has binds => (
90 isa => ArrayRef,
5bf8c024 91 is => 'ro',
0bf8a8c4 92 clearer => '_clear_binds',
93 lazy => 1,
4769c837 94 default => sub { [ ] },
95 metaclass => 'Collection::Array',
96 provides => {
97 push => 'add_bind',
4769c837 98 }
99 );
100
14774be0 101 # TODO: once MXMS supports %args, use that here
102 method create(ClassName $class: Int $ver) {
103 croak "AST version $ver is greater than supported version of $AST_VERSION"
104 if $ver > $AST_VERSION;
105
106 my $name = "${class}::AST::v$ver";
107 Class::MOP::load_class($name);
108
109 return $name->new(ast_version => $ver);
c314b35d 110 }
111
112 # Main entry point
cbcfedc1 113 method generate(ClassName $class: AST $ast) {
c314b35d 114 croak "SQL::Abstract AST version not specified"
115 unless ($ast->[0] eq '-ast_version');
116
117 my (undef, $ver) = splice(@$ast, 0, 2);
118
14774be0 119 # TODO: once MXMS supports %args, use that here
120 my $self = $class->create($ver);
c314b35d 121
122 return ($self->dispatch($ast), $self->binds);
123 }
124
0bf8a8c4 125 method reset() {
126 $self->_clear_binds();
127 }
128
cbcfedc1 129 method dispatch (AST $ast) {
130 # I want multi methods!
131 my $tag;
132 if (is_ArrayAST($ast)) {
133 ($tag = $ast->[0]) =~ s/^-/_/;
134 } else {
135 $tag = "_" . $ast->{-type};
136 }
0bf8a8c4 137
cbcfedc1 138 my $meth = $self->can($tag) || croak "Unknown tag '$tag'";
0bf8a8c4 139 return $meth->($self, $ast);
140 }
4769c837 141
a0185af2 142};