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