Skip to content

Commit

Permalink
WIP: add record storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Marshall Hampson committed Nov 15, 2018
1 parent 1dbd084 commit 88cb239
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 25 deletions.
25 changes: 12 additions & 13 deletions src/com/mrhampson/database/ColumnDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,26 @@
*/
public class ColumnDefinition {
static final int MAX_NAME_LENGTH = 256;
// Number of bytes in a column def on disk name + fieldLength + dataType
// Number of bytes in a column def on disk name + fieldLength + storageType
static final int NUM_BYTES = 256 + 4 + 1;

private final DataType dataType;
private final StorageDataType storageType;
private final int fieldLength;
private final String columnName;

public ColumnDefinition(DataType dataType, int fieldLength, String columnName) {
Objects.requireNonNull(dataType);
public ColumnDefinition(StorageDataType storageType, int fieldLength, String columnName) {
Objects.requireNonNull(storageType);
Objects.requireNonNull(columnName);
if (columnName.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException("Name too long");
}

this.dataType = dataType;
this.storageType = storageType;
this.fieldLength = fieldLength;
this.columnName = columnName;
}

public DataType getDataType() {
return dataType;
public StorageDataType getStorageType() {
return storageType;
}

public int getFieldLength() {
Expand All @@ -55,7 +54,7 @@ public String getColumnName() {
public byte[] toBytes() {
ByteBuffer output = ByteBuffer.allocate(NUM_BYTES);
// Data type
int dataTypeOrdinal = dataType.ordinal();
int dataTypeOrdinal = storageType.ordinal();
if (dataTypeOrdinal > 256) {
throw new IllegalStateException("Data type is too large. Too many data types defined");
}
Expand All @@ -75,7 +74,7 @@ public static ColumnDefinition fromBytes(ByteBuffer bytes) {
}
bytes.rewind();
int dataTypeOrdinal = bytes.get();
DataType dataType = DataType.fromOrdinal(dataTypeOrdinal);
StorageDataType dataType = StorageDataType.fromOrdinal(dataTypeOrdinal);
int fieldLength = bytes.getInt();
String columnName = ByteBufferUtils.fromASCIIBytes(bytes);
return new ColumnDefinition(dataType, fieldLength, columnName.trim());
Expand All @@ -87,12 +86,12 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
ColumnDefinition that = (ColumnDefinition) o;
return fieldLength == that.fieldLength &&
dataType == that.dataType &&
storageType == that.storageType &&
Objects.equals(columnName, that.columnName);
}

@Override
public int hashCode() {
return Objects.hash(dataType, fieldLength, columnName);
return Objects.hash(storageType, fieldLength, columnName);
}
}
4 changes: 2 additions & 2 deletions src/com/mrhampson/database/ColumnValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@
*/
public interface ColumnValue<T> {
ColumnDefinition getColumnDefinition();
void setValue(T value);
void setValue(Object value);
T getValue();
byte[] toBytes();

@SuppressWarnings("unchecked")
static <T> ColumnValue<T> fromColumnDefinition(ColumnDefinition definition) {
Objects.requireNonNull(definition);
switch (definition.getDataType()) {
switch (definition.getStorageType()) {
case VARCHAR:
return (ColumnValue<T>)new VarCharColumnValue(definition);
}
Expand Down
77 changes: 77 additions & 0 deletions src/com/mrhampson/database/Record.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Record.java
* Created on Nov 15, 2018, 11:41 AM
*
* Copyright 2008-2018 LiveAction, Incorporated. All Rights Reserved.
* 3500 W Bayshore Road, Palo Alto, California 94303, U.S.A.
*
* This software is the confidential and proprietary information
* of LiveAction ("Confidential Information").
* You shall not disclose such Confidential Information and shall use
* it only in accordance with the terms of the license agreement
* you entered into with LiveAction.
*/
package com.mrhampson.database;

import java.nio.ByteBuffer;
import java.util.*;

/**
* @author Marshall Hampson
*/
public class Record {
private final int recordBytes;
private final Map<String, ColumnValue<?>> columnValues;

private Record(Builder builder) {
this.recordBytes = builder.recordBytes;
this.columnValues = Collections.unmodifiableMap(builder.values);
}

public Map<String, ColumnValue<?>> getColumnValues() {
return this.columnValues;
}

public int getRecordBytes() {
return recordBytes;
}

public byte[] toBytes() {
ByteBuffer buffer = ByteBuffer.allocate(recordBytes);
for (ColumnValue<?> value : columnValues.values()) {
buffer.put(value.toBytes());
}
return buffer.array();
}

public static final class Builder {
private final int recordBytes;
private final TableDefinition tableDefinition;
private final Map<String, ColumnValue<?>> values;

public Builder(TableDefinition tableDefinition) {
Objects.requireNonNull(tableDefinition);
this.tableDefinition = tableDefinition;
this.values = new LinkedHashMap<>();
int byteCounter = 0;
for (ColumnDefinition columnDefinition : this.tableDefinition.getColumns()) {
byteCounter += columnDefinition.getFieldLength();
this.values.put(columnDefinition.getColumnName(), ColumnValue.fromColumnDefinition(columnDefinition));
}
this.recordBytes = byteCounter;
}

public void setColumnValue(String columnName, Object value) {
Objects.requireNonNull(columnName);
ColumnValue<?> columnValue = this.values.get(columnName);
if (columnValue == null) {
throw new IllegalArgumentException("Column not defined");
}
columnValue.setValue(value);
}

public Record build() {
return new Record(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* DataType.java
* StorageDataType.java
* Created on Nov 10, 2018, 6:31 PM
*
* Copyright 2008-2018 LiveAction, Incorporated. All Rights Reserved.
Expand All @@ -13,25 +13,38 @@
*/
package com.mrhampson.database;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
*
* NOTE: Cannot define more than 256 datatypes
* @author Marshall Hampson
*/
public enum DataType {
public enum StorageDataType {
INTEGER,
VARCHAR;

private static final DataType[] VALUES;
private static final StorageDataType[] VALUES;
private static final Map<StorageDataType, Class<?>> STORAGE_TO_JAVA_TYPE;

static {
VALUES = DataType.values();
VALUES = StorageDataType.values();
Map<StorageDataType, Class<?>> storageToJavaType = new HashMap<>();
storageToJavaType.put(INTEGER, Integer.class);
storageToJavaType.put(VARCHAR, String.class);
STORAGE_TO_JAVA_TYPE = Collections.unmodifiableMap(storageToJavaType);
}

public static DataType fromOrdinal(int ordinal) {
public static StorageDataType fromOrdinal(int ordinal) {
if (ordinal < 0 || ordinal >= VALUES.length) {
throw new IllegalArgumentException("Ordinal out of bounds");
}
return VALUES[ordinal];
}

public Class<?> getJavaType() {
return STORAGE_TO_JAVA_TYPE.get(this);
}
}
5 changes: 5 additions & 0 deletions src/com/mrhampson/database/TableStorageManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.READ;
Expand All @@ -43,6 +44,10 @@ public void create(TableDefinition tableDefinition) throws IOException {
writeHeader(tableDefinition);
}

public void storeRecord(Record record) throws IOException {
fileChannel.write(ByteBuffer.wrap(record.toBytes()));
}

public void load() throws IOException {
fileChannel = FileChannel.open(tableFilePath, READ, WRITE);
TableDefinition tableDefinition = readHeader();
Expand Down
4 changes: 2 additions & 2 deletions src/com/mrhampson/database/TestMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
*/
public class TestMain {
public static void main(String[] args) {
ColumnDefinition nameColumn = new ColumnDefinition(DataType.VARCHAR, 100, "NAME");
ColumnDefinition ageColumn = new ColumnDefinition(DataType.VARCHAR, 100, "CITY");
ColumnDefinition nameColumn = new ColumnDefinition(StorageDataType.VARCHAR, 100, "NAME");
ColumnDefinition ageColumn = new ColumnDefinition(StorageDataType.VARCHAR, 100, "CITY");

TableDefinition tableDefinition = new TableDefinition(
"PEOPLE",
Expand Down
11 changes: 8 additions & 3 deletions src/com/mrhampson/database/VarCharColumnValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @author Marshall Hampson
*/
public class VarCharColumnValue implements ColumnValue<String> {
private static final Class<String> CLASS = String.class;
private final ColumnDefinition columnDefinition;
private String value = null;

Expand All @@ -34,11 +35,15 @@ public ColumnDefinition getColumnDefinition() {
}

@Override
public void setValue(String value) {
if (value != null && value.length() > columnDefinition.getFieldLength()) {
public void setValue(Object value) {
if (value != null && !CLASS.equals(value.getClass())) {
throw new IllegalArgumentException("Wrong type for column");
}
String stringValue = (String)value;
if (stringValue != null && stringValue.length() > columnDefinition.getFieldLength()) {
throw new IllegalArgumentException("Length out of range");
}
this.value = value;
this.value = stringValue;
}

@Override
Expand Down

0 comments on commit 88cb239

Please sign in to comment.