Repository: calcite Updated Branches: refs/heads/master 9ba9bdc1d -> ed424ed81
http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeEmbeddedPolicy.java ---------------------------------------------------------------------- diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeEmbeddedPolicy.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeEmbeddedPolicy.java new file mode 100644 index 0000000..b1045b3 --- /dev/null +++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeEmbeddedPolicy.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.adapter.geode.rel; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.distributed.AbstractLauncher; +import org.apache.geode.distributed.ServerLauncher; + +import com.google.common.base.Preconditions; + +import org.junit.rules.ExternalResource; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Manages embedded Geode instance using native {@link ServerLauncher}. + */ +public class GeodeEmbeddedPolicy extends ExternalResource { + + private final ServerLauncher launcher; + + private GeodeEmbeddedPolicy(final ServerLauncher launcher) { + Objects.requireNonNull(launcher, "launcher"); + Preconditions.checkState(!launcher.isRunning(), "Launcher process is already running"); + this.launcher = launcher; + } + + @Override protected void before() { + requireStatus(AbstractLauncher.Status.NOT_RESPONDING); + launcher.start(); + } + + @Override protected void after() { + if (launcher.status().getStatus() == AbstractLauncher.Status.ONLINE) { + CacheFactory.getAnyInstance().close(); + } + + final Path pidFile = Paths.get(launcher.getWorkingDirectory()).resolve("vf.gf.server.pid"); + launcher.stop(); + + if (Files.exists(pidFile)) { + // delete PID file. Otherwise ("next") geode instance complains about existing process + try { + Files.delete(pidFile); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + + /** + * Allows this instance to be shared by multiple test classes (in parallel). Guarantees that + * {@code before()} and {@code after()} methods will be called only once. This setup is useful + * for maven (surefire) plugin which executes tests in parallel (including {@code @ClassRule} + * methods) and may initialize (or destroy) same resource multiple times. + */ + GeodeEmbeddedPolicy share() { + return new RefCountPolicy(this); + } + + /** + * Returns current cache instance which was initialized for tests. + * @throws IllegalStateException if server process didn't start + */ + Cache cache() { + requireStatus(AbstractLauncher.Status.ONLINE); + return CacheFactory.getAnyInstance(); + } + + private void requireStatus(AbstractLauncher.Status expected) { + final AbstractLauncher.Status current = launcher.status().getStatus(); + Preconditions.checkState(current == expected, + "Expected state %s but got %s", expected, current); + } + + static GeodeEmbeddedPolicy create() { + final ServerLauncher launcher = new ServerLauncher.Builder() + .setMemberName("fake-geode") + .set("log-file", "") // log to stdout + .set("log-level", "severe") // minimal logging + .set("bind-address", "127.0.0.1") // accept internal connections only + .setServerPort(0) // bind to any available port + .setPdxPersistent(false) + .setPdxReadSerialized(true) + .build(); + + return new GeodeEmbeddedPolicy(launcher); + } + + /** + * Calls {@code before()} and {@code after()} methods only once (for first and last subscriber + * respectively). The implementation counts number of times {@link #before()} was called + * which determines number of "clients". Delegate {@link #after()} is called when that count + * reaches zero again (when last "client" called that method). + */ + private static class RefCountPolicy extends GeodeEmbeddedPolicy { + + private final AtomicInteger refCount; + + private final GeodeEmbeddedPolicy policy; + + RefCountPolicy(final GeodeEmbeddedPolicy policy) { + super(Objects.requireNonNull(policy, "policy").launcher); + this.policy = policy; + this.refCount = new AtomicInteger(); + } + + @Override GeodeEmbeddedPolicy share() { + // for cases like share().share() + return this; + } + + @Override public synchronized void before() { + try { + if (refCount.get() == 0) { + // initialize only once + policy.before(); + } + } finally { + refCount.incrementAndGet(); + } + } + + @Override protected void after() { + if (refCount.decrementAndGet() == 0) { + // destroy only once + policy.after(); + } + } + } +} + +// End GeodeEmbeddedPolicy.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java ---------------------------------------------------------------------- diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java deleted file mode 100644 index 2ca7df5..0000000 --- a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsIT.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.calcite.adapter.geode.rel; - -import org.apache.calcite.test.CalciteAssert; -import org.apache.calcite.util.Sources; -import org.apache.calcite.util.Util; - -import com.google.common.collect.ImmutableMap; - -import org.junit.Test; - -/** - * Tests for the {@code org.apache.calcite.adapter.geode} package. - * - * <p>Before calling this rel, you need to populate Geode, as follows: - * - * <blockquote><code> - * git clone https://github.com/vlsi/calcite-test-dataset<br> - * cd calcite-rel-dataset<br> - * mvn install - * </code></blockquote> - * - * <p>This will create a virtual machine with Geode and the "bookshop" and "zips" rel dataset. - */ -public class GeodeZipsIT { - /** - * Connection factory based on the "geode relational " model. - */ - public static final ImmutableMap<String, String> GEODE_ZIPS = - ImmutableMap.of("CONFORMANCE", "LENIENT", "model", - Sources.of(GeodeZipsIT.class.getResource("/model-zips.json")) - .file().getAbsolutePath()); - - - /** - * Whether to run Geode tests. Enabled by default, however rel is only - * included if "it" profile is activated ({@code -Pit}). To disable, - * specify {@code -Dcalcite.rel.geode=false} on the Java command line. - */ - public static final boolean ENABLED = Util.getBooleanProperty("calcite.rel.geode", true); - - /** - * Whether to run this rel. - */ - protected boolean enabled() { - return ENABLED; - } - - - @Test - public void testGroupByView() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"state\", SUM(\"pop\") FROM \"geode\".\"ZIPS\" GROUP BY \"state\"") - .returnsCount(51) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeAggregate(group=[{1}], EXPR$1=[SUM($0)])\n" - + " GeodeProject(pop=[CAST($3):INTEGER], state=[CAST($4):VARCHAR(2) CHARACTER SET" - + " \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testGroupByViewWithAliases() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"state\" as \"st\", SUM(\"pop\") \"po\" " - + "FROM \"geode\".\"ZIPS\" GROUP BY " - + "\"state\"") - .returnsCount(51) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeAggregate(group=[{1}], po=[SUM($0)])\n" - + " GeodeProject(pop=[CAST($3):INTEGER], state=[CAST($4):VARCHAR(2) CHARACTER SET" - + " \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testGroupByRaw() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"state\" as \"st\", SUM(\"pop\") \"po\" " - + "FROM \"geode_raw\".\"Zips\" GROUP" - + " BY \"state\"") - .returnsCount(51) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeAggregate(group=[{4}], po=[SUM($3)])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testGroupByRawWithAliases() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"state\" AS \"st\", SUM(\"pop\") AS \"po\" " - + "FROM \"geode_raw\".\"Zips\" " - + "GROUP BY \"state\"") - .returnsCount(51) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeAggregate(group=[{4}], po=[SUM($3)])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testMaxRaw() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT MAX(\"pop\") FROM \"geode_raw\".\"Zips\"") - .returnsCount(1) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeAggregate(group=[{}], EXPR$0=[MAX($3)])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testJoin() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"r\".\"_id\" FROM \"geode_raw\".\"Zips\" AS \"v\" JOIN \"geode_raw\"" - + ".\"Zips\" AS \"r\" ON \"v\".\"_id\" = \"r\".\"_id\" LIMIT 1") - .returnsCount(1) - .explainContains("PLAN=EnumerableCalc(expr#0..2=[{inputs}], _id1=[$t0])\n" - + " EnumerableLimit(fetch=[1])\n" - + " EnumerableJoin(condition=[=($1, $2)], joinType=[inner])\n" - + " GeodeToEnumerableConverter\n" - + " GeodeProject(_id=[$0], _id0=[CAST($0):VARCHAR CHARACTER SET " - + "\"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n" - + " GeodeToEnumerableConverter\n" - + " GeodeProject(_id0=[CAST($0):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE " - + "\"ISO-8859-1$en_US$primary\"])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testSelectLocItem() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" " - + "FROM \"geode_raw\".\"Zips\" LIMIT 1") - .returnsCount(1) - .returns("lat=-74.700748; lon=41.65158\n") - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" - + " GeodeSort(fetch=[1])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } - - @Test - public void testItemPredicate() { - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" " - + "FROM \"geode_raw\".\"Zips\" WHERE \"loc\"[0] < 0 LIMIT 1") - .returnsCount(1) - .returns("lat=-74.700748; lon=41.65158\n") - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" - + " GeodeSort(fetch=[1])\n" - + " GeodeFilter(condition=[<(ITEM($2, 0), 0)])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - - CalciteAssert.that() - .enable(enabled()) - .with(GEODE_ZIPS) - .query("SELECT \"loc\"[0] as \"lat\", \"loc\"[1] as \"lon\" " - + "FROM \"geode_raw\".\"Zips\" WHERE \"loc\"[0] > 0 LIMIT 1") - .returnsCount(0) - .explainContains("PLAN=GeodeToEnumerableConverter\n" - + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" - + " GeodeSort(fetch=[1])\n" - + " GeodeFilter(condition=[>(ITEM($2, 0), 0)])\n" - + " GeodeTableScan(table=[[geode_raw, Zips]])\n"); - } -} - -// End GeodeZipsIT.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java ---------------------------------------------------------------------- diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java new file mode 100644 index 0000000..7f23957 --- /dev/null +++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/GeodeZipsTest.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.adapter.geode.rel; + +import org.apache.calcite.jdbc.CalciteConnection; +import org.apache.calcite.schema.SchemaPlus; +import org.apache.calcite.schema.impl.ViewTable; +import org.apache.calcite.schema.impl.ViewTableMacro; +import org.apache.calcite.test.CalciteAssert; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.Region; + +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collections; + +/** + * Tests based on {@code zips-min.json} dataset. Runs automatically as part of CI. + */ +public class GeodeZipsTest extends AbstractGeodeTest { + + @BeforeClass + public static void setUp() throws Exception { + Cache cache = POLICY.cache(); + Region<?, ?> region = cache.<String, Object>createRegionFactory().create("zips"); + new JsonLoader(region).loadClasspathResource("/zips-mini.json"); + } + + private CalciteAssert.ConnectionFactory newConnectionFactory() { + return new CalciteAssert.ConnectionFactory() { + @Override public Connection createConnection() throws SQLException { + final Connection connection = DriverManager.getConnection("jdbc:calcite:lex=JAVA"); + final SchemaPlus root = connection.unwrap(CalciteConnection.class).getRootSchema(); + + root.add("geode", new GeodeSchema(POLICY.cache(), Collections.singleton("zips"))); + + // add calcite view programmatically + final String viewSql = "select \"_id\" AS \"id\", \"city\", \"loc\", " + + "cast(\"pop\" AS integer) AS \"pop\", cast(\"state\" AS varchar(2)) AS \"state\" " + + "from \"geode\".\"zips\""; + + + ViewTableMacro macro = ViewTable.viewMacro(root, viewSql, + Collections.singletonList("geode"), Arrays.asList("geode", "view"), false); + root.add("view", macro); + + return connection; + } + }; + } + + private CalciteAssert.AssertThat calciteAssert() { + return CalciteAssert.that() + .with(newConnectionFactory()); + } + + @Test + public void testGroupByView() { + calciteAssert() + .query("SELECT state, SUM(pop) FROM view GROUP BY state") + .returnsCount(51) + .queryContains( + GeodeAssertions.query("SELECT state AS state, " + + "SUM(pop) AS EXPR$1 FROM /zips GROUP BY state")); + } + + @Test + @Ignore("Currently fails") + public void testGroupByViewWithAliases() { + calciteAssert() + .query("SELECT state as st, SUM(pop) po " + + "FROM view GROUP BY state") + .queryContains( + GeodeAssertions.query("SELECT state, SUM(pop) AS po FROM /zips GROUP BY state")) + .returnsCount(51) + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeAggregate(group=[{1}], po=[SUM($0)])\n" + + " GeodeProject(pop=[CAST($3):INTEGER], state=[CAST($4):VARCHAR(2) CHARACTER SET" + + " \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } + + @Test + public void testGroupByRaw() { + calciteAssert() + .query("SELECT state as st, SUM(pop) po " + + "FROM geode.zips GROUP BY state") + .returnsCount(51) + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeAggregate(group=[{4}], po=[SUM($3)])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } + + @Test + public void testGroupByRawWithAliases() { + calciteAssert() + .query("SELECT state AS st, SUM(pop) AS po " + + "FROM geode.zips GROUP BY state") + .returnsCount(51) + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeAggregate(group=[{4}], po=[SUM($3)])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } + + @Test + public void testMaxRaw() { + calciteAssert() + .query("SELECT MAX(pop) FROM view") + .returns("EXPR$0=112047\n") + .queryContains(GeodeAssertions.query("SELECT MAX(pop) AS EXPR$0 FROM /zips")); + } + + @Test + @Ignore("Currently fails") + public void testJoin() { + calciteAssert() + .query("SELECT r._id FROM geode.zips AS v " + + "JOIN geode.zips AS r ON v._id = r._id LIMIT 1") + .returnsCount(1) + .explainContains("PLAN=EnumerableCalc(expr#0..2=[{inputs}], _id1=[$t0])\n" + + " EnumerableLimit(fetch=[1])\n" + + " EnumerableJoin(condition=[=($1, $2)], joinType=[inner])\n" + + " GeodeToEnumerableConverter\n" + + " GeodeProject(_id=[$0], _id0=[CAST($0):VARCHAR CHARACTER SET " + + "\"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n" + + " GeodeTableScan(table=[[geode, zips]])\n" + + " GeodeToEnumerableConverter\n" + + " GeodeProject(_id0=[CAST($0):VARCHAR CHARACTER SET \"ISO-8859-1\" COLLATE " + + "\"ISO-8859-1$en_US$primary\"])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } + + @Test + public void testSelectLocItem() { + calciteAssert() + .query("SELECT loc[0] as lat, loc[1] as lon " + + "FROM view LIMIT 1") + .returns("lat=-105.007985; lon=39.840562\n") + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" + + " GeodeSort(fetch=[1])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } + + @Test + public void testItemPredicate() { + calciteAssert() + .query("SELECT loc[0] as lat, loc[1] as lon " + + "FROM view WHERE loc[0] < 0 LIMIT 1") + .returnsCount(1) + .returns("lat=-105.007985; lon=39.840562\n") + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" + + " GeodeSort(fetch=[1])\n" + + " GeodeFilter(condition=[<(ITEM($2, 0), 0)])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + + calciteAssert() + .query("SELECT loc[0] as lat, loc[1] as lon " + + "FROM view WHERE loc[0] > 0 LIMIT 1") + .returnsCount(0) + .explainContains("PLAN=GeodeToEnumerableConverter\n" + + " GeodeProject(lat=[ITEM($2, 0)], lon=[ITEM($2, 1)])\n" + + " GeodeSort(fetch=[1])\n" + + " GeodeFilter(condition=[>(ITEM($2, 0), 0)])\n" + + " GeodeTableScan(table=[[geode, zips]])\n"); + } +} + +// End GeodeZipsTest.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/java/org/apache/calcite/adapter/geode/rel/JsonLoader.java ---------------------------------------------------------------------- diff --git a/geode/src/test/java/org/apache/calcite/adapter/geode/rel/JsonLoader.java b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/JsonLoader.java new file mode 100644 index 0000000..ea74b48 --- /dev/null +++ b/geode/src/test/java/org/apache/calcite/adapter/geode/rel/JsonLoader.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.calcite.adapter.geode.rel; + +import org.apache.geode.cache.Region; +import org.apache.geode.pdx.PdxInstance; +import org.apache.geode.pdx.PdxInstanceFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.Objects; + +/** + * Populates a geode region from a file having JSON entries (line by line). + */ +class JsonLoader { + + private static final String ROOT_PACKATE = "org.apache.calcite.adapter.geode"; + + private final String rootPackage; + private final Region region; + private final ObjectMapper mapper; + + JsonLoader(Region<?, ?> region) { + this.region = Objects.requireNonNull(region, "region"); + this.rootPackage = ROOT_PACKATE; + this.mapper = new ObjectMapper(); + } + + private void load(Reader reader) throws IOException { + Objects.requireNonNull(reader, "reader"); + try (BufferedReader br = new BufferedReader(reader)) { + int key = 0; + for (String line; (line = br.readLine()) != null;) { + Map jsonMap = mapper.readValue(line, Map.class); + PdxInstance pdxInstance = mapToPdx(rootPackage, jsonMap); + region.put(key++, pdxInstance); + } + } + } + + void loadClasspathResource(String location) throws IOException { + Objects.requireNonNull(location, "location"); + InputStream is = getClass().getResourceAsStream(location); + if (is == null) { + throw new IllegalArgumentException("Resource " + location + " not found in the classpath"); + } + + load(new InputStreamReader(is, StandardCharsets.UTF_8)); + } + + private PdxInstance mapToPdx(String packageName, Map<String, Object> map) { + PdxInstanceFactory pdxBuilder = region.getRegionService().createPdxInstanceFactory(packageName); + + for (String name : map.keySet()) { + Object value = map.get(name); + + if (value instanceof Map) { + pdxBuilder.writeObject(name, mapToPdx(packageName + "." + name, (Map) value)); + } else { + pdxBuilder.writeObject(name, value); + } + } + + return pdxBuilder.create(); + } + +} + +// End JsonLoader.java http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/book_customer.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/book_customer.json b/geode/src/test/resources/book_customer.json new file mode 100644 index 0000000..d32d20f --- /dev/null +++ b/geode/src/test/resources/book_customer.json @@ -0,0 +1,3 @@ +{"customerNumber":5598,"firstName":"Kari","lastName":"Powell","primaryAddress":{"addressLine1":"123 Main St.","addressLine2":null,"addressLine3":null,"city":"Topeka","state":"KS","postalCode":"50505","country":"US","phoneNumber":"423-555-3322","addressTag":"HOME"},"myBookOrders":[17699,18009,18049]} +{"customerNumber":5543,"firstName":"Lula","lastName":"Wax","primaryAddress":{"addressLine1":"123 Main St.","addressLine2":null,"addressLine3":null,"city":"Topeka","state":"KS","postalCode":"50505","country":"US","phoneNumber":"423-555-3322","addressTag":"HOME"},"myBookOrders":[17700]} +{"customerNumber":6024,"firstName":"Trenton","lastName":"Garcia","primaryAddress":{"addressLine1":"123 Main St.","addressLine2":null,"addressLine3":null,"city":"San Francisco","state":"CA","postalCode":"50505","country":"US","phoneNumber":"423-555-3322","addressTag":"HOME"},"myBookOrders":[]} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/book_master.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/book_master.json b/geode/src/test/resources/book_master.json new file mode 100644 index 0000000..5571971 --- /dev/null +++ b/geode/src/test/resources/book_master.json @@ -0,0 +1,3 @@ +{"itemNumber":123,"description":"Run on sentences and drivel on all things mundane","retailCost":34.99,"yearPublished":2011,"author":"Daisy Mae West","title":"A Treatise of Treatises"} +{"itemNumber":456,"description":"A book about a dog","retailCost":11.99,"yearPublished":1971,"author":"Clarence Meeks","title":"Clifford the Big Red Dog"} +{"itemNumber":789,"description":"Theoretical information about the structure of Operating Systems","retailCost":59.99,"yearPublished":2011,"author":"Jim Heavisides","title":"Operating Systems: An Introduction"} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/log4j.properties b/geode/src/test/resources/log4j.properties new file mode 100644 index 0000000..a62b381 --- /dev/null +++ b/geode/src/test/resources/log4j.properties @@ -0,0 +1,26 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to you under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Root logger is configured at INFO and is sent to A1 +log4j.rootLogger=INFO, A1 + +log4j.logger.org.apache.calcite.adapter.geode=WARN + +# A1 goes to the console +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# Set the pattern for each log message +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p - %m%n http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model-bookshop-all.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model-bookshop-all.json b/geode/src/test/resources/model-bookshop-all.json deleted file mode 100644 index 13ed2e5..0000000 --- a/geode/src/test/resources/model-bookshop-all.json +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "TEST", - "schemas": [ - { - "name": "TEST", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "BookMaster,BookCustomer,BookOrder,BookInventory", - "pdxSerializablePackagePath": "org.apache.calcite.adapter.geode.domain.bookshop.*" - } - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model-bookshop.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model-bookshop.json b/geode/src/test/resources/model-bookshop.json deleted file mode 100644 index aaab978..0000000 --- a/geode/src/test/resources/model-bookshop.json +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "TEST", - "schemas": [ - { - "name": "TEST", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "BookMaster,BookCustomer", - "pdxSerializablePackagePath": "org.apache.calcite.adapter.geode.*" - } - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model-geode-pg-federation.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model-geode-pg-federation.json b/geode/src/test/resources/model-geode-pg-federation.json deleted file mode 100644 index 586fafa..0000000 --- a/geode/src/test/resources/model-geode-pg-federation.json +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "geode", - "schemas": [ - { - "type": "custom", - "name": "geode_zips", - "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "Zips", - "pdxSerializablePackagePath": ".*" - } - }, - { - "type": "jdbc", - "name": "mysql_foodmart", - "jdbcUser": "foodmart", - "jdbcPassword": "foodmart", - "jdbcUrl": "jdbc:mysql://localhost", - "jdbcCatalog": "foodmart", - "jdbcSchema": null - }, - { - "type": "jdbc", - "name": "postgresql_foodmart", - "jdbcUser": "foodmart", - "jdbcPassword": "foodmart", - "jdbcDriver": "org.postgresql.Driver", - "jdbcUrl": "jdbc:postgresql://localhost/foodmart", - "jdbcCatalog": "foodmart", - "jdbcSchema": null - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model-with-classes.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model-with-classes.json b/geode/src/test/resources/model-with-classes.json deleted file mode 100644 index b776f0e..0000000 --- a/geode/src/test/resources/model-with-classes.json +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "TEST", - "schemas": [ - { - "name": "TEST", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "BookMaster,Customer,InventoryItem,BookOrder", - "BookMaster": "net.tzolov.geode.bookstore.domain.BookMaster", - "Customer": "net.tzolov.geode.bookstore.domain.Customer", - "InventoryItem": "net.tzolov.geode.bookstore.domain.InventoryItem", - "BookOrder": "net.tzolov.geode.bookstore.domain.BookOrder", - "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*" - } - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model-zips.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model-zips.json b/geode/src/test/resources/model-zips.json deleted file mode 100644 index 4077768..0000000 --- a/geode/src/test/resources/model-zips.json +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "geode_raw", - "schemas": [ - { - "name": "geode_raw", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.rel.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "Zips", - "pdxSerializablePackagePath": ".*" - } - }, - { - "name": "geode", - "tables": [ - { - "name": "ZIPS", - "type": "view", - "sql": [ - "select \"_id\" AS \"id\", \"city\", \"loc\", cast(\"pop\" AS integer) AS \"pop\", cast(\"state\" AS varchar(2)) AS \"state\" from \"geode_raw\".\"Zips\"" - ] - } - ] - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model.json b/geode/src/test/resources/model.json deleted file mode 100644 index c1a2c86..0000000 --- a/geode/src/test/resources/model.json +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "TEST", - "schemas": [ - { - "name": "TEST", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "BookMaster", - "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*" - } - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/model2.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/model2.json b/geode/src/test/resources/model2.json deleted file mode 100644 index 4cbe328..0000000 --- a/geode/src/test/resources/model2.json +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to you under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * A JSON model of a simple Calcite schema. - */ -{ - "version": "1.0", - "defaultSchema": "TEST", - "schemas": [ - { - "name": "TEST", - "type": "custom", - "factory": "org.apache.calcite.adapter.geode.simple.GeodeSchemaFactory", - "operand": { - "locatorHost": "localhost", - "locatorPort": "10334", - "regions": "BookMaster,Customer,InventoryItem,BookOrder", - "pdxSerializablePackagePath": "net.tzolov.geode.bookstore.domain.*" - } - } - ] -} http://git-wip-us.apache.org/repos/asf/calcite/blob/ed424ed8/geode/src/test/resources/zips-mini.json ---------------------------------------------------------------------- diff --git a/geode/src/test/resources/zips-mini.json b/geode/src/test/resources/zips-mini.json new file mode 100644 index 0000000..858117a --- /dev/null +++ b/geode/src/test/resources/zips-mini.json @@ -0,0 +1,149 @@ +{ "_id" : "01701", "city" : "FRAMINGHAM", "loc" : [ -71.42548600000001, 42.300665 ], "pop" : 65046, "state" : "MA" } +{ "_id" : "02154", "city" : "NORTH WALTHAM", "loc" : [ -71.236497, 42.382492 ], "pop" : 57871, "state" : "MA" } +{ "_id" : "02401", "city" : "BROCKTON", "loc" : [ -71.03434799999999, 42.081571 ], "pop" : 59498, "state" : "MA" } +{ "_id" : "02840", "city" : "MIDDLETOWN", "loc" : [ -71.30347999999999, 41.504502 ], "pop" : 47687, "state" : "RI" } +{ "_id" : "02860", "city" : "PAWTUCKET", "loc" : [ -71.39071300000001, 41.872873 ], "pop" : 45442, "state" : "RI" } +{ "_id" : "02895", "city" : "NORTH SMITHFIELD", "loc" : [ -71.513683, 41.99948 ], "pop" : 53733, "state" : "RI" } +{ "_id" : "03060", "city" : "NASHUA", "loc" : [ -71.466684, 42.756395 ], "pop" : 41438, "state" : "NH" } +{ "_id" : "03103", "city" : "MANCHESTER", "loc" : [ -71.449325, 42.965563 ], "pop" : 36613, "state" : "NH" } +{ "_id" : "03301", "city" : "CONCORD", "loc" : [ -71.527734, 43.218525 ], "pop" : 34035, "state" : "NH" } +{ "_id" : "04240", "city" : "LEWISTON", "loc" : [ -70.191619, 44.098538 ], "pop" : 40173, "state" : "ME" } +{ "_id" : "04401", "city" : "BANGOR", "loc" : [ -68.791839, 44.824199 ], "pop" : 40434, "state" : "ME" } +{ "_id" : "05301", "city" : "BRATTLEBORO", "loc" : [ -72.593322, 42.857353 ], "pop" : 17522, "state" : "VT" } +{ "_id" : "05401", "city" : "BURLINGTON", "loc" : [ -73.219875, 44.484023 ], "pop" : 39127, "state" : "VT" } +{ "_id" : "05701", "city" : "RUTLAND", "loc" : [ -72.97077299999999, 43.614131 ], "pop" : 22576, "state" : "VT" } +{ "_id" : "06010", "city" : "BRISTOL", "loc" : [ -72.930193, 41.682293 ], "pop" : 60670, "state" : "CT" } +{ "_id" : "06450", "city" : "MERIDEN", "loc" : [ -72.799734, 41.533396 ], "pop" : 59441, "state" : "CT" } +{ "_id" : "06902", "city" : "STAMFORD", "loc" : [ -73.53742800000001, 41.052552 ], "pop" : 54605, "state" : "CT" } +{ "_id" : "07002", "city" : "BAYONNE", "loc" : [ -74.119169, 40.666399 ], "pop" : 61444, "state" : "NJ" } +{ "_id" : "07087", "city" : "WEEHAWKEN", "loc" : [ -74.030558, 40.768153 ], "pop" : 69646, "state" : "NJ" } +{ "_id" : "07111", "city" : "IRVINGTON", "loc" : [ -74.23127100000001, 40.7261 ], "pop" : 60986, "state" : "NJ" } +{ "_id" : "10021", "city" : "NEW YORK", "loc" : [ -73.958805, 40.768476 ], "pop" : 106564, "state" : "NY" } +{ "_id" : "11226", "city" : "BROOKLYN", "loc" : [ -73.956985, 40.646694 ], "pop" : 111396, "state" : "NY" } +{ "_id" : "11373", "city" : "JACKSON HEIGHTS", "loc" : [ -73.878551, 40.740388 ], "pop" : 88241, "state" : "NY" } +{ "_id" : "17042", "city" : "CLEONA", "loc" : [ -76.425895, 40.335912 ], "pop" : 61993, "state" : "PA" } +{ "_id" : "18042", "city" : "FORKS TOWNSHIP", "loc" : [ -75.23582, 40.6867 ], "pop" : 65784, "state" : "PA" } +{ "_id" : "19143", "city" : "PHILADELPHIA", "loc" : [ -75.228819, 39.944815 ], "pop" : 80454, "state" : "PA" } +{ "_id" : "19711", "city" : "NEWARK", "loc" : [ -75.737534, 39.701129 ], "pop" : 50573, "state" : "DE" } +{ "_id" : "19720", "city" : "MANOR", "loc" : [ -75.589938, 39.67703 ], "pop" : 46906, "state" : "DE" } +{ "_id" : "19901", "city" : "DOVER", "loc" : [ -75.535983, 39.156639 ], "pop" : 46005, "state" : "DE" } +{ "_id" : "20011", "city" : "WASHINGTON", "loc" : [ -77.020251, 38.951786 ], "pop" : 62924, "state" : "DC" } +{ "_id" : "20301", "city" : "PENTAGON", "loc" : [ -77.038196, 38.891019 ], "pop" : 21, "state" : "DC" } +{ "_id" : "21061", "city" : "GLEN BURNIE", "loc" : [ -76.61886199999999, 39.158968 ], "pop" : 75692, "state" : "MD" } +{ "_id" : "21207", "city" : "GWYNN OAK", "loc" : [ -76.734064, 39.329628 ], "pop" : 76002, "state" : "MD" } +{ "_id" : "21215", "city" : "BALTIMORE", "loc" : [ -76.67939699999999, 39.344572 ], "pop" : 74402, "state" : "MD" } +{ "_id" : "22901", "city" : "CHARLOTTESVILLE", "loc" : [ -78.490869, 38.054752 ], "pop" : 62708, "state" : "VA" } +{ "_id" : "23464", "city" : "VIRGINIA BEACH", "loc" : [ -76.175909, 36.797772 ], "pop" : 67276, "state" : "VA" } +{ "_id" : "23602", "city" : "NEWPORT NEWS", "loc" : [ -76.53212499999999, 37.131684 ], "pop" : 68525, "state" : "VA" } +{ "_id" : "25801", "city" : "BECKLEY", "loc" : [ -81.206084, 37.793214 ], "pop" : 45196, "state" : "WV" } +{ "_id" : "26003", "city" : "ELM GROVE", "loc" : [ -80.685126, 40.072736 ], "pop" : 49136, "state" : "WV" } +{ "_id" : "26505", "city" : "STAR CITY", "loc" : [ -79.95422499999999, 39.633858 ], "pop" : 70185, "state" : "WV" } +{ "_id" : "27292", "city" : "LEXINGTON", "loc" : [ -80.262049, 35.82306 ], "pop" : 69179, "state" : "NC" } +{ "_id" : "28677", "city" : "STATESVILLE", "loc" : [ -80.894009, 35.799022 ], "pop" : 52895, "state" : "NC" } +{ "_id" : "29150", "city" : "OSWEGO", "loc" : [ -80.32100800000001, 33.928199 ], "pop" : 46394, "state" : "SC" } +{ "_id" : "29501", "city" : "FLORENCE", "loc" : [ -79.772786, 34.18375 ], "pop" : 66990, "state" : "SC" } +{ "_id" : "29801", "city" : "AIKEN", "loc" : [ -81.71942900000001, 33.553024 ], "pop" : 51233, "state" : "SC" } +{ "_id" : "30032", "city" : "DECATUR", "loc" : [ -84.263165, 33.740825 ], "pop" : 56056, "state" : "GA" } +{ "_id" : "30906", "city" : "PEACH ORCHARD", "loc" : [ -82.038358, 33.402024 ], "pop" : 58646, "state" : "GA" } +{ "_id" : "32216", "city" : "JACKSONVILLE", "loc" : [ -81.547387, 30.293907 ], "pop" : 58867, "state" : "FL" } +{ "_id" : "33012", "city" : "HIALEAH", "loc" : [ -80.30589999999999, 25.865395 ], "pop" : 73194, "state" : "FL" } +{ "_id" : "33311", "city" : "FORT LAUDERDALE", "loc" : [ -80.172786, 26.142104 ], "pop" : 65378, "state" : "FL" } +{ "_id" : "35215", "city" : "CENTER POINT", "loc" : [ -86.693197, 33.635447 ], "pop" : 43862, "state" : "AL" } +{ "_id" : "35401", "city" : "TUSCALOOSA", "loc" : [ -87.56266599999999, 33.196891 ], "pop" : 42124, "state" : "AL" } +{ "_id" : "35901", "city" : "SOUTHSIDE", "loc" : [ -86.010279, 33.997248 ], "pop" : 44165, "state" : "AL" } +{ "_id" : "37042", "city" : "CLARKSVILLE", "loc" : [ -87.418621, 36.585315 ], "pop" : 43296, "state" : "TN" } +{ "_id" : "37211", "city" : "NASHVILLE", "loc" : [ -86.72403799999999, 36.072486 ], "pop" : 51478, "state" : "TN" } +{ "_id" : "38109", "city" : "MEMPHIS", "loc" : [ -90.073238, 35.042538 ], "pop" : 60508, "state" : "TN" } +{ "_id" : "39180", "city" : "VICKSBURG", "loc" : [ -90.85065, 32.325824 ], "pop" : 46968, "state" : "MS" } +{ "_id" : "39401", "city" : "HATTIESBURG", "loc" : [ -89.306471, 31.314553 ], "pop" : 41866, "state" : "MS" } +{ "_id" : "39440", "city" : "LAUREL", "loc" : [ -89.13115500000001, 31.705444 ], "pop" : 45040, "state" : "MS" } +{ "_id" : "40214", "city" : "LOUISVILLE", "loc" : [ -85.77802699999999, 38.159318 ], "pop" : 42198, "state" : "KY" } +{ "_id" : "40216", "city" : "SHIVELY", "loc" : [ -85.831771, 38.186138 ], "pop" : 41719, "state" : "KY" } +{ "_id" : "40601", "city" : "HATTON", "loc" : [ -84.88061, 38.192831 ], "pop" : 46563, "state" : "KY" } +{ "_id" : "44035", "city" : "ELYRIA", "loc" : [ -82.10508799999999, 41.372353 ], "pop" : 66674, "state" : "OH" } +{ "_id" : "44060", "city" : "MENTOR", "loc" : [ -81.342133, 41.689468 ], "pop" : 60109, "state" : "OH" } +{ "_id" : "44107", "city" : "EDGEWATER", "loc" : [ -81.79714300000001, 41.482654 ], "pop" : 59702, "state" : "OH" } +{ "_id" : "46360", "city" : "MICHIGAN CITY", "loc" : [ -86.869899, 41.698031 ], "pop" : 55392, "state" : "IN" } +{ "_id" : "47130", "city" : "JEFFERSONVILLE", "loc" : [ -85.735885, 38.307767 ], "pop" : 56543, "state" : "IN" } +{ "_id" : "47906", "city" : "WEST LAFAYETTE", "loc" : [ -86.923661, 40.444025 ], "pop" : 54702, "state" : "IN" } +{ "_id" : "48180", "city" : "TAYLOR", "loc" : [ -83.267269, 42.231738 ], "pop" : 70811, "state" : "MI" } +{ "_id" : "48185", "city" : "WESTLAND", "loc" : [ -83.374908, 42.318882 ], "pop" : 84712, "state" : "MI" } +{ "_id" : "48227", "city" : "DETROIT", "loc" : [ -83.193732, 42.388303 ], "pop" : 68390, "state" : "MI" } +{ "_id" : "50010", "city" : "AMES", "loc" : [ -93.639398, 42.029859 ], "pop" : 52105, "state" : "IA" } +{ "_id" : "50317", "city" : "PLEASANT HILL", "loc" : [ -93.549446, 41.612499 ], "pop" : 39883, "state" : "IA" } +{ "_id" : "52001", "city" : "DUBUQUE", "loc" : [ -90.68191400000001, 42.514977 ], "pop" : 41934, "state" : "IA" } +{ "_id" : "53209", "city" : "MILWAUKEE", "loc" : [ -87.947834, 43.118765 ], "pop" : 51008, "state" : "WI" } +{ "_id" : "54401", "city" : "WAUSAU", "loc" : [ -89.633955, 44.963433 ], "pop" : 51083, "state" : "WI" } +{ "_id" : "54901", "city" : "OSHKOSH", "loc" : [ -88.54363499999999, 44.021962 ], "pop" : 57187, "state" : "WI" } +{ "_id" : "55106", "city" : "SAINT PAUL", "loc" : [ -93.048817, 44.968384 ], "pop" : 47905, "state" : "MN" } +{ "_id" : "55112", "city" : "NEW BRIGHTON", "loc" : [ -93.199691, 45.074129 ], "pop" : 44128, "state" : "MN" } +{ "_id" : "55337", "city" : "BURNSVILLE", "loc" : [ -93.275283, 44.76086 ], "pop" : 51421, "state" : "MN" } +{ "_id" : "57103", "city" : "SIOUX FALLS", "loc" : [ -96.686415, 43.537386 ], "pop" : 32508, "state" : "SD" } +{ "_id" : "57401", "city" : "ABERDEEN", "loc" : [ -98.485642, 45.466109 ], "pop" : 28786, "state" : "SD" } +{ "_id" : "57701", "city" : "ROCKERVILLE", "loc" : [ -103.200259, 44.077041 ], "pop" : 45328, "state" : "SD" } +{ "_id" : "58103", "city" : "FARGO", "loc" : [ -96.812252, 46.856406 ], "pop" : 38483, "state" : "ND" } +{ "_id" : "58501", "city" : "BISMARCK", "loc" : [ -100.774755, 46.823448 ], "pop" : 36602, "state" : "ND" } +{ "_id" : "58701", "city" : "MINOT", "loc" : [ -101.298476, 48.22914 ], "pop" : 42195, "state" : "ND" } +{ "_id" : "59102", "city" : "BILLINGS", "loc" : [ -108.572662, 45.781265 ], "pop" : 40121, "state" : "MT" } +{ "_id" : "59601", "city" : "HELENA", "loc" : [ -112.021283, 46.613066 ], "pop" : 40102, "state" : "MT" } +{ "_id" : "59801", "city" : "MISSOULA", "loc" : [ -114.025207, 46.856274 ], "pop" : 33811, "state" : "MT" } +{ "_id" : "60623", "city" : "CHICAGO", "loc" : [ -87.7157, 41.849015 ], "pop" : 112047, "state" : "IL" } +{ "_id" : "60634", "city" : "NORRIDGE", "loc" : [ -87.796054, 41.945213 ], "pop" : 69160, "state" : "IL" } +{ "_id" : "60650", "city" : "CICERO", "loc" : [ -87.76008, 41.84776 ], "pop" : 67670, "state" : "IL" } +{ "_id" : "63031", "city" : "FLORISSANT", "loc" : [ -90.340097, 38.806865 ], "pop" : 52659, "state" : "MO" } +{ "_id" : "63116", "city" : "SAINT LOUIS", "loc" : [ -90.26254299999999, 38.581356 ], "pop" : 49014, "state" : "MO" } +{ "_id" : "63136", "city" : "JENNINGS", "loc" : [ -90.260189, 38.738878 ], "pop" : 54994, "state" : "MO" } +{ "_id" : "66502", "city" : "MANHATTAN", "loc" : [ -96.585776, 39.193757 ], "pop" : 50178, "state" : "KS" } +{ "_id" : "67212", "city" : "WICHITA", "loc" : [ -97.438344, 37.700683 ], "pop" : 41349, "state" : "KS" } +{ "_id" : "67401", "city" : "BAVARIA", "loc" : [ -97.60878700000001, 38.823802 ], "pop" : 45208, "state" : "KS" } +{ "_id" : "68104", "city" : "OMAHA", "loc" : [ -95.999888, 41.29186 ], "pop" : 35325, "state" : "NE" } +{ "_id" : "68502", "city" : "LINCOLN", "loc" : [ -96.693763, 40.789282 ], "pop" : 27576, "state" : "NE" } +{ "_id" : "68847", "city" : "KEARNEY", "loc" : [ -99.077883, 40.713608 ], "pop" : 28674, "state" : "NE" } +{ "_id" : "70072", "city" : "MARRERO", "loc" : [ -90.110462, 29.859756 ], "pop" : 58905, "state" : "LA" } +{ "_id" : "70117", "city" : "NEW ORLEANS", "loc" : [ -90.03124, 29.970298 ], "pop" : 56494, "state" : "LA" } +{ "_id" : "70560", "city" : "NEW IBERIA", "loc" : [ -91.819959, 30.001027 ], "pop" : 56105, "state" : "LA" } +{ "_id" : "72032", "city" : "CONWAY", "loc" : [ -92.423574, 35.084199 ], "pop" : 43236, "state" : "AR" } +{ "_id" : "72076", "city" : "GRAVEL RIDGE", "loc" : [ -92.13043500000001, 34.881985 ], "pop" : 37428, "state" : "AR" } +{ "_id" : "72401", "city" : "JONESBORO", "loc" : [ -90.69652600000001, 35.833016 ], "pop" : 53532, "state" : "AR" } +{ "_id" : "73034", "city" : "EDMOND", "loc" : [ -97.47983499999999, 35.666483 ], "pop" : 43814, "state" : "OK" } +{ "_id" : "73505", "city" : "LAWTON", "loc" : [ -98.455234, 34.617939 ], "pop" : 45542, "state" : "OK" } +{ "_id" : "74801", "city" : "SHAWNEE", "loc" : [ -96.931321, 35.34907 ], "pop" : 40076, "state" : "OK" } +{ "_id" : "78207", "city" : "SAN ANTONIO", "loc" : [ -98.52596699999999, 29.422855 ], "pop" : 58355, "state" : "TX" } +{ "_id" : "78521", "city" : "BROWNSVILLE", "loc" : [ -97.461236, 25.922103 ], "pop" : 79463, "state" : "TX" } +{ "_id" : "78572", "city" : "ALTON", "loc" : [ -98.342647, 26.24153 ], "pop" : 67604, "state" : "TX" } +{ "_id" : "80123", "city" : "BOW MAR", "loc" : [ -105.07766, 39.596854 ], "pop" : 59418, "state" : "CO" } +{ "_id" : "80221", "city" : "FEDERAL HEIGHTS", "loc" : [ -105.007985, 39.840562 ], "pop" : 54069, "state" : "CO" } +{ "_id" : "80631", "city" : "GARDEN CITY", "loc" : [ -104.704756, 40.413968 ], "pop" : 53905, "state" : "CO" } +{ "_id" : "82001", "city" : "CHEYENNE", "loc" : [ -104.796234, 41.143719 ], "pop" : 33107, "state" : "WY" } +{ "_id" : "82070", "city" : "LARAMIE", "loc" : [ -105.581146, 41.312907 ], "pop" : 29327, "state" : "WY" } +{ "_id" : "82716", "city" : "GILLETTE", "loc" : [ -105.497442, 44.282009 ], "pop" : 25968, "state" : "WY" } +{ "_id" : "83301", "city" : "TWIN FALLS", "loc" : [ -114.469265, 42.556495 ], "pop" : 34539, "state" : "ID" } +{ "_id" : "83704", "city" : "BOISE", "loc" : [ -116.295099, 43.633001 ], "pop" : 40912, "state" : "ID" } +{ "_id" : "83814", "city" : "COEUR D ALENE", "loc" : [ -116.784976, 47.692841 ], "pop" : 33589, "state" : "ID" } +{ "_id" : "84118", "city" : "KEARNS", "loc" : [ -111.98521, 40.652759 ], "pop" : 55999, "state" : "UT" } +{ "_id" : "84120", "city" : "WEST VALLEY CITY", "loc" : [ -112.009783, 40.68708 ], "pop" : 52854, "state" : "UT" } +{ "_id" : "84604", "city" : "PROVO", "loc" : [ -111.654906, 40.260681 ], "pop" : 43841, "state" : "UT" } +{ "_id" : "85023", "city" : "PHOENIX", "loc" : [ -112.111838, 33.632383 ], "pop" : 54668, "state" : "AZ" } +{ "_id" : "85204", "city" : "MESA", "loc" : [ -111.789554, 33.399168 ], "pop" : 55180, "state" : "AZ" } +{ "_id" : "85364", "city" : "YUMA", "loc" : [ -114.642362, 32.701507 ], "pop" : 57131, "state" : "AZ" } +{ "_id" : "87501", "city" : "POJOAQUE VALLEY", "loc" : [ -105.974818, 35.702472 ], "pop" : 51715, "state" : "NM" } +{ "_id" : "88001", "city" : "LAS CRUCES", "loc" : [ -106.746034, 32.321641 ], "pop" : 57502, "state" : "NM" } +{ "_id" : "88201", "city" : "ROSWELL", "loc" : [ -104.525857, 33.388504 ], "pop" : 53644, "state" : "NM" } +{ "_id" : "89031", "city" : "NORTH LAS VEGAS", "loc" : [ -115.124832, 36.206228 ], "pop" : 48113, "state" : "NV" } +{ "_id" : "89115", "city" : "LAS VEGAS", "loc" : [ -115.067062, 36.215818 ], "pop" : 51532, "state" : "NV" } +{ "_id" : "89502", "city" : "RENO", "loc" : [ -119.776395, 39.497239 ], "pop" : 38332, "state" : "NV" } +{ "_id" : "90011", "city" : "LOS ANGELES", "loc" : [ -118.258189, 34.007856 ], "pop" : 96074, "state" : "CA" } +{ "_id" : "90201", "city" : "BELL GARDENS", "loc" : [ -118.17205, 33.969177 ], "pop" : 99568, "state" : "CA" } +{ "_id" : "90650", "city" : "NORWALK", "loc" : [ -118.081767, 33.90564 ], "pop" : 94188, "state" : "CA" } +{ "_id" : "96734", "city" : "KAILUA", "loc" : [ -157.744781, 21.406262 ], "pop" : 53403, "state" : "HI" } +{ "_id" : "96744", "city" : "KANEOHE", "loc" : [ -157.811543, 21.422819 ], "pop" : 55236, "state" : "HI" } +{ "_id" : "96818", "city" : "HONOLULU", "loc" : [ -157.926925, 21.353173 ], "pop" : 62915, "state" : "HI" } +{ "_id" : "97005", "city" : "BEAVERTON", "loc" : [ -122.805395, 45.475035 ], "pop" : 46660, "state" : "OR" } +{ "_id" : "97206", "city" : "PORTLAND", "loc" : [ -122.59727, 45.483995 ], "pop" : 43134, "state" : "OR" } +{ "_id" : "97301", "city" : "SALEM", "loc" : [ -122.979692, 44.926039 ], "pop" : 48007, "state" : "OR" } +{ "_id" : "98031", "city" : "KENT", "loc" : [ -122.193184, 47.388004 ], "pop" : 50515, "state" : "WA" } +{ "_id" : "98059", "city" : "RENTON", "loc" : [ -122.151178, 47.467383 ], "pop" : 48197, "state" : "WA" } +{ "_id" : "98310", "city" : "BREMERTON", "loc" : [ -122.629913, 47.601916 ], "pop" : 49057, "state" : "WA" } +{ "_id" : "99504", "city" : "ANCHORAGE", "loc" : [ -149.74467, 61.203696 ], "pop" : 32383, "state" : "AK" } +{ "_id" : "99709", "city" : "FAIRBANKS", "loc" : [ -147.846917, 64.85437 ], "pop" : 23238, "state" : "AK" } +{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" }
