fix CLI type detection
[yosql.git] / yosql-codegen / src / main / java / wtf / metio / yosql / codegen / files / DefaultSqlStatementParser.java
blob1f2224d306b40d9d8238d2cc6e50c9ddb08a27a4
1 /*
2 * This file is part of yosql. It is subject to the license terms in the LICENSE file found in the top-level
3 * directory of this distribution and at https://creativecommons.org/publicdomain/zero/1.0/. No part of yosql,
4 * including this file, may be copied, modified, propagated, or distributed except according to the terms contained
5 * in the LICENSE file.
6 */
7 package wtf.metio.yosql.codegen.files;
9 import org.slf4j.cal10n.LocLogger;
10 import wtf.metio.yosql.codegen.lifecycle.ApplicationErrors;
11 import wtf.metio.yosql.codegen.lifecycle.ParseLifecycle;
12 import wtf.metio.yosql.codegen.orchestration.ExecutionErrors;
13 import wtf.metio.yosql.models.immutables.FilesConfiguration;
14 import wtf.metio.yosql.models.immutables.SqlStatement;
16 import java.io.BufferedReader;
17 import java.io.IOException;
18 import java.io.StringReader;
19 import java.nio.file.Files;
20 import java.nio.file.Path;
21 import java.util.Objects;
22 import java.util.concurrent.atomic.AtomicInteger;
23 import java.util.function.Consumer;
24 import java.util.regex.Pattern;
25 import java.util.stream.Stream;
27 import static java.util.function.Predicate.not;
29 /**
30 * Default SQL file parser.
32 public final class DefaultSqlStatementParser implements SqlStatementParser {
34 private static final String SQL_COMMENT_PREFIX = "--";
35 private static final String NEWLINE = "\n";
37 private final Pattern statementSplitter;
38 private final LocLogger logger;
39 private final SqlConfigurationFactory factory;
40 private final FilesConfiguration files;
41 private final ExecutionErrors errors;
43 public DefaultSqlStatementParser(
44 final LocLogger logger,
45 final SqlConfigurationFactory factory,
46 final FilesConfiguration files,
47 final ExecutionErrors errors) {
48 statementSplitter = Pattern.compile(files.sqlStatementSeparator());
49 this.logger = logger;
50 this.factory = factory;
51 this.files = files;
52 this.errors = errors;
55 @Override
56 public Stream<SqlStatement> parse(final Path source) {
57 try {
58 final var charset = files.sqlFilesCharset();
59 final var rawText = Files.readString(source, charset);
60 final var skippedText = skipLines(rawText);
61 final var counter = new AtomicInteger(1);
62 return statementSplitter.splitAsStream(skippedText)
63 .parallel()
64 .filter(Objects::nonNull)
65 .map(String::strip)
66 .filter(not(String::isBlank))
67 .map(statement -> parseStatement(source, statement, counter.getAndIncrement()));
68 } catch (final IOException exception) {
69 errors.add(exception);
70 logger.debug(ApplicationErrors.FILE_PARSING_FAILED, source);
71 return Stream.empty();
75 private String skipLines(final String rawText) {
76 final var builder = new StringBuilder(rawText);
77 for (int index = 0; index < files.skipLines(); index++) {
78 builder.delete(0, builder.indexOf("\n") + 1);
80 return builder.toString();
83 private SqlStatement parseStatement(
84 final Path source,
85 final String rawStatement,
86 final int statementInFile) {
87 final var yaml = new StringBuilder();
88 final var sql = new StringBuilder();
90 splitUpYamlAndSql(rawStatement, yaml::append, sql::append);
92 logger.trace(ParseLifecycle.STATEMENT_PARSING_STARTING, rawStatement);
93 final String rawYaml = yaml.toString();
94 final String rawSqlStatement = sql.toString();
95 logger.trace(ParseLifecycle.STATEMENT_YAML_FRONT_MATTER_PARSED, rawYaml);
96 logger.trace(ParseLifecycle.STATEMENT_PARSED, rawSqlStatement);
98 final var parameterIndices = SqlStatementParser.extractParameterIndices(rawSqlStatement);
99 final var configuration = factory.createConfiguration(source, rawYaml,
100 parameterIndices, statementInFile);
101 logger.debug(ParseLifecycle.STATEMENT_PARSING_FINISHED, source, configuration.name());
102 return SqlStatement.builder()
103 .setSourcePath(source)
104 .setConfiguration(configuration)
105 .setRawStatement(rawSqlStatement)
106 .build();
109 private void splitUpYamlAndSql(
110 final String rawStatement,
111 final Consumer<String> yaml,
112 final Consumer<String> sql) {
113 try (final var reader = new StringReader(rawStatement);
114 final var buffer = new BufferedReader(reader)) {
115 buffer.lines()
116 .filter(line -> !line.strip().isEmpty())
117 .filter(line -> !SQL_COMMENT_PREFIX.equals(line.strip()))
118 .forEach(line -> split(yaml, sql, line));
119 } catch (final IOException exception) {
120 errors.add(exception);
124 private static void split(
125 final Consumer<String> yaml,
126 final Consumer<String> sql,
127 final String line) {
128 if (line.startsWith(SQL_COMMENT_PREFIX)) {
129 yaml.accept(line.substring(2));
130 yaml.accept(NEWLINE);
131 } else {
132 sql.accept(line);
133 sql.accept(NEWLINE);