LEFT JOIN + rework join tests
[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;
a464be15 13 use SQL::Abstract::Types qw/NameSeparator QuoteChars AST HashAST ArrayAST/;
747f7c21 14 use Devel::PartialDump qw/dump/;
4769c837 15
c314b35d 16 clean;
a0185af2 17
a0185af2 18 our $VERSION = '2.000000';
19
20 our $AST_VERSION = '1';
21
3e63a4d5 22 # Operator precedence for bracketing
23 our %PRIO = (
24 and => 10,
25 or => 50
26 );
27
0bf8a8c4 28 our %BINOP_MAP = (
3e63a4d5 29 '>' => '>',
30 '<' => '<',
31 '==' => '=',
32 '!=' => '!=',
0bf8a8c4 33 # LIKE is always "field LIKE <value>"
1b85673a 34 '-like' => 'LIKE',
0bf8a8c4 35 '-not_like' => 'NOT LIKE',
3e63a4d5 36 );
37
ef0d6124 38 has expr_dispatch_table => (
0bf8a8c4 39 is => 'ro',
eb22ecd3 40 lazy => 1,
ef0d6124 41 builder => '_build_expr_dispatch_table',
0c371882 42 isa => HashRef[CodeRef],
43 metaclass => 'Collection::ImmutableHash',
44 provides => {
ef0d6124 45 get => 'lookup_expr_dispatch'
0c371882 46 }
0bf8a8c4 47 );
48
49 has binop_map => (
50 is => 'ro',
eb22ecd3 51 lazy => 1,
52 builder => '_build_binops',
0bf8a8c4 53 isa => HashRef,
54 metaclass => 'Collection::ImmutableHash',
55 provides => {
56 exists => 'is_valid_binop',
57 get => 'binop_mapping',
58 keys => 'binary_operators'
59 }
60 );
61
eb22ecd3 62 # List of default binary operators (for in where clauses)
63 sub _build_binops { return {%BINOP_MAP} };
0bf8a8c4 64
ef0d6124 65 method _build_expr_dispatch_table {
0c371882 66 my $binop = $self->can('_binop') or croak "InternalError: $self can't do _binop!";
0bf8a8c4 67 return {
68 map { $_ => $binop } $self->binary_operators
69 }
70 }
71
c314b35d 72 has ast_version => (
73 is => 'ro',
74 isa => Int,
75 required => 1
76 );
77
a0185af2 78 has name_separator => (
79 is => 'rw',
80 isa => NameSeparator,
4ee32f41 81 default => '.',
a0185af2 82 coerece => 1,
83 required => 1,
84 );
85
86 has list_separator => (
87 is => 'rw',
88 isa => Str,
89 default => ', ',
90 required => 1,
91 );
92
4ee32f41 93 has quote_chars => (
94 is => 'rw',
95 isa => QuoteChars,
96 coerece => 1,
97 predicate => 'is_quoting',
98 clearer => 'disable_quoting',
99 );
100
4769c837 101 has binds => (
102 isa => ArrayRef,
5bf8c024 103 is => 'ro',
0bf8a8c4 104 clearer => '_clear_binds',
105 lazy => 1,
4769c837 106 default => sub { [ ] },
107 metaclass => 'Collection::Array',
108 provides => {
109 push => 'add_bind',
4769c837 110 }
111 );
112
14774be0 113 # TODO: once MXMS supports %args, use that here
114 method create(ClassName $class: Int $ver) {
115 croak "AST version $ver is greater than supported version of $AST_VERSION"
116 if $ver > $AST_VERSION;
117
118 my $name = "${class}::AST::v$ver";
119 Class::MOP::load_class($name);
120
121 return $name->new(ast_version => $ver);
c314b35d 122 }
123
124 # Main entry point
a464be15 125 method generate(ClassName $class: HashAST $ast) {
126 my $ver = $ast->{-ast_version};
c314b35d 127 croak "SQL::Abstract AST version not specified"
a464be15 128 unless defined $ver;
c314b35d 129
14774be0 130 # TODO: once MXMS supports %args, use that here
131 my $self = $class->create($ver);
c314b35d 132
133 return ($self->dispatch($ast), $self->binds);
134 }
135
0bf8a8c4 136 method reset() {
137 $self->_clear_binds();
138 }
139
cbcfedc1 140 method dispatch (AST $ast) {
141 # I want multi methods!
142 my $tag;
143 if (is_ArrayAST($ast)) {
747f7c21 144 confess "FIX: " . dump($ast);
cbcfedc1 145 } else {
146 $tag = "_" . $ast->{-type};
147 }
0bf8a8c4 148
cbcfedc1 149 my $meth = $self->can($tag) || croak "Unknown tag '$tag'";
0bf8a8c4 150 return $meth->($self, $ast);
151 }
4769c837 152
a0185af2 153};