diff --git a/.gitignore b/.gitignore index 9742423..1a5f6b3 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ libpb-test-* *.obj *.lst liblibpb.a +dub.selections.json diff --git a/dub.json b/dub.json index 184af18..e55e8ef 100644 --- a/dub.json +++ b/dub.json @@ -3,9 +3,14 @@ "Tristan B. Velloza Kildaire" ], "copyright": "Copyright © 2022, Tristan B. Velloza Kildaire", + "dependencies": { + "jstruct": "0.1.2" + }, "description": "PocketBase wrapper with serializer/deserializer support", + "libs": [ + "curl" + ], "license": "LGPL v3.0", "name": "libpb", - "targetType" : "library", - "libs":["curl"] + "targetType": "library" } diff --git a/source/libpb/deserialization.d b/source/libpb/deserialization.d deleted file mode 100644 index 200df4f..0000000 --- a/source/libpb/deserialization.d +++ /dev/null @@ -1,205 +0,0 @@ -module libpb.deserialization; - -import std.json; -import libpb.exceptions : RemoteFieldMissing; - -import std.traits : FieldTypeTuple, FieldNameTuple; - -/** - * Deserializes the provided JSON into a struct of type RecordType - * - * Params: - * jsonIn = the JSON to deserialize - * Throws: - * RemoteFieldMissing = if the field names in the provided RecordType - * cannot be found within the prpvided JSONValue `jsonIn`. - * Returns: an instance of RecordType - */ -public RecordType fromJSON(RecordType)(JSONValue jsonIn) -{ - RecordType record; - - // Alias as to only expand later when used in compile-time - alias structTypes = FieldTypeTuple!(RecordType); - alias structNames = FieldNameTuple!(RecordType); - alias structValues = record.tupleof; - - static foreach(cnt; 0..structTypes.length) - { - debug(dbg) - { - pragma(msg, structTypes[cnt]); - pragma(msg, structNames[cnt]); - // pragma(msg, structValues[cnt]); - } - - debug(dbg) - { - pragma(msg, "Bruh type"); - pragma(msg, structTypes[cnt]); - // pragma(msg, __traits(identifier, mixin(structTypes[cnt]))); - } - - try - { - static if(__traits(isSame, mixin(structTypes[cnt]), byte)) - { - mixin("record."~structNames[cnt]) = cast(byte)jsonIn[structNames[cnt]].integer(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), ubyte)) - { - mixin("record."~structNames[cnt]) = cast(ubyte)jsonIn[structNames[cnt]].uinteger(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), short)) - { - mixin("record."~structNames[cnt]) = cast(short)jsonIn[structNames[cnt]].integer(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), ushort)) - { - mixin("record."~structNames[cnt]) = cast(ushort)jsonIn[structNames[cnt]].uinteger(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), int)) - { - mixin("record."~structNames[cnt]) = cast(int)jsonIn[structNames[cnt]].integer(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), uint)) - { - mixin("record."~structNames[cnt]) = cast(uint)jsonIn[structNames[cnt]].uinteger(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), ulong)) - { - mixin("record."~structNames[cnt]) = cast(ulong)jsonIn[structNames[cnt]].uinteger(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), long)) - { - mixin("record."~structNames[cnt]) = cast(long)jsonIn[structNames[cnt]].integer(); - } - else static if(__traits(isSame, mixin(structTypes[cnt]), string)) - { - mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].str(); - - debug(dbg) - { - pragma(msg,"record."~structNames[cnt]); - } - } - else static if(__traits(isSame, mixin(structTypes[cnt]), JSONValue)) - { - mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]]; - - debug(dbg) - { - pragma(msg,"record."~structNames[cnt]); - } - } - else static if(__traits(isSame, mixin(structTypes[cnt]), bool)) - { - mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].boolean(); - - debug(dbg) - { - pragma(msg,"record."~structNames[cnt]); - } - } - //FIXME: Not sure how to get array support going, very new to meta programming - else static if(__traits(isSame, mixin(structTypes[cnt]), mixin(structTypes[cnt])[])) - { - mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].boolean(); - - debug(dbg) - { - pragma(msg,"record."~structNames[cnt]); - } - } - else - { - // throw new - //TODO: Throw error - debug(dbg) - { - pragma(msg, "Unknown type for de-serialization"); - } - } - } - catch(JSONException e) - { - throw new RemoteFieldMissing(); - } - } - - return record; -} - -unittest -{ - import std.string : cmp; - import std.stdio : writeln; - - struct Person - { - public string firstname, lastname; - public int age; - public bool isMale; - public JSONValue obj; - public int[] list; - } - - JSONValue json = parseJSON(`{ -"firstname" : "Tristan", -"lastname": "Kildaire", -"age": 23, -"obj" : {"bruh":1}, -"isMale": true, -"list": [1,2,3] -} -`); - - Person person = fromJSON!(Person)(json); - - debug(dbg) - { - writeln(person); - } - - assert(cmp(person.firstname, "Tristan") == 0); - assert(cmp(person.lastname, "Kildaire") == 0); - assert(person.age == 23); - assert(person.isMale == true); - assert(person.obj["bruh"].integer() == 1); - //TODO: list test case -} - -unittest -{ - import std.string : cmp; - import std.stdio : writeln; - - struct Person - { - public string firstname, lastname; - public int age; - public bool isMale; - public JSONValue obj; - public int[] list; - } - - JSONValue json = parseJSON(`{ -"firstname" : "Tristan", -"lastname": "Kildaire", -"age": 23, -"obj" : {"bruh":1}, -"list": [1,2,3] -} -`); - - try - { - Person person = fromJSON!(Person)(json); - assert(false); - } - catch(RemoteFieldMissing) - { - assert(true); - } - -} \ No newline at end of file diff --git a/source/libpb/driver.d b/source/libpb/driver.d index e82ce4b..f470fb6 100644 --- a/source/libpb/driver.d +++ b/source/libpb/driver.d @@ -6,8 +6,7 @@ import std.net.curl; import std.conv : to; import std.string : cmp; import libpb.exceptions; -import libpb.serialization; -import libpb.deserialization; +import jstruct : fromJSON, SerializationError, serializeRecord; private mixin template AuthTokenHeader(alias http, PocketBase pbInstance) @@ -188,6 +187,10 @@ public class PocketBase { throw new PocketBaseParsingException(); } + catch(SerializationError e) + { + throw new RemoteFieldMissing(); + } } /** @@ -301,6 +304,10 @@ public class PocketBase { throw new PocketBaseParsingException(); } + catch(SerializationError e) + { + throw new RemoteFieldMissing(); + } } /** @@ -376,6 +383,10 @@ public class PocketBase { throw new PocketBaseParsingException(); } + catch(SerializationError e) + { + throw new RemoteFieldMissing(); + } } /** @@ -471,6 +482,10 @@ public class PocketBase { throw new PocketBaseParsingException(); } + catch(SerializationError e) + { + throw new RemoteFieldMissing(); + } } /** @@ -584,6 +599,10 @@ public class PocketBase { throw new PocketBaseParsingException(); } + catch(SerializationError e) + { + throw new RemoteFieldMissing(); + } } /** diff --git a/source/libpb/serialization.d b/source/libpb/serialization.d deleted file mode 100644 index 51ca543..0000000 --- a/source/libpb/serialization.d +++ /dev/null @@ -1,109 +0,0 @@ -module libpb.serialization; - -import std.json; -import std.conv : to; -import std.traits : FieldTypeTuple, FieldNameTuple; - -public JSONValue serializeRecord(RecordType)(RecordType record) -{ - // Final JSON to submit - JSONValue builtJSON; - - // Alias as to only expand later when used in compile-time - alias structTypes = FieldTypeTuple!(RecordType); - alias structNames = FieldNameTuple!(RecordType); - alias structValues = record.tupleof; - - static foreach(cnt; 0..structTypes.length) - { - debug(dbg) - { - pragma(msg, structTypes[cnt]); - pragma(msg, structNames[cnt]); - // pragma(msg, structValues[cnt]); - } - - - static if(__traits(isSame, mixin(structTypes[cnt]), int)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), uint)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), ulong)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), long)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), string)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), JSONValue)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else static if(__traits(isSame, mixin(structTypes[cnt]), bool)) - { - builtJSON[structNames[cnt]] = structValues[cnt]; - } - else - { - debug(dbg) - { - pragma(msg, "Yaa"); - } - builtJSON[structNames[cnt]] = to!(string)(structValues[cnt]); - } - } - - - return builtJSON; -} - -// Test serialization of a struct to JSON -private enum EnumType -{ - DOG, - CAT -} -unittest -{ - import std.algorithm.searching : canFind; - import std.string : cmp; - import std.stdio : writeln; - - struct Person - { - public string firstname, lastname; - public int age; - public string[] list; - public JSONValue extraJSON; - public EnumType eType; - } - - Person p1; - p1.firstname = "Tristan"; - p1.lastname = "Kildaire"; - p1.age = 23; - p1.list = ["1", "2", "3"]; - p1.extraJSON = parseJSON(`{"item":1, "items":[1,2,3]}`); - p1.eType = EnumType.CAT; - - JSONValue serialized = serializeRecord(p1); - - string[] keys = serialized.object().keys(); - assert(canFind(keys, "firstname") && cmp(serialized["firstname"].str(), "Tristan") == 0); - assert(canFind(keys, "lastname") && cmp(serialized["lastname"].str(), "Kildaire") == 0); - assert(canFind(keys, "age") && serialized["age"].integer() == 23); - - debug(dbg) - { - writeln(serialized.toPrettyString()); - } -}