From 50638ac872d07c0e1002b8232f7597b939b29454 Mon Sep 17 00:00:00 2001 From: Paolo Guagliardo <paolo.guagliardo@ed.ac.uk> Date: Wed, 9 Sep 2020 12:11:59 +0100 Subject: [PATCH] Handle BaseTable in schemas --- .../uk/ac/ed/pguaglia/real/db/Schema.java | 58 ++++--------------- .../ac/ed/pguaglia/real/db/SchemaMapper.java | 46 +++++++++------ .../ed/pguaglia/real/db/engine/BaseTable.java | 26 ++++++++- .../pguaglia/real/runtime/CommandLineApp.java | 9 ++- 4 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/main/java/uk/ac/ed/pguaglia/real/db/Schema.java b/src/main/java/uk/ac/ed/pguaglia/real/db/Schema.java index 5238ec9..0541087 100644 --- a/src/main/java/uk/ac/ed/pguaglia/real/db/Schema.java +++ b/src/main/java/uk/ac/ed/pguaglia/real/db/Schema.java @@ -9,18 +9,16 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.SetUtils; - import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; +import uk.ac.ed.pguaglia.real.db.engine.BaseTable; +import uk.ac.ed.pguaglia.real.db.engine.DataValue.DataType; import uk.ac.ed.pguaglia.real.lang.Expression; public class Schema { - private Map<String,List<String>> tables; - private Map<String,File> datafiles; + private Map<String,BaseTable> tables; private Map<String,Expression> views; private Map<String,Set<String>> isUsedBy; @@ -28,46 +26,14 @@ public class Schema { tables = new HashMap<>(); views = new HashMap<>(); isUsedBy = new HashMap<>(); - datafiles = new HashMap<>(); } public static Schema fromJSON(File src) throws JsonParseException, JsonMappingException, IOException { return SchemaMapper.getInstance().readValue(src, Schema.class); } - protected Schema(Map<String, List<String>> tables, Map<String, File> datafiles, Map<String, Expression> views) - throws IllegalArgumentException { - Set<String> tableNames = tables.keySet(); - Set<String> viewNames = views.keySet(); - if (SetUtils.isEqualSet(tableNames, datafiles.keySet()) == false) { - throw new IllegalArgumentException(); - } - if (CollectionUtils.containsAny(tableNames, viewNames)) { - throw new IllegalArgumentException(); - } - Set<String> baseNames = SetUtils.union(tableNames, viewNames); - - this.tables = new HashMap<>(tables); - this.datafiles = new HashMap<>(datafiles); - this.views = new HashMap<>(); - this.isUsedBy = new HashMap<>(); - - for (String name : views.keySet()) { - Expression expr = views.get(name); - if (baseNames.containsAll(expr.getBaseNames()) == false) { - throw new IllegalArgumentException(); - } - this.views.put(name, expr); - updateDeps(name, expr); - } - } - public File getTableDatafile(String name) throws IOException { - if (datafiles.containsKey(name) == false) { - String msg = String.format("ERROR: \"%s\" (No such table)", name); - throw new IOException(msg); - } - return datafiles.get(name); + return tables.get(name).datafile().toFile(); } public boolean hasTable(String name) { @@ -79,19 +45,18 @@ public class Schema { } public List<String> getTableAttributes(String name) { - return tables.get(name); + return tables.get(name).attributes(); } public Expression getViewDefinition(String name) { return views.get(name); } - public void addTable(String name, List<String> attributes, File data) throws Exception { + public void addTable(String name, BaseTable table) throws Exception { if (tables.containsKey(name)) { throw new Exception(String.format("ERROR: Table %s already exists", name)); } - tables.put(name, attributes); - datafiles.put(name, data.getAbsoluteFile()); + tables.put(name, table); } public void dropTable(String name) throws Exception { @@ -101,11 +66,6 @@ public class Schema { throw new Exception(msg); } tables.remove(name); - datafiles.remove(name); - } - - public List<String> addTable(String name, List<String> attributes) { - return tables.put(name, attributes); } public Expression addView(String name, Expression def) throws SchemaException { @@ -160,6 +120,10 @@ public class Schema { return tables.keySet(); } + public DataType getDataType(String tbl, String attr) { + return tables.get(tbl).getDataType(attr); + } + public Set<String> getTableNames(Expression expr) throws SchemaException { Set<String> base = new HashSet<>(); for (String name : expr.getBaseNames()) { diff --git a/src/main/java/uk/ac/ed/pguaglia/real/db/SchemaMapper.java b/src/main/java/uk/ac/ed/pguaglia/real/db/SchemaMapper.java index 351ad9a..483a256 100644 --- a/src/main/java/uk/ac/ed/pguaglia/real/db/SchemaMapper.java +++ b/src/main/java/uk/ac/ed/pguaglia/real/db/SchemaMapper.java @@ -2,11 +2,10 @@ package uk.ac.ed.pguaglia.real.db; import java.io.File; import java.io.IOException; +import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import org.antlr.v4.runtime.RecognitionException; @@ -22,6 +21,8 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import uk.ac.ed.pguaglia.real.db.engine.BaseTable; +import uk.ac.ed.pguaglia.real.db.engine.DataValue.DataType; import uk.ac.ed.pguaglia.real.lang.Expression; import uk.ac.ed.pguaglia.real.lang.ReplacementException; @@ -54,7 +55,7 @@ public final class SchemaMapper extends ObjectMapper { gen.writeObjectFieldStart(TABLE_ATTRIBUTES); // start attributes for (String attrName : sch.getTableAttributes(tableName)) { gen.writeObjectFieldStart(attrName); - gen.writeObjectField(ATTRIBUTE_TYPE,"STRING"); + gen.writeObjectField(ATTRIBUTE_TYPE, sch.getDataType(tableName, attrName)); gen.writeEndObject(); } gen.writeEndObject(); // end attributes @@ -84,40 +85,51 @@ public final class SchemaMapper extends ObjectMapper { @Override public Schema deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonNode node = jp.getCodec().readTree(jp); + Schema sch = new Schema(); JsonNode tables = node.get(TABLES); Iterator<String> tableNames = tables.fieldNames(); - Map<String,List<String>> tableMap = new HashMap<>(); - Map<String,File> dataMap = new HashMap<>(); while (tableNames.hasNext()) { String name = tableNames.next(); JsonNode tbl = tables.get(name); List<String> attributes = new ArrayList<>(); + List<DataType> types = new ArrayList<>(); Iterator<String> attrNames = tbl.get(TABLE_ATTRIBUTES).fieldNames(); while (attrNames.hasNext()) { - attributes.add(attrNames.next()); + String attr = attrNames.next(); + String type = tbl.get(TABLE_ATTRIBUTES).get(attr).get(ATTRIBUTE_TYPE).textValue(); + switch (type) { + case "TEXT": + types.add(DataType.TEXT); + break; + case "NUMBER": + types.add(DataType.NUMBER); + break; + default: + throw new IllegalStateException(); + } + attributes.add(attr); + } + Path p = new File(tbl.get(TABLE_DATAFILE).textValue()).toPath(); + BaseTable bt = new BaseTable(p, attributes.toArray(new String[0]), types.toArray(new DataType[0])); + try { + sch.addTable(name, bt); + } catch (Exception e) { + throw new JsonProcessingException(e) {}; } - tableMap.put(name, attributes); - dataMap.put(name, new File(tbl.get(TABLE_DATAFILE).textValue())); } JsonNode views = node.get(VIEWS); Iterator<String> viewNames = views.fieldNames(); - Map<String,Expression> viewsMap = new HashMap<>(); while (viewNames.hasNext()) { String name = viewNames.next(); try { - viewsMap.put(name, Expression.parse(views.get(name).textValue())); - } catch (RecognitionException | ReplacementException e) { + sch.addView(name, Expression.parse(views.get(name).textValue())); + } catch (RecognitionException | ReplacementException | SchemaException e) { throw new JsonProcessingException(e) {}; } } - - try { - return new Schema(tableMap, dataMap, viewsMap); - } catch (IllegalArgumentException e) { - throw new JsonProcessingException(e) {}; - } + return sch; } } diff --git a/src/main/java/uk/ac/ed/pguaglia/real/db/engine/BaseTable.java b/src/main/java/uk/ac/ed/pguaglia/real/db/engine/BaseTable.java index b5fbcb4..93dcb17 100644 --- a/src/main/java/uk/ac/ed/pguaglia/real/db/engine/BaseTable.java +++ b/src/main/java/uk/ac/ed/pguaglia/real/db/engine/BaseTable.java @@ -3,17 +3,20 @@ package uk.ac.ed.pguaglia.real.db.engine; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; import java.util.stream.Stream; import uk.ac.ed.pguaglia.real.db.engine.DataValue.DataType; public class BaseTable { - private String[] attributes; // in fetch order - private DataType[] types; // in fetch order - private Path datafile; + private final String[] attributes; // in fetch order + private final DataType[] types; // in fetch order + private final Path datafile; public BaseTable(Path data, String[] attributes, DataType[] types) { + // TODO: check sizes match this.datafile = data; this.types = types; this.attributes = attributes; @@ -22,4 +25,21 @@ public class BaseTable { public Stream<Record> fetch() throws IOException { return Files.lines(datafile).map(s -> Record.of(s.split(","), types)); } + + public List<String> attributes() { + return Arrays.asList(attributes); + } + + public List<DataType> types() { + return Arrays.asList(types); + } + + public DataType getDataType(String attr) { + int pos = Arrays.asList(attributes).indexOf(attr); + return types[pos]; + } + + public Path datafile() { + return datafile; + } } diff --git a/src/main/java/uk/ac/ed/pguaglia/real/runtime/CommandLineApp.java b/src/main/java/uk/ac/ed/pguaglia/real/runtime/CommandLineApp.java index 422d35a..f492a70 100644 --- a/src/main/java/uk/ac/ed/pguaglia/real/runtime/CommandLineApp.java +++ b/src/main/java/uk/ac/ed/pguaglia/real/runtime/CommandLineApp.java @@ -3,6 +3,7 @@ package uk.ac.ed.pguaglia.real.runtime; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -15,6 +16,7 @@ import org.apache.commons.cli.MissingOptionException; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; +import org.apache.commons.lang3.ArrayUtils; import org.jline.reader.LineReader; import org.jline.reader.LineReaderBuilder; import org.jline.terminal.Terminal; @@ -27,6 +29,8 @@ import uk.ac.ed.pguaglia.real.db.Schema; import uk.ac.ed.pguaglia.real.db.SchemaException; import uk.ac.ed.pguaglia.real.db.SchemaMapper; import uk.ac.ed.pguaglia.real.db.Table; +import uk.ac.ed.pguaglia.real.db.engine.BaseTable; +import uk.ac.ed.pguaglia.real.db.engine.DataValue.DataType; import uk.ac.ed.pguaglia.real.lang.Expression; import uk.ac.ed.pguaglia.real.lang.ReplacementException; @@ -322,8 +326,11 @@ public final class CommandLineApp { for (String attr : spec.substring(start+1,end).split(",")) { attributes.add(attr.strip()); } + DataType[] dt = new DataType[attributes.size()]; // TODO: add support for types + Arrays.fill(dt, DataType.TEXT); + BaseTable bt = new BaseTable(new File(filename).toPath(), attributes.toArray(new String[0]), dt); try { - sch.addTable(tableName, attributes, new File(filename)); + sch.addTable(tableName, bt); } catch (Exception e) { System.err.println("ERROR: " + e.getMessage()); } -- GitLab