001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *       http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.modeshape.common.text;
017
018import java.util.LinkedList;
019import java.util.List;
020import org.modeshape.common.annotation.Immutable;
021
022public class SampleSqlParser {
023
024    public List<Statement> parse( String ddl ) {
025        TokenStream tokens = new TokenStream(ddl, TokenStream.basicTokenizer(false), false);
026        List<Statement> statements = new LinkedList<Statement>();
027        tokens.start();
028
029        while (tokens.hasNext()) {
030            if (tokens.matches("SELECT")) {
031                statements.add(parseSelect(tokens));
032            } else {
033                statements.add(parseDelete(tokens));
034            }
035        }
036        return statements;
037    }
038
039    protected Select parseSelect( TokenStream tokens ) throws ParsingException {
040        tokens.consume("SELECT");
041        List<Column> columns = parseColumns(tokens);
042        tokens.consume("FROM");
043        String tableName = tokens.consume();
044        return new Select(tableName, columns);
045    }
046
047    protected List<Column> parseColumns( TokenStream tokens ) throws ParsingException {
048        List<Column> columns = new LinkedList<Column>();
049        if (tokens.matches('*')) {
050            tokens.consume(); // leave the columns empty to signal wildcard
051        } else {
052            // Read names until we see a ','
053            do {
054                String columnName = tokens.consume();
055                if (tokens.canConsume("AS")) {
056                    String columnAlias = tokens.consume();
057                    columns.add(new Column(columnName, columnAlias));
058                } else {
059                    columns.add(new Column(columnName, null));
060                }
061            } while (tokens.canConsume(','));
062        }
063        return columns;
064    }
065
066    protected Delete parseDelete( TokenStream tokens ) throws ParsingException {
067        tokens.consume("DELETE", "FROM");
068        String tableName = tokens.consume();
069        tokens.consume("WHERE");
070        String lhs = tokens.consume();
071        tokens.consume('=');
072        String rhs = tokens.consume();
073        return new Delete(tableName, new Criteria(lhs, rhs));
074    }
075
076    @Immutable
077    public abstract static class Statement {
078    }
079
080    @Immutable
081    public static class Select extends Statement {
082        private final String from;
083        private final List<Column> columns;
084
085        public Select( String from,
086                       List<Column> columns ) {
087            this.from = from;
088            this.columns = columns;
089        }
090
091        public String getFrom() {
092            return from;
093        }
094
095        public List<Column> getColumns() {
096            return columns;
097        }
098    }
099
100    @Immutable
101    public static class Delete extends Statement {
102        private final String from;
103        private final Criteria criteria;
104
105        public Delete( String from,
106                       Criteria criteria ) {
107            this.from = from;
108            this.criteria = criteria;
109        }
110
111        public String getFrom() {
112            return from;
113        }
114
115        public Criteria getCriteria() {
116            return criteria;
117        }
118    }
119
120    @Immutable
121    public static class Column {
122        private final String name;
123        private final String alias;
124
125        public Column( String name,
126                       String alias ) {
127            this.name = name;
128            this.alias = alias;
129        }
130
131        public String getName() {
132            return name;
133        }
134
135        public String getAlias() {
136            return alias;
137        }
138    }
139
140    @Immutable
141    public static class Criteria {
142        private final String lhs;
143        private final String rhs;
144
145        public Criteria( String lhs,
146                         String rhs ) {
147            this.lhs = lhs;
148            this.rhs = rhs;
149        }
150
151        public String getLhs() {
152            return lhs;
153        }
154
155        public String getRhs() {
156            return rhs;
157        }
158    }
159
160    @Immutable
161    public static class Query {
162        private final String from;
163        private final List<Column> columns;
164
165        public Query( String from,
166                      List<Column> columns ) {
167            this.from = from;
168            this.columns = columns;
169        }
170
171        public String getFrom() {
172            return from;
173        }
174
175        public List<Column> getColumns() {
176            return columns;
177        }
178    }
179
180}