net.metanotion.sqlc.SqlcPhp.java Source code

Java tutorial

Introduction

Here is the source code for net.metanotion.sqlc.SqlcPhp.java

Source

/***************************************************************************
   Copyright 2017 Emily Estes
    
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at
    
   http://www.apache.org/licenses/LICENSE-2.0
    
   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***************************************************************************/
package net.metanotion.sqlc;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.sql.PreparedStatement;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.metanotion.scripting.Struct;
import net.metanotion.scripting.StructManager;
import net.metanotion.sqlc.setters.*;
import net.metanotion.util.ArgsToStruct;
import net.metanotion.util.Description;
import net.metanotion.util.reflect.GetInitializer;

public final class SqlcPhp {
    private static final Logger logger = LoggerFactory.getLogger(SqlcPhp.class);

    /** This class represents the command line options used by the PHP version of the SQL compiler. */
    public static final class Args {
        @Description("If this option is set, no @implicit objects will be created.")
        public boolean noStructs;

        @Description("If this option is set, PHP 7 type annotation/hints will not be emitted.")
        public boolean omitTypes;

        @Description("The folder containing the source code or source file to compile.")
        public String source;

        @Description("The folder to place generated PHP in.")
        public String out;
    }

    public static void main(final String[] args) throws Exception {
        final Args arg = (new ArgsToStruct<>(Args.class)).getInstance(args);
        final File f = new File(arg.source);

        final Iterable<String> srcPathes = java.util.Collections.emptyList(); // TO DO - until it can be cleaned up.

        final SQLC.ClassInfo ir = new SQLC.ClassInfo();
        if (f.isDirectory()) {
            SQLC.treewalk(ir, f, srcPathes);
        } else {
            SQLC.processFile(ir, arg.source, srcPathes);
        }
        for (final SQLClass q : ir.classes) {
            SqlcPhp.compile(arg.out, q, ir.sm, ir.implicits, ir.exceptions);
        }
        if (ir.implicits.size() > 0) {
            SqlcPhp.generateStructs(arg.out, ir.sm, ir.implicits, ir.implicitDocs);
            //SQLC.generateExceptions(outputFolder, ir.exceptions, ir.inheritanceMap, ir.implicits, ir.implicitDocs, ir.implicitVisibility);
        }
    }

    private static File getFilePath(final String outPath, final String[] packageName) {
        String outFolder = outPath;
        for (final String pe : packageName) {
            outFolder += File.separator + pe;
        }
        logger.debug("::" + outFolder + " - " + packageName.length);
        return new File(outFolder);
    }

    public static String mkPath(final String outPath, final String[] packageName, final String name) {
        final File f = getFilePath(outPath, packageName);
        f.mkdirs();
        return (f.toString() + File.separator + name + ".php");
    }

    private static void generateStructs(final String outputFolder, final StructManager sm,
            final Set<String> implicits, final Map<String, String> implicitDocs) throws IOException {
        for (final Map.Entry<String, GetInitializer> e : sm) {
            if (!implicits.contains(e.getKey())) {
                continue;
            }
            System.out.println("GENERATING " + e.getKey());
            final String docString = implicitDocs.get(e.getKey());
            final GetInitializer gi = e.getValue();

            final Struct s = (Struct) gi;
            final String[] name = e.getKey().split("\\.");
            final String[] pkg = new String[name.length - 1];
            for (int i = 0; i < pkg.length; i++) {
                pkg[i] = name[i];
            }
            final FileOutputStream fos = new FileOutputStream(mkPath(outputFolder, pkg, name[pkg.length]));
            final PrintWriter writer = new PrintWriter(new OutputStreamWriter(fos, "UTF-8"));
            writer.println("<?php");
            if (pkg.length > 0) {
                writer.print("namespace ");
                String sep = "";
                for (String pe : pkg) {
                    writer.print(sep + pe);
                    sep = "\\";
                }
                writer.println(";");
                writer.println("");
            }

            System.out.println("GENERATING: " + name[pkg.length]);
            writer.print("/** ");
            if (docString != null) {
                writer.println(docString.substring(3, docString.length() - 2));
            }
            writer.println("<i>This is a data/struct/value class generated by the SQLC compiler.</i> */");
            writer.println("final class " + name[pkg.length] + " {");
            for (final String p : s.listProperties()) {
                writer.print("\tpublic ");
                //writer.print(s.getType(p));
                writer.println(" $" + p + ";");
            }
            writer.println("}");
            writer.println("?>");
            writer.close();
            fos.close();
        }
    }

    public static void compile(final String outputFolder, final SQLClass q, final StructManager sm,
            final Set<String> implicits, final Map<String, ExceptionInfo> exceptions) throws IOException {
        final String visibility = q.isPublic() ? "public " : " ";
        System.out.println("COMPILING " + visibility + " " + q.getName());
        final String finality = q.isOpen() ? "" : "final ";
        final String[] name = q.getName().split("\\.");
        final String[] pkg = new String[name.length - 1];
        for (int i = 0; i < pkg.length; i++) {
            pkg[i] = name[i];
        }
        logger.debug("package name:" + q.getName() + " - " + name.length);

        try (final FileOutputStream fos = new FileOutputStream(mkPath(outputFolder, pkg, name[pkg.length]))) {
            try (final PrintWriter writer = new PrintWriter(new OutputStreamWriter(fos, "UTF-8"))) {

                writer.println("<?php");
                writer.println(q.packageDoc);
                if (pkg.length > 0) {
                    writer.print("namespace ");
                    String sep = "";
                    for (final String pe : pkg) {
                        writer.print(sep + pe);
                        sep = "\\";
                    }
                    writer.println(";");
                    writer.println("");
                }

                writer.print("/**");
                writer.println(q.docString.substring(3, q.docString.length() - 2));
                writer.println("<i>This is a SQL query class generated by the SQLC compiler.</i> */");
                writer.println(finality + " class " + name[pkg.length] + " {");
                /* TO DO writer.println("\tprivate final net.metanotion.util.Dictionary<Class,net.metanotion.util.types.Parser> types;");
                writer.println("\tpublic " + name[pkg.length]
                   + "() { this.types = new net.metanotion.util.types.TypeDictionary(); }");
                writer.println("\tpublic " + name[pkg.length]
                   + "(net.metanotion.util.Dictionary<Class,net.metanotion.util.types.Parser> types) { this.types = types; }");
                */
                for (final SQLMethod m : q.getMethods()) {
                    final int[] gensym = new int[] { 1 };
                    final String type = (m.modifier == null) ? m.finalType : (m.modifier + "<" + m.finalType + ">");
                    if (!"".equals(m.docString)) {
                        writer.println(m.docString);
                    } else {
                        writer.println("\t/**");
                        writer.println("\t\t@param $_0 PDO connection object.");
                        int ct = 1;
                        for (final String p : m.pList) {
                            writer.println("\t\t@param $_" + Integer.toString(ct) + " " + p + ": "
                                    + m.parameterTypes.get(p));
                            ct++;
                        }
                        writer.println("\t*/");
                    }
                    writer.print("\tpublic function " /*+ type + " "*/ + m.name + "(/* pdo */ $_0");
                    for (final String p : m.pList) {
                        writer.print(", /* " + p + ": " + m.parameterTypes.get(p) + " */ $_" + gensym[0]);
                        gensym[0]++;
                    }
                    writer.println(") {");
                    /* TO DO - when exception handling for PHP is understood.
                    writer.println(") throws");
                    for(final ExceptionBlock ex: m.exceptions) {
                       writer.println("\t\t" + ex.name +",");
                    }
                    writer.println("\t\tException {");
                    */
                    //if(m.exceptions.size() > 0) { writer.println("\t\ttry {"); }
                    makeMethod(writer, m, m.body, 0, gensym, new int[] { 0 }, true);
                    /* TO DO - when exception handling for PHP is understood.
                    if(m.exceptions.size() > 0) {
                       final int exVar = gensym[0];
                       gensym[0]++;
                       writer.println("\t\t} catch (final java.sql.SQLException _" + exVar + ") {");
                       for(final ExceptionBlock ex: m.exceptions) {
                          writer.println("\t\t\tif (");
                          String sep = "";
                          for(final ExceptionBlock.Pattern pattern: ex.patterns) {
                    writer.print("\t\t\t\t\t" + sep);
                    if(pattern instanceof ExceptionBlock.EqualityCheck) {
                       final ExceptionBlock.EqualityCheck ec = (ExceptionBlock.EqualityCheck) pattern;
                       final Object value = ((ExceptionBlock.Literal) ec.value).value;
                       writer.print("(" + value + ".equals(");
                       if("SQLState".equals(ec.variable)) {
                          writer.print("_" + exVar + ".getSQLState())");
                       } else if("message".equals(ec.variable)) {
                          writer.print("_" + exVar + ".getMessage())");
                       }
                       writer.println(")");
                    } else if (pattern instanceof ExceptionBlock.ValueContains) {
                       final ExceptionBlock.ValueContains vc = (ExceptionBlock.ValueContains) pattern;
                       if(!"message".equals(vc.variable)) {
                          throw new RuntimeException("message only supported exception variable for contains clause.");
                       }
                       writer.print("(");
                       String sep2 = "";
                       for(final ExceptionBlock.Param value: vc.values) {
                          final Object v = ((ExceptionBlock.Literal) value).value;
                          writer.println(sep2 + "(_" + exVar + ".getMessage().contains(" + v + "))");
                          sep2 = "\t\t\t\t\t\t&&";
                       }
                       writer.print("\t\t\t\t\t)");
                    } else {
                       throw new RuntimeException("invalid exception throw pattern.");
                    }
                    sep = "&&";
                          }
                          writer.println("\t\t\t) {");
                          writer.println("\t\t\t\tthrow new " + ex.name + "(");
                          sep = "";
                          for(final ExceptionBlock.Param param: ex.params) {
                    writer.print("\t\t\t\t\t" + sep);
                    if(param instanceof ExceptionBlock.Literal) {
                       writer.println(((ExceptionBlock.Literal) param).value.toString());
                    } else {
                       throw new RuntimeException("variables in custom exception parameters not supported.");
                    }
                    sep = ", ";
                          }
                          writer.println("\t\t\t\t);");
                          writer.println("\t\t\t} else");
                       }
                       writer.println("\t\t\t{ throw _" + exVar + "; }");
                       writer.println("\t\t}");
                    }*/
                    writer.println("\t}");
                }
                writer.println("}");
                writer.println("?>");
            }
        }
    }

    public static int makeMethod(final PrintWriter writer, final SQLMethod m, final QueryExpr qe, final int level,
            final int[] gensym, final int[] braces, final boolean retValue) {
        if (qe instanceof AssignmentWrap) {
            return makeMethod(writer, m, (AssignmentWrap) qe, level, gensym, braces, retValue);
            /*      } else if(qe instanceof CountWrap) {
                     return makeMethod(writer, m, (CountWrap) qe, level, gensym, braces, retValue);*/
        } else if (qe instanceof DoWrap) {
            return makeMethod(writer, m, (DoWrap) qe, level, gensym, braces, retValue);
        } else if (qe instanceof ListWrap) {
            return makeMethod(writer, m, (ListWrap) qe, level, gensym, braces, retValue);
        } else if (qe instanceof Statement) {
            return makeMethod(writer, m, (Statement) qe, level, gensym, braces, retValue);
            /*      } else if(qe instanceof StatementMacro) {
                     return makeMethod(writer, m, (StatementMacro) qe, level, gensym, braces, retValue);
                  } else if(qe instanceof TXWrap) {
                     return makeMethod(writer, m, (TXWrap) qe, level, gensym, braces, retValue);
                  } else if(qe instanceof OptionalWrap) {
                     return makeMethod(writer, m, (OptionalWrap) qe, level, gensym, braces, retValue);
                  } else if(qe instanceof ValueWrap) {
                     return makeMethod(writer, m, (ValueWrap) qe, level, gensym, braces, retValue);
                  } else if(qe instanceof VoidWrap) {
                     return makeMethod(writer, m, (VoidWrap) qe, level, gensym, braces, retValue);*/
        } else {
            //         throw new RuntimeException("Invalid QueryExpr type");
            return 0;
        }
    }

    public static int makeMethod(final PrintWriter writer, final SQLMethod m, final AssignmentWrap qe,
            final int level, final int[] gensym, final int[] braces, final boolean retValue) {
        final int val = gensym[0];
        gensym[0] += 1;
        writer.println("\t\t$_" + (val) + " = new " + qe.result + "();");
        /*
              final int gi = gensym[0];
              final int init = gensym[0] + 1;
              gensym[0]+=2;
              writer.println("\t\t\tfinal net.metanotion.util.reflect.GetInitializer<" + qe.result + "> _" + gi
                 + " = net.metanotion.util.reflect.ReflectiveFieldInitializer.getInitializer("
                 + qe.result + ".class, this.types);");
              writer.println("\t\t\tfinal net.metanotion.util.reflect.Initializer<" + qe.result + "> _" + init
                 + " = _" + gi + ".initializer();");
        */
        final Iterator<String> fields = qe.fields.iterator();
        final Iterator<QueryExpr> qs = qe.exprs.iterator();
        while (qs.hasNext()) {
            final QueryExpr q = qs.next();
            final String field = fields.next();
            int returnSymbol = makeMethod(writer, m, q, level, gensym, braces, false);
            writer.println("\t\t\t$_" + (val) + "->" + field + " = $_" + (returnSymbol) + ";");
        }
        //writer.println("\t\t\treturn _" + init + ".instance();");
        writer.println("\t\treturn $_" + (val) + ";");
        while (braces[0] > 0) {
            writer.println("}");
            braces[0]--;
        }
        return -1;
    }

    public static int makeMethod(final PrintWriter writer, final SQLMethod m, final Statement qe, final int level,
            final int[] gensym, final int[] braces, final boolean retValue) {
        final int stmt = gensym[0];
        gensym[0]++;
        /*
              writer.println("\t\t\ttry (final java.sql.PreparedStatement _" + stmt
                 + " = _0.prepareStatement(\"" + StringEscapeUtils.escapeJava(qe.sql.trim()) + "\")) {");
        */
        writer.println(
                "\t\t\t$_" + stmt + " = $_0.prepare(\"" + StringEscapeUtils.escapeJava(qe.sql.trim()) + "\");");
        //braces[0] = braces[0] + 1;
        for (final SQLSetter s : qe.setters) {
            int i = 0;
            for (int j = 0; j < m.pList.length; j++) {
                if (s.name.equals(m.pList[j])) {
                    i = j + 1;
                    break;
                }
            }
            writer.println("\t\t\t" + s.setStatic("$_" + stmt, "_" + i) + ";");
        }
        writer.println("\t\t\t$_" + stmt + ".execute();");
        return -1;
    }

    public static int makeMethod(final PrintWriter writer, final SQLMethod m, final ListWrap qe, final int level,
            final int[] gensym, final int[] braces, final boolean retValue) {
        makeMethod(writer, m, qe.e, level + 1, gensym, braces, retValue);
        final int stmt = gensym[0] - 1;

        //      final int rsVar = gensym[0];
        //      gensym[0]++;

        //writer.println("\t\t\ttry (final java.sql.ResultSet _" + rsVar + " = _" + stmt + ".getResultSet()) {");
        //      braces[0] = braces[0] + 1;

        // convert result set to list.
        final int list = gensym[0];
        gensym[0]++;

        final int row = gensym[0] + 1;
        gensym[0] += 1;
        if (qe.g instanceof StructGetter) {
            final StructGetter sg = (StructGetter) qe.g;
            writer.println("\t\t\t$_" + list + " = array();");
            final int init = gensym[0] + 1;
            gensym[0] += 1;
            writer.println("\t\t\twhile ($_" + row + " = $_" + stmt + "->fetch()) {");
            writer.println("\t\t$_" + init + " = new " + sg.struct + "();");
            for (final RSGetter rg : sg.fields) {
                writer.println("\t\t\t\t\t$_" + init + "->" + rg.name + " = " + rg.getStatic("$_" + row) + ";");
            }
            writer.println("\t\t\t\t\t$_" + list + "[] = $_" + init + ";");
        } else if (qe.g instanceof ValueGetter) {
            final RSGetter rg = ((ValueGetter) qe.g).field;
            writer.println("\t\t\t$_" + list + " = array();");

            writer.println("\t\t\twhile ($_" + row + " = $_" + stmt + "->fetch()) {");
            writer.println("\t\t\t\t\t$_" + list + "[] = " + rg.getStatic("$_" + row, 1) + ";");
        }
        writer.println("\t\t}");
        if (retValue) {
            writer.println("\t\t\treturn $_" + list + ";");
            while (braces[0] > 0) {
                writer.println("}");
                braces[0]--;
            }
        }
        return list;
    }

    public static int makeMethod(final PrintWriter writer, final SQLMethod m, final DoWrap qe, final int level,
            final int[] gensym, final int[] braces, final boolean retValue) {
        for (final QueryExpr<PreparedStatement> e : qe.exprs) {
            makeMethod(writer, m, e, level + 1, gensym, braces, retValue);
        }
        if (level == 0) {
            writer.println("\t\t\treturn $_" + (gensym[0] - 1) + ";");
            while (braces[0] > 0) {
                writer.println("}");
                braces[0]--;
            }
        }
        return gensym[0] - 1;
    }
}