1 module writer; 2 3 import sqlited; 4 import varint; 5 import utils; 6 import misc; 7 8 struct CowSlice { 9 const ubyte[] roData; 10 alias roData this; 11 } 12 13 14 15 struct PathEntry { 16 enum TransitionType { 17 LPageToLCell, // End 18 RPageToLPage, 19 RPageToIPage, 20 IPageToICell, 21 ICellToLPage, 22 } 23 TransitionType transitionType; 24 uint transitionDestination; 25 } 26 27 28 struct WritableDatabase { 29 uint currentPosition; 30 uint currentEffectivePosition; 31 static struct WriteOperation { 32 // ... OperationType bla bla bla bla ... 33 } 34 35 static struct WriteOperationEntry { 36 WriteOperation operation; 37 uint posOfNextWriteOperation; 38 } 39 WriteOperationEntry[] writeOperations; 40 41 void insertInto(T...)(string tableName, T values) { 42 43 } 44 45 static const(ubyte[]) headerBytes(T)(T value) pure { 46 return getTypeCode(value).byteArray; 47 } 48 49 static ubyte[] dataBytes(T)(T value) pure { 50 static if (__traits(isIntegral, (typeof(value)))) { 51 uint len = sizeInBytes(value); 52 return bigEndian(value).asArray[value.sizeof - len .. value.sizeof]; 53 } else static if (is(typeof(value) == ubyte[])) { 54 return value; 55 } else static if (is(typeof(value) == string)) { 56 return cast(ubyte[])value; 57 } else 58 static assert (0, "no dataBytes overload for: " ~ T.stringof); 59 } 60 61 // db.table("mytable").insertRow("value",12); 62 63 static ubyte[] rowBytes(T...)(T values) pure { 64 ubyte[] pageContent; 65 uint headerOffset; 66 67 foreach(v;values) { 68 pageContent ~= headerBytes(v); 69 } 70 71 headerOffset = cast(uint)pageContent.length; 72 73 foreach(v;values) { 74 pageContent ~= dataBytes(v); 75 } 76 77 return pageContent; 78 } 79 80 81 static assert(rowBytes("hello",12,"hello") == [ 82 cast(ubyte)23, 0x01, cast(ubyte)23, 83 cast(ubyte)'h', cast(ubyte)'e', cast(ubyte)'l', cast(ubyte)'l', cast(ubyte)'o', 84 cast(ubyte)12, 85 cast(ubyte)'h', cast(ubyte)'e', cast(ubyte)'l', cast(ubyte)'l', cast(ubyte)'o' 86 ]); 87 88 struct WriteableTable { 89 Table table; 90 WritableDatabase db; 91 alias table this; 92 93 this(Table table, WritableDatabase db) { 94 this.table = table; 95 this.db = db; 96 } 97 98 void serialize(struct_type)(struct_type s) { 99 uint ctr; 100 Database.Payload[] rowContent; 101 foreach (member; __traits(derivedMembers, struct_type)) { 102 alias type = typeof(__traits(getMember, s, member)); 103 static if (!is(type == function)) { 104 rowContent ~= Database.Payload(__traits(getMember, s, member)); 105 } 106 } 107 return instance; 108 } 109 110 } 111 112 Database db; 113 alias db this; 114 ubyte[] data; 115 116 this (const Database input) { 117 data = cast (ubyte[]) CowSlice(input.data[0 .. $]); 118 db = Database(data); 119 120 } 121 122 struct WriteablePageRange { 123 // PageStat currentPageStat; 124 Database.PageRange _pages; 125 alias _pages this; 126 } 127 128 WriteablePageRange pages; 129 130 131 this(string filename) { 132 this(Database(filename)); 133 } 134 135 WriteableTable table(string tableName) { 136 auto table = db.table(tableName); 137 return WriteableTable(db.table(tableName), this); 138 } 139 140 static VarInt getTypeCode(T)(T t) pure { 141 static if (is(T == typeof(null))) { 142 return VarInt(bigEndian!long(0)); 143 } else static if (is(T == ubyte[])) { 144 return VarInt(bigEndian!long(t.length*2 + 12)); 145 } else static if (is (T == string)) { 146 return VarInt(bigEndian!long(t.length*2 + 13)); 147 } else static if (__traits(isIntegral, T)) { 148 // The oblivous optimisation is to mask the sign first! 149 // and then just check the abs 150 // check if this makes things faster (it should!) 151 if (t >= -(1<<7) && t < (1<<7)) { 152 return VarInt(bigEndian!long(1)); 153 } else if (t >= -(1<<15) && t < (1<<15)) { 154 return VarInt(bigEndian!long(2)); 155 } else if (t >= -(1<<23) && t < (1<<23)) { 156 return VarInt(bigEndian!long(3)); 157 } else if (t >= -(1<<31) && t < (1<<31)) { 158 return VarInt(bigEndian!long(4)); 159 } else if (t >= -(1L<<47) && t < (1L<<47)) { 160 return VarInt(bigEndian!long(5)); 161 } else if (t >= -(1L<<63) && t < (1L<<63)) { 162 return VarInt(bigEndian!long(6)); 163 } else 164 assert(0); 165 } else static if (__traits(isFloatingPoint, T)) { 166 return VarInt(bigEndian!long(7)); 167 } else static if (is(T == bool)) { 168 return t ? VarInt(bigEndian!long(9)) : VarInt(bigEndian!long(8)); 169 } else static assert (0, "Payload has to be of numericType, string, ubyte[] or bool"); 170 } 171 172 static assert (getTypeCode("hello") == VarInt(bigEndian!long(23))); 173 static assert (getTypeCode(12) == VarInt(bigEndian!long(1))); 174 static assert (getTypeCode(127) == VarInt(bigEndian!long(1))); 175 static assert (getTypeCode(128) == VarInt(bigEndian!long(2))); 176 static assert (getTypeCode(cast(ubyte[])[]) == VarInt(bigEndian!long(12))); 177 }