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 }