From e182f821103859229685d057dce0335ec07a10e5 Mon Sep 17 00:00:00 2001 From: dspeck1 Date: Thu, 5 Sep 2024 12:47:46 -0500 Subject: [PATCH] Add tap support for BigQuery as backend. --- cadc-tap-server-bigquery/README.md | 3 + cadc-tap-server-bigquery/build.gradle | 49 ++ .../expression/BqColumnAliasSelectItem.java | 92 ++++ .../tap/expression/BqExpressionDeParser.java | 83 +++ .../tap/expression/BqKeywordExpression.java | 116 +++++ .../tap/parser/BqQuerySelectDeParser.java | 100 ++++ .../parser/converter/BqRegionConverter.java | 472 ++++++++++++++++++ .../tap/parser/region/function/BqCircle.java | 86 ++++ .../region/function/BqGeometricFunction.java | 156 ++++++ .../tap/parser/region/function/BqPoint.java | 86 ++++ .../tap/parser/region/function/BqPolygon.java | 115 +++++ .../tap/writer/format/BqFormatFactory.java | 91 ++++ .../converter/BqRegionConverterTest.java | 307 ++++++++++++ .../parser/region/function/BqCircleTest.java | 93 ++++ .../parser/region/function/BqPointTest.java | 90 ++++ .../parser/region/function/BqPolygonTest.java | 116 +++++ 16 files changed, 2055 insertions(+) create mode 100644 cadc-tap-server-bigquery/README.md create mode 100644 cadc-tap-server-bigquery/build.gradle create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqColumnAliasSelectItem.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqExpressionDeParser.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqKeywordExpression.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/BqQuerySelectDeParser.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverter.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqCircle.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqGeometricFunction.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPoint.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPolygon.java create mode 100644 cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/writer/format/BqFormatFactory.java create mode 100644 cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverterTest.java create mode 100644 cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqCircleTest.java create mode 100644 cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPointTest.java create mode 100644 cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPolygonTest.java diff --git a/cadc-tap-server-bigquery/README.md b/cadc-tap-server-bigquery/README.md new file mode 100644 index 00000000..2d2bcf94 --- /dev/null +++ b/cadc-tap-server-bigquery/README.md @@ -0,0 +1,3 @@ +# cadc-tap-server-bigquery 1.0.0 + +Offers BigQuery support to handle datatype conversions in ADQL. \ No newline at end of file diff --git a/cadc-tap-server-bigquery/build.gradle b/cadc-tap-server-bigquery/build.gradle new file mode 100644 index 00000000..e2de7df7 --- /dev/null +++ b/cadc-tap-server-bigquery/build.gradle @@ -0,0 +1,49 @@ +plugins { + id "java" + id "maven" + id 'maven-publish' + id 'checkstyle' +} + +repositories { + mavenCentral() + mavenLocal() + // tmp to resolve uk.ac.starlink + jcenter() +} + +apply from: '../opencadc.gradle' + +sourceCompatibility = 1.8 + +group = 'org.opencadc' + +version = '1.0.5' + +description = 'OpenCADC TAP-1.1 tap server plugin (BigQuery)' +def git_url = 'https://github.com/opencadc/tap' + +dependencies { + implementation 'org.opencadc:cadc-tap-schema:[1.1.22,)' + implementation 'org.opencadc:cadc-tap-server:[1.1.7,)' + implementation 'org.opencadc:cadc-adql:[1.1.10,)' + implementation 'org.opencadc:cadc-jsqlparser-compat:[0.6.4,)' + + testImplementation 'junit:junit:[4.0,5.0)' + testImplementation 'org.opencadc:cadc-util:[1.6,)' + testImplementation 'xerces:xercesImpl:[2.0,)' +} + +publishing { + + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/burwood/tap-bigquery" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } +} \ No newline at end of file diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqColumnAliasSelectItem.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqColumnAliasSelectItem.java new file mode 100644 index 00000000..2e971be3 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqColumnAliasSelectItem.java @@ -0,0 +1,92 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.expression; + +import net.sf.jsqlparser.statement.select.SelectExpressionItem; +import net.sf.jsqlparser.statement.select.SelectItemVisitor; + +public class BqColumnAliasSelectItem extends SelectExpressionItem { + public BqColumnAliasSelectItem(SelectExpressionItem selectExpressionItem) { + super(); + setExpression(selectExpressionItem.getExpression()); + setAlias(selectExpressionItem.getAlias()); + } + + @Override + public void accept(SelectItemVisitor selectItemVisitor) { + selectItemVisitor.visit(this); + } + + @Override + public String toString() { + String alias = getAlias(); + return (alias == null) ? getExpression() + "" : alias; + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqExpressionDeParser.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqExpressionDeParser.java new file mode 100644 index 00000000..027e9d02 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqExpressionDeParser.java @@ -0,0 +1,83 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2018. (c) 2018. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.expression; + +import ca.nrc.cadc.tap.parser.BaseExpressionDeParser; +import net.sf.jsqlparser.statement.select.SelectVisitor; + +public class BqExpressionDeParser extends BaseExpressionDeParser { + public BqExpressionDeParser(SelectVisitor selectVisitor, StringBuffer buffer) { + super(selectVisitor, buffer); + } + + void visit(BqKeywordExpression expression) { + buffer.append(expression.toString()); + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqKeywordExpression.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqKeywordExpression.java new file mode 100644 index 00000000..9abad06f --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/expression/BqKeywordExpression.java @@ -0,0 +1,116 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2018. (c) 2018. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.expression; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.ExpressionVisitor; + + +public class BqKeywordExpression implements Expression { + + private final String keyword; + + public BqKeywordExpression(String keyword) { + this.keyword = keyword; + } + + @Override + public void accept(ExpressionVisitor expressionVisitor) { + if (expressionVisitor instanceof BqExpressionDeParser) { + ((BqExpressionDeParser) expressionVisitor).visit(this); + } + } + + /** + * Returns a string representation of the object. In general, the + * {@code toString} method returns a string that + * "textually represents" this object. The result should + * be a concise but informative representation that is easy for a + * person to read. + * It is recommended that all subclasses override this method. + * + *

The {@code toString} method for class {@code Object} + * returns a string consisting of the name of the class of which the + * object is an instance, the at-sign character `{@code @}', and + * the unsigned hexadecimal representation of the hash code of the + * object. In other words, this method returns a string equal to the + * value of: + *

+ *
+     * getClass().getName() + '@' + Integer.toHexString(hashCode())
+     * 
+ * + * @return a string representation of the object. + */ + @Override + public String toString() { + return keyword; + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/BqQuerySelectDeParser.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/BqQuerySelectDeParser.java new file mode 100644 index 00000000..b20aba09 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/BqQuerySelectDeParser.java @@ -0,0 +1,100 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser; + +import ca.nrc.cadc.tap.expression.BqColumnAliasSelectItem; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectExpressionItem; + + +public class BqQuerySelectDeParser extends QuerySelectDeParser { + @Override + public void visit(PlainSelect plainSelect) { + super.visit(plainSelect); + } + + @Override + public void visit(SelectExpressionItem selectExpressionItem) { + Expression selectExpression = selectExpressionItem.getExpression(); + + if (selectExpression instanceof Column) { + String normalizedColumnName = ((Column) selectExpression).getColumnName().replaceAll("\"", ""); + ((Column) selectExpression).setColumnName(normalizedColumnName); + } + + if (selectExpressionItem instanceof BqColumnAliasSelectItem) { + getBuffer().append(selectExpressionItem); + } else { + super.visit(selectExpressionItem); + } + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverter.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverter.java new file mode 100644 index 00000000..16a92f60 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverter.java @@ -0,0 +1,472 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.converter; + +import ca.nrc.cadc.tap.parser.ParserUtil; +import ca.nrc.cadc.tap.parser.RegionFinder; +import ca.nrc.cadc.tap.parser.navigator.ExpressionNavigator; +import ca.nrc.cadc.tap.parser.navigator.FromItemNavigator; +import ca.nrc.cadc.tap.parser.navigator.ReferenceNavigator; +import ca.nrc.cadc.tap.parser.region.function.BqCircle; +import ca.nrc.cadc.tap.parser.region.function.BqPoint; +import ca.nrc.cadc.tap.parser.region.function.BqPolygon; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals; +import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class BqRegionConverter extends RegionFinder { + + private static final Logger LOGGER = Logger.getLogger(BqRegionConverter.class); + + private static final String CONTAINS_FUNCTION_NAME = "ST_CONTAINS"; + private static final String NOT_FUNCTION_NAME = "NOT"; + private static final String DWITHIN_FUNCTION_NAME = "ST_DWITHIN"; + private static final String INTERSECTS_FUNCTION_NAME = "ST_INTERSECTS"; + private static final String ST_AREA_FUNCTION_NAME = "ST_AREA"; + private static final String ST_DISTANCE_FUNCTION_NAME = "ST_DISTANCE"; + private static final String ST_MAXDISTANCE_FUNCTION_NAME = "ST_MAXDISTANCE"; + private static final List MEASURE_FUNCTIONS = Arrays.asList(ST_DISTANCE_FUNCTION_NAME, ST_MAXDISTANCE_FUNCTION_NAME, ST_AREA_FUNCTION_NAME); + private static final double DEGREE_ARC_SECONDS = 3600; + private static final double ARC_SECOND_METERS = 30.8874796235; + private static final String SAFE_DIVIDE = "SAFE_DIVIDE"; + private static final String SAFE_MULTIPLY = "SAFE_MULTIPLY"; + + public BqRegionConverter(ExpressionNavigator en, ReferenceNavigator rn, + FromItemNavigator fn) { + super(en, rn, fn); + } + + @Override + public Expression convertToImplementation(Function func) { + return super.convertToImplementation(func); + } + + /** + * This method is called when a REGION PREDICATE function is one of the arguments in a binary expression, + * and after the direct function conversion. + * + *

Supported functions: CONTAINS + * + *

Examples: + * + *

CONTAINS() = 0 + * CONTAINS() = 1 + * 1 = CONTAINS() + * 0 = CONTAINS() + */ + @Override + protected Expression handleRegionPredicate(BinaryExpression binaryExpression) { + LOGGER.debug("handleRegionPredicate(" + binaryExpression.getClass().getSimpleName() + "): " + binaryExpression); + + binaryExpression = convertToMeters(binaryExpression); + + Expression left = binaryExpression.getLeftExpression(); + Expression right = binaryExpression.getRightExpression(); + + if (!(binaryExpression instanceof EqualsTo)) { + return binaryExpression; + } + + Expression binaryValueExpression = null; + Expression containsExpression = null; + + if ((isFunction(left) || isBinaryExpression(left)) && ParserUtil.isBinaryValue(right)) { + containsExpression = left; + binaryValueExpression = right; + } + + if (ParserUtil.isBinaryValue(left) && (isFunction(right) || isBinaryExpression(right))) { + containsExpression = right; + binaryValueExpression = left; + } + + if (containsExpression == null) { + return binaryExpression; + } + + boolean isTrueExpression = binaryValueExpression.toString().equals("1"); + if (!isTrueExpression) { + Expression notBinaryExpression = handleNotExpression(containsExpression); + return notBinaryExpression; + } + + return containsExpression; + } + + /** + * This method is called when a CONTAINS is found outside of a predicate. + * This could occur if the query had CONTAINS(...) in the select list or as + * part of an arithmetic expression or aggregate function (since CONTAINS + * returns a numeric value). + * In Bq, we need to switch the arguments. + */ + @Override + protected Expression handleContains(Expression left, Expression right) { + if (isCircle(left)) { + if (isContainsPolygon(right)) { + return polygonContainsCircle(right, left); + } + + return circleIntersects(left, right, true); + } + + if (isCircle(right)) { + if (isContainsPolygon(left)) { + return circleContainsPolygon(left, right); + } + + return circleIntersects(left, right, true); + } + + Function containsFunction = new Function(); + containsFunction.setName(CONTAINS_FUNCTION_NAME); + List paramList = Arrays.asList(right, left); + + ExpressionList parameters = new ExpressionList(paramList); + containsFunction.setParameters(parameters); + + return containsFunction; + } + + private Function handleNotExpression(Expression containsFunction) { + Function notFunction = new Function(); + ExpressionList parameters = new ExpressionList(Arrays.asList(containsFunction)); + + notFunction.setName(NOT_FUNCTION_NAME); + notFunction.setParameters(parameters); + + return notFunction; + } + + /** + * This method is called when a POINT geometry value is found. + */ + @Override + protected Expression handlePoint(Expression coordsys, Expression ra, Expression dec) { + return new BqPoint(ra, dec); + } + + /** + * This method is called when a POLYGON geometry value is found. + */ + @Override + protected Expression handlePolygon(List expressions) { + return new BqPolygon(expressions); + } + + /** + * This method is called when a CIRCLE geometry value is found. + */ + @Override + protected Expression handleCircle(Expression coordsys, Expression ra, Expression dec, Expression radiusExpression) { + + if (isNumberValue((radiusExpression))) { + double radius = getDoubleValue(radiusExpression).getValue(); + + if (radius > 0.0D) { + return new BqCircle(ra, dec, radiusExpression); + } + } + + LOGGER.debug("Radius is missing or is 0.0. Returning a POINT instead."); + return handlePoint(coordsys, ra, dec); + } + + /** + * This method is called when a INTERSECTS is found outside of a predicate. + * This could occur if the query had INTERSECTS(...) in the select list or as + * part of an arithmetic expression or aggregate function (since INTERSECTS + * returns a numeric value). + */ + @Override + protected Expression handleIntersects(Expression left, Expression right) { + if (isContainsCircle(left, right)) { + return circleIntersects(left, right, false); + } + + Function intersectsFunction = new Function(); + ExpressionList parameters = new ExpressionList(Arrays.asList(right, left)); + + intersectsFunction.setName(INTERSECTS_FUNCTION_NAME); + intersectsFunction.setParameters(parameters); + + return intersectsFunction; + } + + @Override + protected Expression handleArea(Function areaFunction) { + areaFunction.setName(ST_AREA_FUNCTION_NAME); + + return metersToDegreeFunction(areaFunction); + } + + private BinaryExpression convertToMeters(BinaryExpression binaryExpression) { + Expression left = binaryExpression.getLeftExpression(); + Expression right = binaryExpression.getRightExpression(); + + if (isFunction(right)) { + Expression measureFunction = getInternalMeasureFunction(right); + if (measureFunction != null) { + right = measureFunction; + binaryExpression.setRightExpression(right); + + if (isNumberValue(left)) { + DoubleValue leftNormalized = getDoubleValue(left); + DoubleValue leftInMeters = getArchDistanceInMetersFromExpression(leftNormalized); + binaryExpression.setLeftExpression(leftInMeters); + } + } + } + + if (isFunction(left)) { + Expression measureFunction = getInternalMeasureFunction(left); + if (measureFunction != null) { + left = measureFunction; + binaryExpression.setLeftExpression(left); + + if (isNumberValue(right)) { + DoubleValue rightNormalized = getDoubleValue(right); + DoubleValue rightInMeters = getArchDistanceInMetersFromExpression(rightNormalized); + binaryExpression.setRightExpression(rightInMeters); + } + } + } + + return binaryExpression; + } + + private Expression getInternalMeasureFunction(Expression expression) { + List measureFunctionParams = ((Function) expression).getParameters().getExpressions(); + + return measureFunctionParams + .stream() + .filter(exp -> isFunction(exp) && MEASURE_FUNCTIONS.contains(((Function) exp).getName())) + .findAny() + .orElse(null); + } + + private Function handleDistance(Expression left, Expression right, String distanceFunctionName) { + Function distanceFunction = new Function(); + ExpressionList parameters = new ExpressionList(Arrays.asList(right, left)); + + distanceFunction.setName(distanceFunctionName); + distanceFunction.setParameters(parameters); + + return distanceFunction; + } + + private Expression metersToDegreeFunction(Function measuresFunction) { + Function multiplyFunction = new Function(); + multiplyFunction.setName(SAFE_MULTIPLY); + ExpressionList multiplyFunctionParameters = new ExpressionList( + Arrays.asList( + new DoubleValue(Double.toString(DEGREE_ARC_SECONDS)), + new DoubleValue(Double.toString(ARC_SECOND_METERS)) + ) + ); + multiplyFunction.setParameters(multiplyFunctionParameters); + + Function divideFunction = new Function(); + divideFunction.setName(SAFE_DIVIDE); + ExpressionList divideFunctionParameters = new ExpressionList(Arrays.asList(measuresFunction, multiplyFunction)); + divideFunction.setParameters(divideFunctionParameters); + + return divideFunction; + } + + /** + * This method is called when DISTANCE function is found. + */ + @Override + protected Expression handleDistance(Expression left, Expression right) { + Function distanceFunction = handleDistance(left, right, ST_DISTANCE_FUNCTION_NAME); + return metersToDegreeFunction(distanceFunction); + } + + private DoubleValue getDoubleValue(Expression expression) { + return isDoubleValue(expression) ? + (DoubleValue) expression : + new DoubleValue(((Long) ((LongValue) expression).getValue()).toString()); + } + + private boolean isDoubleValue(Expression expression) { + return (expression instanceof DoubleValue); + } + + private boolean isLongValue(Expression expression) { + return (expression instanceof LongValue); + } + + private boolean isNumberValue(Expression expression) { + return isDoubleValue(expression) || isLongValue(expression); + } + + private boolean isFunction(Expression expression) { + return (expression instanceof Function); + } + + private boolean isBinaryExpression(Expression expression) { + return (expression instanceof BinaryExpression); + } + + private boolean isCircle(Expression expression) { + return expression.toString().toLowerCase().contains("circle"); + } + + private boolean isContainsCircle(Expression left, Expression right) { + return isCircle(left) || isCircle(right); + } + + private DoubleValue getRadius(Expression expression) { + Expression radiusExpression = (Expression) ((Function) expression).getParameters().getExpressions().get(1); + + double radius = getDoubleValue(radiusExpression).getValue(); + double archDistanceInMeters = getArchDistanceInMeters(radius); + + return new DoubleValue(Double.toString(archDistanceInMeters)); + } + + private DoubleValue getArchDistanceInMetersFromExpression(Expression expression) { + double measurement = ((DoubleValue) expression).getValue(); + double measurementInMeters = getArchDistanceInMeters(measurement); + return new DoubleValue(Double.toString(measurementInMeters)); + } + + private double getArchDistanceInMeters(double measurement) { + return measurement * DEGREE_ARC_SECONDS * ARC_SECOND_METERS; + } + + private Expression getCircleCenterPoint(Expression expression) { + return (Expression) ((Function) expression).getParameters().getExpressions().get(0); + } + + private List circleDataParams(Expression left, Expression right, boolean isContains) { + if (isCircle(left)) { + DoubleValue radius = right.toString().toLowerCase().contains("point") && isContains ? + new DoubleValue("0") : + getRadius(left); + + return new ArrayList<>(Arrays.asList(right, getCircleCenterPoint(left), radius)); + } + + return new ArrayList<>(Arrays.asList(getCircleCenterPoint(right), left, getRadius(right))); + } + + private Expression shapeContainsShape(Expression left, Expression right, String distanceFunctionName, BinaryExpression binaryExpression) { + List paramList = circleDataParams(left, right, true); + + int lastIndex = paramList.size() - 1; + Expression radius = paramList.get(lastIndex); + paramList.remove(lastIndex); + + Expression containsFunction = handleDistance(paramList.get(0), paramList.get(1), distanceFunctionName); + binaryExpression.setLeftExpression(containsFunction); + binaryExpression.setRightExpression(radius); + + return binaryExpression; + } + + private Expression circleContainsPolygon(Expression left, Expression right) { + MinorThanEquals minorThanEquals = new MinorThanEquals(); + Expression containsExpression = shapeContainsShape(left, right, ST_MAXDISTANCE_FUNCTION_NAME, minorThanEquals); + + return containsExpression; + } + + private Expression polygonContainsCircle(Expression left, Expression right) { + GreaterThanEquals greaterThanEquals = new GreaterThanEquals(); + Expression containsExpression = shapeContainsShape(left, right, ST_DISTANCE_FUNCTION_NAME, greaterThanEquals); + + return containsExpression; + } + + private Function circleIntersects(Expression left, Expression right, boolean isContains) { + Function intersectsFunction = new Function(); + + intersectsFunction.setName(DWITHIN_FUNCTION_NAME); + List paramList = circleDataParams(left, right, isContains); + + ExpressionList parameters = new ExpressionList(paramList); + intersectsFunction.setParameters(parameters); + + return intersectsFunction; + } + + private boolean isContainsPolygon(Expression expression) { + return expression.toString().toLowerCase().contains("polygon"); + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqCircle.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqCircle.java new file mode 100644 index 00000000..4a2e82d3 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqCircle.java @@ -0,0 +1,86 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + + +public class BqCircle extends BqGeometricFunction { + public BqCircle(Expression ra, Expression dec, Expression radius) { + super(ra, dec, radius); + } + + @Override + String mapValues(ExpressionList parameterList) { + // Do nothing. + return null; + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqGeometricFunction.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqGeometricFunction.java new file mode 100644 index 00000000..d0efaa05 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqGeometricFunction.java @@ -0,0 +1,156 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import ca.nrc.cadc.tap.expression.BqKeywordExpression; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.Function; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Abstract class for an Bq Geometric Function. + */ +abstract class BqGeometricFunction extends Function { + + private static final String POINT_FUNCTION_NAME = "ST_GEOGPOINT"; + private static final String CIRCLE_FUNCTION_NAME = "CIRCLE"; + private static final String POLYGON_FUNCTION_NAME = "ST_MAKEPOLYGON"; + private static final String LINE_FUNCTION_NAME = "ST_MAKELINE"; + private static final String ARRAY = "ARRAY"; + + final List vertices = new ArrayList<>(); + + BqGeometricFunction(Expression ra, Expression dec) { + setName(POINT_FUNCTION_NAME); + + ExpressionList parameters = new ExpressionList(new ArrayList<>()); + parameters.getExpressions().add(ra); + parameters.getExpressions().add(dec); + + setParameters(parameters); + } + + BqGeometricFunction(Expression ra, Expression dec, Expression radius) { + setName(CIRCLE_FUNCTION_NAME); + + Function pointFunction = new Function(); + pointFunction.setName(POINT_FUNCTION_NAME); + pointFunction.setParameters(new ExpressionList(Arrays.asList(ra, dec))); + + ExpressionList parameters = new ExpressionList(new ArrayList<>()); + parameters.getExpressions().add(pointFunction); + parameters.getExpressions().add(radius); + + setParameters(parameters); + } + + BqGeometricFunction(List verticeExpressions) { + if (verticeExpressions != null) { + List verticeValues = verticeExpressions.stream().skip(1).collect(Collectors.toList()); + vertices.addAll(verticeValues); + } + } + + private Function getMakeLineFunction() { + Function makeLineFunction = new Function(); + makeLineFunction.setName(LINE_FUNCTION_NAME); + + return makeLineFunction; + } + + /** + * For Polygon shapes (i.e. non-point shapes), convert the values to be used as function parameters. Point + * Functions can omit this call. + */ + void processVerticesParameters() { + setName(POLYGON_FUNCTION_NAME); + + Function makeLineFunction = getMakeLineFunction(); + + ExpressionList verticesArrayFunctionParameters = new ExpressionList(new ArrayList<>()); + String geoText = String.format("%s%s", ARRAY, mapValues(verticesArrayFunctionParameters)); + + makeLineFunction.setParameters(new ExpressionList(Arrays.asList(new BqKeywordExpression(geoText)))); + + setParameters(new ExpressionList(Arrays.asList(makeLineFunction))); + } + + /** + * Map this shape's values to BQ function parameters. + * + * @param parameterList The ExpressionList to add parameters to. + */ + abstract String mapValues(ExpressionList parameterList); +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPoint.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPoint.java new file mode 100644 index 00000000..11c6cad9 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPoint.java @@ -0,0 +1,86 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + + +public class BqPoint extends BqGeometricFunction { + public BqPoint(Expression ra, Expression dec) { + super(ra, dec); + } + + @Override + String mapValues(ExpressionList parameterList) { + // Do nothing. + return null; + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPolygon.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPolygon.java new file mode 100644 index 00000000..d7d4427f --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/parser/region/function/BqPolygon.java @@ -0,0 +1,115 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class BqPolygon extends BqGeometricFunction { + + public BqPolygon(List verticeExpressions) { + super(verticeExpressions); + + if (!vertices.isEmpty()) { + processVerticesParameters(); + } + } + + /** + * Map this shape's values to BQ function parameters. + * + * @param parameterList The ExpressionList to add parameters to. + */ + @Override + String mapValues(ExpressionList parameterList) { + ExpressionList points = new ExpressionList( + IntStream + .range(0, vertices.size()) + .filter(i -> i % 2 == 0) + .mapToObj(i -> pointBuilder(i)) + .collect(Collectors.toList()) + ); + + points.getExpressions().add(pointBuilder(0)); + + return points.getExpressions().toString(); + } + + private BqPoint pointBuilder(int i) { + Expression ra = vertices.get(i); + Expression dec = vertices.get(i + 1); + + return new BqPoint(ra, dec); + } +} diff --git a/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/writer/format/BqFormatFactory.java b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/writer/format/BqFormatFactory.java new file mode 100644 index 00000000..8a2dc0a1 --- /dev/null +++ b/cadc-tap-server-bigquery/src/main/java/ca/nrc/cadc/tap/writer/format/BqFormatFactory.java @@ -0,0 +1,91 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2018. (c) 2018. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.writer.format; + +import ca.nrc.cadc.dali.util.Format; +import ca.nrc.cadc.tap.TapSelectItem; + +public class BqFormatFactory extends DefaultFormatFactory { + + @Override + protected Format getPointFormat(TapSelectItem columnDesc) { + throw new UnsupportedOperationException("no formatter for column " + columnDesc.getName()); + } + + @Override + protected Format getPolygonFormat(TapSelectItem columnDesc) { + throw new UnsupportedOperationException("no formatter for column " + columnDesc.getName()); + } + + @Override + protected Format getRegionFormat(TapSelectItem columnDesc) { + throw new UnsupportedOperationException("no formatter for column " + columnDesc.getName()); + } +} diff --git a/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverterTest.java b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverterTest.java new file mode 100644 index 00000000..0cdd2ec5 --- /dev/null +++ b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/converter/BqRegionConverterTest.java @@ -0,0 +1,307 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.converter; + +import ca.nrc.cadc.tap.parser.navigator.ExpressionNavigator; +import ca.nrc.cadc.tap.parser.navigator.FromItemNavigator; +import ca.nrc.cadc.tap.parser.navigator.ReferenceNavigator; +import ca.nrc.cadc.tap.parser.region.function.BqCircle; +import ca.nrc.cadc.tap.parser.region.function.BqPoint; +import net.sf.jsqlparser.expression.*; +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; +import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; +import org.junit.Assert; +import org.junit.Test; + + +public class BqRegionConverterTest { + + @Test + public void handleContains() { + + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression left = new BqPoint(ra, dec); + + Expression longitude = new DoubleValue("88.0"); + Expression latitude = new DoubleValue("12.0"); + Expression radiusInDegrees = new DoubleValue("0.8"); + + Expression right = new BqCircle(longitude, latitude, radiusInDegrees); + + Expression result = bqRegionConverter.handleContains(left, right); + + assert result instanceof Function; + + Function resultFunction = (Function) result; + String resultFunctionSource = resultFunction.toString(); + + Assert.assertEquals("ST_DWITHIN(ST_GEOGPOINT(88.0, 12.0), ST_GEOGPOINT(16.8, 33.4), 88955.94131568)", + resultFunctionSource); + } + + @Test + public void handleRegionPredicateContains() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression left = new BqPoint(ra, dec); + + Expression longitude = new DoubleValue("88.0"); + Expression latitude = new DoubleValue("12.0"); + Expression radiusInDegrees = new DoubleValue("0.8"); + + Expression right = new BqCircle(longitude, latitude, radiusInDegrees); + + Expression containsFunction = bqRegionConverter.handleContains(left, right); + + assert containsFunction instanceof Function; + + BinaryExpression equals = new EqualsTo(); + + equals.setLeftExpression(containsFunction); + equals.setRightExpression(new LongValue("1")); + + Expression result = bqRegionConverter.handleRegionPredicate(equals); + String resultFunctionSource = result.toString(); + + Assert.assertEquals("ST_DWITHIN(ST_GEOGPOINT(88.0, 12.0), ST_GEOGPOINT(16.8, 33.4), 88955.94131568)", resultFunctionSource); + } + + @Test + public void handleColumnReferenceContains() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression left = new BqPoint(ra, dec); + + Expression right = new Column(new Table(), "s_region"); + Expression distanceFunction = bqRegionConverter.handleContains(left, right); + + assert distanceFunction instanceof Function; + + Assert.assertEquals("ST_CONTAINS(s_region, ST_GEOGPOINT(16.8, 33.4))", distanceFunction.toString()); + } + +/* + @Test + public void handleColumnReference() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression left = new BqPoint(new Column(new Table(), "ra"), + new Column(new Table(), "dec")); + + Expression longitude = new DoubleValue("88.0"); + Expression latitude = new DoubleValue("12.0"); + Expression radiusInDegrees = new DoubleValue("0.8"); + + Expression right = new BqCircle(longitude, latitude, radiusInDegrees); + + Expression distanceFunction = bqRegionConverter.handleDistance(left, right); + + assert distanceFunction instanceof Function; + + Assert.assertEquals("ST_DISTANCE(CIRCLE(ST_GEOGPOINT(88.0, 12.0), 0.8), ST_GEOGPOINT(ra, dec))", distanceFunction.toString()); + } + */ + + @Test + public void handleRegionPredicateIntersects() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression left = new BqPoint(ra, dec); + + Expression longitude = new DoubleValue("88.0"); + Expression latitude = new DoubleValue("12.0"); + Expression radiusInDegrees = new DoubleValue("0.8"); + + Expression right = new BqCircle(longitude, latitude, radiusInDegrees); + + Expression intersectsFunction = bqRegionConverter.handleIntersects(left, right); + + assert intersectsFunction instanceof Function; + + BinaryExpression equals = new EqualsTo(); + + equals.setLeftExpression(intersectsFunction); + equals.setRightExpression(new LongValue("0")); + + Expression result = bqRegionConverter.handleRegionPredicate(equals); + String resultFunctionSource = result.toString(); + + Assert.assertEquals("NOT(ST_DWITHIN(ST_GEOGPOINT(88.0, 12.0), ST_GEOGPOINT(16.8, 33.4), 88955.94131568))", resultFunctionSource); + } + + @Test + public void handleColumnReferenceIntersects() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression left = new BqPoint(ra, dec); + + Expression right = new Column(new Table("bq", "table"), "shape"); + + Expression intersectsFunction = bqRegionConverter.handleIntersects(left, right); + + assert intersectsFunction instanceof Function; + + BinaryExpression equals = new EqualsTo(); + + equals.setLeftExpression(intersectsFunction); + equals.setRightExpression(new LongValue("0")); + + Expression result = bqRegionConverter.handleRegionPredicate(equals); + String resultFunctionSource = result.toString(); + + Assert.assertEquals("NOT(ST_INTERSECTS(bq.table.shape, ST_GEOGPOINT(16.8, 33.4)))", resultFunctionSource); + } + + @Test + public void handleColumnReferenceIntersectsNoRadius() { + final double longitude = 204.25382917D; + final double latitude = -29.86576111D; + final double radius = 0.0d; + + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression left = bqRegionConverter.handleCircle(null, + new DoubleValue(Double.toString(longitude)), + new DoubleValue(Double.toString(latitude)), + new DoubleValue(Double.toString(radius))); + Expression right = new Column(new Table("bq", "table"), "region"); + Expression intersectsFunction = bqRegionConverter.handleIntersects(left, right); + + assert intersectsFunction instanceof Function; + + BinaryExpression equals = new EqualsTo(); + + equals.setLeftExpression(intersectsFunction); + equals.setRightExpression(new LongValue(Long.toString(0L))); + + Expression result = bqRegionConverter.handleRegionPredicate(equals); + String resultFunctionSource = result.toString(); + + Assert.assertEquals("NOT(ST_INTERSECTS(bq.table.region, ST_GEOGPOINT(204.25382917, -29.86576111)))", resultFunctionSource); + } + + + @Test + public void handleDistance() { + BqRegionConverter bqRegionConverter = new BqRegionConverter(new ExpressionNavigator(), + new ReferenceNavigator(), + new FromItemNavigator()); + + Expression longitude = new DoubleValue("88.0"); + Expression latitude = new DoubleValue("12.0"); + Expression radiusInDegrees = new DoubleValue("0.8"); + + Expression left = new BqCircle(longitude, latitude, radiusInDegrees); + + Expression ra = new DoubleValue("16.8"); + Expression dec = new DoubleValue("33.4"); + + Expression right = new BqPoint(ra, dec); + + Expression distanceFunction = bqRegionConverter.handleDistance(left, right); + + assert distanceFunction instanceof Function; + + Assert.assertEquals("SAFE_DIVIDE(ST_DISTANCE(ST_GEOGPOINT(16.8, 33.4), CIRCLE(ST_GEOGPOINT(88.0, 12.0), 0.8)), SAFE_MULTIPLY(3600.0, 30.8874796235))", distanceFunction.toString()); + } + + +} diff --git a/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqCircleTest.java b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqCircleTest.java new file mode 100644 index 00000000..aef5e206 --- /dev/null +++ b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqCircleTest.java @@ -0,0 +1,93 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.DoubleValue; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import org.junit.Assert; +import org.junit.Test; + + +public class BqCircleTest { + @Test + public void convertParameters() { + Expression longitude = new DoubleValue("3.4"); + Expression latitude = new DoubleValue("88.5"); + Expression radiusInDegrees = new DoubleValue("0.7"); + + BqCircle testSubject = new BqCircle(longitude, latitude, radiusInDegrees); + ExpressionList result = testSubject.getParameters(); + String resultExpressions = result.getExpressions().toString(); + + + Assert.assertEquals("[ST_GEOGPOINT(3.4, 88.5), 0.7]", resultExpressions); + } +} diff --git a/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPointTest.java b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPointTest.java new file mode 100644 index 00000000..7369bc66 --- /dev/null +++ b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPointTest.java @@ -0,0 +1,90 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.DoubleValue; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import org.junit.Assert; +import org.junit.Test; + +public class BqPointTest { + @Test + public void convertParameters() { + Expression ra = new DoubleValue("13.4"); + Expression dec = new DoubleValue("70.49"); + + BqPoint testSubject = new BqPoint(ra, dec); + ExpressionList result = testSubject.getParameters(); + String resultExpressions = result.getExpressions().toString(); + + Assert.assertEquals("[13.4, 70.49]", resultExpressions); + } +} diff --git a/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPolygonTest.java b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPolygonTest.java new file mode 100644 index 00000000..3d5fd107 --- /dev/null +++ b/cadc-tap-server-bigquery/src/test/java/ca/nrc/cadc/tap/parser/region/function/BqPolygonTest.java @@ -0,0 +1,116 @@ + +/* + ************************************************************************ + ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* + ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** + * + * (c) 2019. (c) 2019. + * Government of Canada Gouvernement du Canada + * National Research Council Conseil national de recherches + * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 + * All rights reserved Tous droits réservés + * + * NRC disclaims any warranties, Le CNRC dénie toute garantie + * expressed, implied, or énoncée, implicite ou légale, + * statutory, of any kind with de quelque nature que ce + * respect to the software, soit, concernant le logiciel, + * including without limitation y compris sans restriction + * any warranty of merchantability toute garantie de valeur + * or fitness for a particular marchande ou de pertinence + * purpose. NRC shall not be pour un usage particulier. + * liable in any event for any Le CNRC ne pourra en aucun cas + * damages, whether direct or être tenu responsable de tout + * indirect, special or general, dommage, direct ou indirect, + * consequential or incidental, particulier ou général, + * arising from the use of the accessoire ou fortuit, résultant + * software. Neither the name de l'utilisation du logiciel. Ni + * of the National Research le nom du Conseil National de + * Council of Canada nor the Recherches du Canada ni les noms + * names of its contributors may de ses participants ne peuvent + * be used to endorse or promote être utilisés pour approuver ou + * products derived from this promouvoir les produits dérivés + * software without specific prior de ce logiciel sans autorisation + * written permission. préalable et particulière + * par écrit. + * + * This file is part of the Ce fichier fait partie du projet + * OpenCADC project. OpenCADC. + * + * OpenCADC is free software: OpenCADC est un logiciel libre ; + * you can redistribute it and/or vous pouvez le redistribuer ou le + * modify it under the terms of modifier suivant les termes de + * the GNU Affero General Public la “GNU Affero General Public + * License as published by the License” telle que publiée + * Free Software Foundation, par la Free Software Foundation + * either version 3 of the : soit la version 3 de cette + * License, or (at your option) licence, soit (à votre gré) + * any later version. toute version ultérieure. + * + * OpenCADC is distributed in the OpenCADC est distribué + * hope that it will be useful, dans l’espoir qu’il vous + * but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE + * without even the implied GARANTIE : sans même la garantie + * warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ + * or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF + * PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence + * General Public License for Générale Publique GNU Affero + * more details. pour plus de détails. + * + * You should have received Vous devriez avoir reçu une + * a copy of the GNU Affero copie de la Licence Générale + * General Public License along Publique GNU Affero avec + * with OpenCADC. If not, see OpenCADC ; si ce n’est + * . pas le cas, consultez : + * . + * + * + ************************************************************************ + */ + +package ca.nrc.cadc.tap.parser.region.function; + +import net.sf.jsqlparser.expression.DoubleValue; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.StringValue; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + + +public class BqPolygonTest { + @Test + public void convertParameters() { + List expressionList = new ArrayList<>(); + expressionList.add(new StringValue("\"ICRS\"")); + expressionList.add(new DoubleValue("88.0")); + expressionList.add(new DoubleValue("188.0")); + expressionList.add(new DoubleValue("288.0")); + expressionList.add(new DoubleValue("388.0")); + expressionList.add(new DoubleValue("288.0")); + expressionList.add(new DoubleValue("28.0")); + + BqPolygon testSubject = new BqPolygon(expressionList); + String resultExpressions = testSubject.getParameters().getExpressions().toString(); + + Assert.assertEquals("[ST_MAKELINE(ARRAY[ST_GEOGPOINT(88.0, 188.0), ST_GEOGPOINT(288.0, 388.0), ST_GEOGPOINT(288.0, 28.0), ST_GEOGPOINT(88.0, 188.0)])]", resultExpressions); + } + + @Test + public void convertParametersFromPolygon() { + List expressionList = new ArrayList<>(); + expressionList.add(new StringValue("\"ICRS\"")); + expressionList.add(new DoubleValue("88.0")); + expressionList.add(new DoubleValue("188.0")); + expressionList.add(new DoubleValue("288.0")); + expressionList.add(new DoubleValue("388.0")); + expressionList.add(new DoubleValue("288.0")); + expressionList.add(new DoubleValue("28.0")); + + BqPolygon testSubject = new BqPolygon(expressionList); + String resultExpressions = testSubject.getParameters().getExpressions().toString(); + + Assert.assertEquals("[ST_MAKELINE(ARRAY[ST_GEOGPOINT(88.0, 188.0), ST_GEOGPOINT(288.0, 388.0), ST_GEOGPOINT(288.0, 28.0), ST_GEOGPOINT(88.0, 188.0)])]", resultExpressions); + } +}