package org.smoothbuild.db.values; import static org.smoothbuild.lang.type.Types.arrayElementJTypes; import static org.smoothbuild.lang.type.Types.arrayTypeContaining; import static org.smoothbuild.lang.type.Types.jTypeToType; import static org.smoothbuild.lang.value.SFile.storeFileInDb; import static org.smoothbuild.lang.value.SString.storeStringInDb; import java.util.function.Function; import javax.inject.Inject; import org.smoothbuild.db.hashed.HashedDb; import org.smoothbuild.io.fs.base.Path; import org.smoothbuild.io.fs.mem.MemoryFileSystem; import org.smoothbuild.io.util.TempManager; import org.smoothbuild.lang.type.ArrayType; import org.smoothbuild.lang.type.Type; import org.smoothbuild.lang.type.Types; import org.smoothbuild.lang.value.Array; import org.smoothbuild.lang.value.ArrayBuilder; import org.smoothbuild.lang.value.Blob; import org.smoothbuild.lang.value.BlobBuilder; import org.smoothbuild.lang.value.SFile; import org.smoothbuild.lang.value.SString; import org.smoothbuild.lang.value.Value; import org.smoothbuild.lang.value.ValueFactory; import com.google.common.hash.HashCode; import com.google.inject.TypeLiteral; public class ValuesDb implements ValueFactory { private final HashedDb hashedDb; @Inject public ValuesDb(@Values HashedDb hashedDb) { this.hashedDb = hashedDb; } public static ValuesDb memoryValuesDb() { MemoryFileSystem fileSystem = new MemoryFileSystem(); return new ValuesDb(new HashedDb(fileSystem, Path.root(), new TempManager(fileSystem))); } public <T extends Value> ArrayBuilder<T> arrayBuilder(Class<T> elementClass) { if (!(arrayElementJTypes().contains(TypeLiteral.get(elementClass)))) { throw new IllegalArgumentException("Illegal type " + elementClass.getCanonicalName()); } Type type = jTypeToType(TypeLiteral.get(elementClass)); return createArrayBuilder(arrayTypeContaining(type), elementClass); } private <T extends Value> ArrayBuilder<T> createArrayBuilder(ArrayType type, Class<?> elementClass) { return new ArrayBuilder<T>(type, (Function<HashCode, T>) valueConstructor(type.elemType()), hashedDb); } public SFile file(SString path, Blob content) { return storeFileInDb(path, content, hashedDb); } public BlobBuilder blobBuilder() { return new BlobBuilder(hashedDb); } public SString string(String string) { return storeStringInDb(string, hashedDb); } public Value read(Type type, HashCode hash) { return valueConstructor(type).apply(hash); } private Function<HashCode, ? extends Value> valueConstructor(Type type) { if (type == Types.STRING) { return (hash) -> new SString(hash, hashedDb); } if (type == Types.BLOB) { return (hash) -> new Blob(hash, hashedDb); } if (type == Types.FILE) { return (hash) -> new SFile(hash, hashedDb); } if (type == Types.NOTHING) { return (hash) -> { throw new UnsupportedOperationException("Nothing cannot be constructed."); }; } if (type instanceof ArrayType) { ArrayType arrayType = (ArrayType) type; return (hash) -> arrayMarshaller(arrayType, valueConstructor(arrayType.elemType()), hash); } throw new RuntimeException("Unexpected type: " + type); } private <T extends Value> Array<T> arrayMarshaller(ArrayType type, Function<HashCode, T> valueConstructor, HashCode hash) { return new Array<T>(hash, type, valueConstructor, hashedDb); } }