commit
eb3c973947
|
@ -1,3 +1,6 @@
|
|||
[submodule "vendor/GCDWebServer"]
|
||||
path = vendor/GCDWebServer
|
||||
url = https://github.com/swisspol/GCDWebServer.git
|
||||
[submodule "vendor/PEGTL"]
|
||||
path = vendor/PEGTL
|
||||
url = https://github.com/ColinH/PEGTL.git
|
||||
|
|
|
@ -19,15 +19,15 @@
|
|||
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSList.cpp */; };
|
||||
0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC411B7CFC0D00010E03 /* RJSList.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC431B7CFC0D00010E03 /* RJSObject.mm */; };
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC431B7CFC0D00010E03 /* RJSObject.cpp */; };
|
||||
0270BC521B7CFC0D00010E03 /* RJSRealm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC531B7CFC0D00010E03 /* RJSRealm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC451B7CFC0D00010E03 /* RJSRealm.mm */; };
|
||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC461B7CFC0D00010E03 /* RJSResults.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC471B7CFC0D00010E03 /* RJSResults.mm */; };
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC471B7CFC0D00010E03 /* RJSResults.cpp */; };
|
||||
0270BC561B7CFC0D00010E03 /* RJSSchema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC491B7CFC0D00010E03 /* RJSSchema.mm */; };
|
||||
0270BC571B7CFC0D00010E03 /* RJSSchema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC491B7CFC0D00010E03 /* RJSSchema.cpp */; };
|
||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */; };
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC4B1B7CFC0D00010E03 /* RJSUtil.cpp */; };
|
||||
0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */; };
|
||||
0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC5E1B7CFC1C00010E03 /* object_schema.cpp */; };
|
||||
0270BC6A1B7CFC1C00010E03 /* object_schema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC5F1B7CFC1C00010E03 /* object_schema.hpp */; };
|
||||
|
@ -46,22 +46,30 @@
|
|||
0270BC861B7D020100010E03 /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* schemas.js */; };
|
||||
0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
||||
0270BCD11B7D067300010E03 /* RealmReact.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReact.mm */; };
|
||||
02786E331BF1065100937061 /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02786E311BF1065000937061 /* parser.cpp */; };
|
||||
02786E341BF1065100937061 /* parser.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02786E321BF1065000937061 /* parser.hpp */; };
|
||||
0291DBD21BD994F700E3852C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
029445931BDEDF40006D1617 /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029445911BDEDF40006D1617 /* transact_log_handler.cpp */; };
|
||||
029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445921BDEDF40006D1617 /* transact_log_handler.hpp */; };
|
||||
029445971BDEDF46006D1617 /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 029445951BDEDF46006D1617 /* external_commit_helper.cpp */; };
|
||||
029445981BDEDF46006D1617 /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 029445961BDEDF46006D1617 /* external_commit_helper.hpp */; };
|
||||
0294465E1BF27DE6006D1617 /* query_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0294465C1BF27DE6006D1617 /* query_builder.cpp */; };
|
||||
0294465F1BF27DE6006D1617 /* query_builder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0294465D1BF27DE6006D1617 /* query_builder.hpp */; };
|
||||
02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
|
||||
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; };
|
||||
02C0864F1BCDB27000942F9C /* list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02C0864D1BCDB27000942F9C /* list.hpp */; };
|
||||
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02D0F23A1BF6C95200B4FC45 /* binding_context.hpp */; };
|
||||
02D0F2D61C037C3400B4FC45 /* GCDWebServers.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 021CEA3C1BFD1BA000D69390 /* GCDWebServers.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02D456D91B7E59A500EE1299 /* ArrayTests.js */; };
|
||||
02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
|
||||
02E9A9F11BFA84F100939F86 /* QueryTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02E9A9F01BFA84F100939F86 /* QueryTests.js */; };
|
||||
02EF76761BFFD41F000D5BAD /* queryTests.json in Resources */ = {isa = PBXBuildFile; fileRef = 02EF76751BFFD41F000D5BAD /* queryTests.json */; };
|
||||
02EF76861BFFDE37000D5BAD /* test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02EF76851BFFDE37000D5BAD /* test.cpp */; };
|
||||
02EF76881BFFDE9E000D5BAD /* GrammarTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 02EF76871BFFDE9E000D5BAD /* GrammarTests.mm */; };
|
||||
F636F6C81BCDB3570023F35C /* RealmReact.h in Headers */ = {isa = PBXBuildFile; fileRef = 0270BCCF1B7D067300010E03 /* RealmReact.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
F64426C51BCDB1E200A81210 /* RealmJS.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
F64E1EF11BC3510E00E0E150 /* util.js in Resources */ = {isa = PBXBuildFile; fileRef = F64E1EF01BC3510E00E0E150 /* util.js */; };
|
||||
F67191381BCE231100AD0939 /* GCDWebServers.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; };
|
||||
F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; };
|
||||
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6BB7DEF1BF681BC00D0A69E /* base64.cpp */; };
|
||||
|
@ -70,42 +78,35 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
02313C461BCC4A43003F9107 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CEE28CEE1AE0051F00F4023C;
|
||||
remoteInfo = "GCDWebServers (iOS)";
|
||||
};
|
||||
02A3C78D1BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
|
||||
021CEA351BFD1BA000D69390 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 8DD76FB20486AB0100D96B5E;
|
||||
remoteInfo = "GCDWebServer (Mac)";
|
||||
};
|
||||
02A3C78F1BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
|
||||
021CEA371BFD1BA000D69390 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = E221125A1690B4DE0048D2B2;
|
||||
remoteInfo = "GCDWebServer (iOS)";
|
||||
};
|
||||
02A3C7911BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
|
||||
021CEA391BFD1BA000D69390 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = CEE28CD11AE004D800F4023C;
|
||||
remoteInfo = "GCDWebServers (Mac)";
|
||||
};
|
||||
02A3C7931BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
|
||||
021CEA3B1BFD1BA000D69390 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = CEE28CEF1AE0051F00F4023C;
|
||||
remoteInfo = "GCDWebServers (iOS)";
|
||||
};
|
||||
02A3C7951BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
|
||||
021CEA3D1BFD1BA000D69390 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
|
@ -126,6 +127,27 @@
|
|||
remoteGlobalIDString = 02B58CB01AE99CEC009B348C;
|
||||
remoteInfo = RealmJS;
|
||||
};
|
||||
02D0F2A01C03775600B4FC45 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = E2DDD1C71BE698A8002CE867;
|
||||
remoteInfo = "GCDWebServer (tvOS)";
|
||||
};
|
||||
02D0F2A21C03775600B4FC45 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = E2DDD18B1BE69404002CE867;
|
||||
remoteInfo = "GCDWebServers (tvOS)";
|
||||
};
|
||||
02D0F2D41C037C1700B4FC45 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = CEE28CEE1AE0051F00F4023C;
|
||||
remoteInfo = "GCDWebServers (iOS)";
|
||||
};
|
||||
02EE6D891BD87E310016A82E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 02EE6D781BD87E310016A82E /* ReactTests.xcodeproj */;
|
||||
|
@ -149,7 +171,7 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
F67191381BCE231100AD0939 /* GCDWebServers.framework in Embed Frameworks */,
|
||||
02D0F2D61C037C3400B4FC45 /* GCDWebServers.framework in Embed Frameworks */,
|
||||
F64426C51BCDB1E200A81210 /* RealmJS.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
|
@ -170,15 +192,15 @@
|
|||
0270BC401B7CFC0D00010E03 /* RJSList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSList.cpp; path = src/RJSList.cpp; sourceTree = "<group>"; };
|
||||
0270BC411B7CFC0D00010E03 /* RJSList.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSList.hpp; path = src/RJSList.hpp; sourceTree = "<group>"; };
|
||||
0270BC421B7CFC0D00010E03 /* RJSObject.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSObject.hpp; path = src/RJSObject.hpp; sourceTree = "<group>"; };
|
||||
0270BC431B7CFC0D00010E03 /* RJSObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSObject.mm; path = src/RJSObject.mm; sourceTree = "<group>"; };
|
||||
0270BC431B7CFC0D00010E03 /* RJSObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSObject.cpp; path = src/RJSObject.cpp; sourceTree = "<group>"; };
|
||||
0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSRealm.hpp; path = src/RJSRealm.hpp; sourceTree = "<group>"; };
|
||||
0270BC451B7CFC0D00010E03 /* RJSRealm.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSRealm.mm; path = src/RJSRealm.mm; sourceTree = "<group>"; };
|
||||
0270BC461B7CFC0D00010E03 /* RJSResults.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSResults.hpp; path = src/RJSResults.hpp; sourceTree = "<group>"; };
|
||||
0270BC471B7CFC0D00010E03 /* RJSResults.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSResults.mm; path = src/RJSResults.mm; sourceTree = "<group>"; };
|
||||
0270BC471B7CFC0D00010E03 /* RJSResults.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSResults.cpp; path = src/RJSResults.cpp; sourceTree = "<group>"; };
|
||||
0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSSchema.hpp; path = src/RJSSchema.hpp; sourceTree = "<group>"; };
|
||||
0270BC491B7CFC0D00010E03 /* RJSSchema.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSSchema.mm; path = src/RJSSchema.mm; sourceTree = "<group>"; };
|
||||
0270BC491B7CFC0D00010E03 /* RJSSchema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSSchema.cpp; path = src/RJSSchema.cpp; sourceTree = "<group>"; };
|
||||
0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = RJSUtil.hpp; path = src/RJSUtil.hpp; sourceTree = "<group>"; };
|
||||
0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RJSUtil.mm; path = src/RJSUtil.mm; sourceTree = "<group>"; };
|
||||
0270BC4B1B7CFC0D00010E03 /* RJSUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSUtil.cpp; path = src/RJSUtil.cpp; sourceTree = "<group>"; };
|
||||
0270BC5A1B7CFC1300010E03 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = src/Info.plist; sourceTree = "<group>"; };
|
||||
0270BC5D1B7CFC1C00010E03 /* object_accessor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = object_accessor.hpp; path = "src/object-store/object_accessor.hpp"; sourceTree = "<group>"; };
|
||||
0270BC5E1B7CFC1C00010E03 /* object_schema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = object_schema.cpp; path = "src/object-store/object_schema.cpp"; sourceTree = "<group>"; };
|
||||
|
@ -200,10 +222,14 @@
|
|||
0270BC7F1B7D020100010E03 /* schemas.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = schemas.js; path = tests/schemas.js; sourceTree = SOURCE_ROOT; };
|
||||
0270BCCF1B7D067300010E03 /* RealmReact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmReact.h; path = ReactNative/RealmReact.h; sourceTree = "<group>"; };
|
||||
0270BCD01B7D067300010E03 /* RealmReact.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmReact.mm; path = ReactNative/RealmReact.mm; sourceTree = "<group>"; };
|
||||
02786E311BF1065000937061 /* parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = parser.cpp; path = "src/object-store/parser/parser.cpp"; sourceTree = "<group>"; };
|
||||
02786E321BF1065000937061 /* parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = parser.hpp; path = "src/object-store/parser/parser.hpp"; sourceTree = "<group>"; };
|
||||
029445911BDEDF40006D1617 /* transact_log_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = transact_log_handler.cpp; path = "src/object-store/impl/transact_log_handler.cpp"; sourceTree = "<group>"; };
|
||||
029445921BDEDF40006D1617 /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/impl/transact_log_handler.hpp"; sourceTree = "<group>"; };
|
||||
029445951BDEDF46006D1617 /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/impl/apple/external_commit_helper.cpp"; sourceTree = "<group>"; };
|
||||
029445961BDEDF46006D1617 /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/impl/apple/external_commit_helper.hpp"; sourceTree = "<group>"; };
|
||||
0294465C1BF27DE6006D1617 /* query_builder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = query_builder.cpp; path = "src/object-store/parser/query_builder.cpp"; sourceTree = "<group>"; };
|
||||
0294465D1BF27DE6006D1617 /* query_builder.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = query_builder.hpp; path = "src/object-store/parser/query_builder.hpp"; sourceTree = "<group>"; };
|
||||
02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = GCDWebServer.xcodeproj; path = GCDWebServer/GCDWebServer.xcodeproj; sourceTree = "<group>"; };
|
||||
02A3C7A41BC4341500B1A7BE /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
|
||||
02B29A161B7CF7C9008A7E6B /* RealmReact.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RealmReact.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
@ -214,7 +240,11 @@
|
|||
02C0864D1BCDB27000942F9C /* list.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = list.hpp; path = "src/object-store/list.hpp"; sourceTree = "<group>"; };
|
||||
02D0F23A1BF6C95200B4FC45 /* binding_context.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = binding_context.hpp; path = "src/object-store/binding_context.hpp"; sourceTree = "<group>"; };
|
||||
02D456D91B7E59A500EE1299 /* ArrayTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = ArrayTests.js; path = tests/ArrayTests.js; sourceTree = SOURCE_ROOT; };
|
||||
02E9A9F01BFA84F100939F86 /* QueryTests.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = QueryTests.js; path = tests/QueryTests.js; sourceTree = SOURCE_ROOT; };
|
||||
02EE6D781BD87E310016A82E /* ReactTests.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ReactTests.xcodeproj; path = tests/ReactTests/ios/ReactTests.xcodeproj; sourceTree = "<group>"; };
|
||||
02EF76751BFFD41F000D5BAD /* queryTests.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = queryTests.json; path = "src/object-store/parser/queryTests.json"; sourceTree = SOURCE_ROOT; };
|
||||
02EF76851BFFDE37000D5BAD /* test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test.cpp; path = "src/object-store/parser/test.cpp"; sourceTree = SOURCE_ROOT; };
|
||||
02EF76871BFFDE9E000D5BAD /* GrammarTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = GrammarTests.mm; path = tests/GrammarTests.mm; sourceTree = SOURCE_ROOT; };
|
||||
F64E1EF01BC3510E00E0E150 /* util.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = util.js; path = tests/util.js; sourceTree = SOURCE_ROOT; };
|
||||
F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RJSModuleLoader.h; path = tests/RJSModuleLoader.h; sourceTree = SOURCE_ROOT; };
|
||||
F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RJSModuleLoader.m; path = tests/RJSModuleLoader.m; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -255,6 +285,20 @@
|
|||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
021CEA2D1BFD1BA000D69390 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
021CEA361BFD1BA000D69390 /* GCDWebServer */,
|
||||
021CEA381BFD1BA000D69390 /* GCDWebServer.app */,
|
||||
02D0F2A11C03775600B4FC45 /* GCDWebServer.app */,
|
||||
021CEA3A1BFD1BA000D69390 /* GCDWebServers.framework */,
|
||||
021CEA3C1BFD1BA000D69390 /* GCDWebServers.framework */,
|
||||
02D0F2A31C03775600B4FC45 /* GCDWebServers.framework */,
|
||||
021CEA3E1BFD1BA000D69390 /* Tests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0270BC3D1B7CFBFD00010E03 /* RealmJS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -279,6 +323,10 @@
|
|||
029445921BDEDF40006D1617 /* transact_log_handler.hpp */,
|
||||
029445951BDEDF46006D1617 /* external_commit_helper.cpp */,
|
||||
029445961BDEDF46006D1617 /* external_commit_helper.hpp */,
|
||||
02786E311BF1065000937061 /* parser.cpp */,
|
||||
02786E321BF1065000937061 /* parser.hpp */,
|
||||
0294465C1BF27DE6006D1617 /* query_builder.cpp */,
|
||||
0294465D1BF27DE6006D1617 /* query_builder.hpp */,
|
||||
0270BC3E1B7CFC0D00010E03 /* RealmJS.h */,
|
||||
0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */,
|
||||
02258FB11BC6E2D00075F13A /* RealmRPC.hpp */,
|
||||
|
@ -286,15 +334,15 @@
|
|||
0270BC401B7CFC0D00010E03 /* RJSList.cpp */,
|
||||
0270BC411B7CFC0D00010E03 /* RJSList.hpp */,
|
||||
0270BC421B7CFC0D00010E03 /* RJSObject.hpp */,
|
||||
0270BC431B7CFC0D00010E03 /* RJSObject.mm */,
|
||||
0270BC431B7CFC0D00010E03 /* RJSObject.cpp */,
|
||||
0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */,
|
||||
0270BC451B7CFC0D00010E03 /* RJSRealm.mm */,
|
||||
0270BC461B7CFC0D00010E03 /* RJSResults.hpp */,
|
||||
0270BC471B7CFC0D00010E03 /* RJSResults.mm */,
|
||||
0270BC471B7CFC0D00010E03 /* RJSResults.cpp */,
|
||||
0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */,
|
||||
0270BC491B7CFC0D00010E03 /* RJSSchema.mm */,
|
||||
0270BC491B7CFC0D00010E03 /* RJSSchema.cpp */,
|
||||
0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */,
|
||||
0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */,
|
||||
0270BC4B1B7CFC0D00010E03 /* RJSUtil.cpp */,
|
||||
0270BC5A1B7CFC1300010E03 /* Info.plist */,
|
||||
);
|
||||
name = RealmJS;
|
||||
|
@ -310,18 +358,6 @@
|
|||
name = RealmReact;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
02A3C7851BC4317A00B1A7BE /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
02A3C78E1BC4317A00B1A7BE /* GCDWebServer */,
|
||||
02A3C7901BC4317A00B1A7BE /* GCDWebServer.app */,
|
||||
02A3C7921BC4317A00B1A7BE /* GCDWebServers.framework */,
|
||||
02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */,
|
||||
02A3C7961BC4317A00B1A7BE /* Tests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
02B58CA71AE99CEB009B348C = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -355,6 +391,8 @@
|
|||
F64E1EF01BC3510E00E0E150 /* util.js */,
|
||||
02D456D91B7E59A500EE1299 /* ArrayTests.js */,
|
||||
0270BC791B7D020100010E03 /* ObjectTests.js */,
|
||||
02E9A9F01BFA84F100939F86 /* QueryTests.js */,
|
||||
02EF76751BFFD41F000D5BAD /* queryTests.json */,
|
||||
0270BC7C1B7D020100010E03 /* RealmTests.js */,
|
||||
0270BC7D1B7D020100010E03 /* ResultsTests.js */,
|
||||
0270BC7A1B7D020100010E03 /* RealmJSTests.h */,
|
||||
|
@ -362,6 +400,8 @@
|
|||
02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */,
|
||||
F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */,
|
||||
F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */,
|
||||
02EF76871BFFDE9E000D5BAD /* GrammarTests.mm */,
|
||||
02EF76851BFFDE37000D5BAD /* test.cpp */,
|
||||
);
|
||||
path = RealmJSTests;
|
||||
sourceTree = "<group>";
|
||||
|
@ -406,6 +446,7 @@
|
|||
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */,
|
||||
02258FB31BC6E2D00075F13A /* RealmRPC.hpp in Headers */,
|
||||
0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */,
|
||||
0294465F1BF27DE6006D1617 /* query_builder.hpp in Headers */,
|
||||
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */,
|
||||
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */,
|
||||
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */,
|
||||
|
@ -414,6 +455,7 @@
|
|||
0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */,
|
||||
02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */,
|
||||
0270BC6C1B7CFC1C00010E03 /* object_store.hpp in Headers */,
|
||||
02786E341BF1065100937061 /* parser.hpp in Headers */,
|
||||
0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */,
|
||||
F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */,
|
||||
029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */,
|
||||
|
@ -450,7 +492,7 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
02313C471BCC4A43003F9107 /* PBXTargetDependency */,
|
||||
02D0F2D51C037C1700B4FC45 /* PBXTargetDependency */,
|
||||
02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */,
|
||||
);
|
||||
name = RealmReact;
|
||||
|
@ -527,7 +569,7 @@
|
|||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 02A3C7851BC4317A00B1A7BE /* Products */;
|
||||
ProductGroup = 021CEA2D1BFD1BA000D69390 /* Products */;
|
||||
ProjectRef = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
|
||||
},
|
||||
{
|
||||
|
@ -545,39 +587,53 @@
|
|||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
02A3C78E1BC4317A00B1A7BE /* GCDWebServer */ = {
|
||||
021CEA361BFD1BA000D69390 /* GCDWebServer */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = "compiled.mach-o.executable";
|
||||
path = GCDWebServer;
|
||||
remoteRef = 02A3C78D1BC4317A00B1A7BE /* PBXContainerItemProxy */;
|
||||
remoteRef = 021CEA351BFD1BA000D69390 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02A3C7901BC4317A00B1A7BE /* GCDWebServer.app */ = {
|
||||
021CEA381BFD1BA000D69390 /* GCDWebServer.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = GCDWebServer.app;
|
||||
remoteRef = 02A3C78F1BC4317A00B1A7BE /* PBXContainerItemProxy */;
|
||||
remoteRef = 021CEA371BFD1BA000D69390 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02A3C7921BC4317A00B1A7BE /* GCDWebServers.framework */ = {
|
||||
021CEA3A1BFD1BA000D69390 /* GCDWebServers.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = GCDWebServers.framework;
|
||||
remoteRef = 02A3C7911BC4317A00B1A7BE /* PBXContainerItemProxy */;
|
||||
remoteRef = 021CEA391BFD1BA000D69390 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */ = {
|
||||
021CEA3C1BFD1BA000D69390 /* GCDWebServers.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = GCDWebServers.framework;
|
||||
remoteRef = 02A3C7931BC4317A00B1A7BE /* PBXContainerItemProxy */;
|
||||
remoteRef = 021CEA3B1BFD1BA000D69390 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02A3C7961BC4317A00B1A7BE /* Tests.xctest */ = {
|
||||
021CEA3E1BFD1BA000D69390 /* Tests.xctest */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = Tests.xctest;
|
||||
remoteRef = 02A3C7951BC4317A00B1A7BE /* PBXContainerItemProxy */;
|
||||
remoteRef = 021CEA3D1BFD1BA000D69390 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02D0F2A11C03775600B4FC45 /* GCDWebServer.app */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.application;
|
||||
path = GCDWebServer.app;
|
||||
remoteRef = 02D0F2A01C03775600B4FC45 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02D0F2A31C03775600B4FC45 /* GCDWebServers.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = GCDWebServers.framework;
|
||||
remoteRef = 02D0F2A21C03775600B4FC45 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
02EE6D8A1BD87E310016A82E /* ReactTests.app */ = {
|
||||
|
@ -609,12 +665,14 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F64E1EF11BC3510E00E0E150 /* util.js in Resources */,
|
||||
02E9A9F11BFA84F100939F86 /* QueryTests.js in Resources */,
|
||||
0270BC851B7D020100010E03 /* asserts.js in Resources */,
|
||||
0270BC811B7D020100010E03 /* ObjectTests.js in Resources */,
|
||||
02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */,
|
||||
0270BC861B7D020100010E03 /* schemas.js in Resources */,
|
||||
F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */,
|
||||
F68A278E1BC30F0A0063D40A /* index.js in Resources */,
|
||||
02EF76761BFFD41F000D5BAD /* queryTests.json in Resources */,
|
||||
0270BC831B7D020100010E03 /* RealmTests.js in Resources */,
|
||||
0270BC841B7D020100010E03 /* ResultsTests.js in Resources */,
|
||||
);
|
||||
|
@ -652,19 +710,21 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */,
|
||||
0270BC571B7CFC0D00010E03 /* RJSSchema.cpp in Sources */,
|
||||
0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */,
|
||||
02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */,
|
||||
0270BC6E1B7CFC1C00010E03 /* results.cpp in Sources */,
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */,
|
||||
02786E331BF1065100937061 /* parser.cpp in Sources */,
|
||||
0270BC511B7CFC0D00010E03 /* RJSObject.cpp in Sources */,
|
||||
0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */,
|
||||
02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */,
|
||||
029445931BDEDF40006D1617 /* transact_log_handler.cpp in Sources */,
|
||||
02258FB41BC6E2D00075F13A /* RealmRPC.cpp in Sources */,
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */,
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */,
|
||||
0270BC591B7CFC0D00010E03 /* RJSUtil.cpp in Sources */,
|
||||
0270BC551B7CFC0D00010E03 /* RJSResults.cpp in Sources */,
|
||||
02C0864E1BCDB27000942F9C /* list.cpp in Sources */,
|
||||
0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */,
|
||||
0294465E1BF27DE6006D1617 /* query_builder.cpp in Sources */,
|
||||
0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */,
|
||||
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */,
|
||||
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */,
|
||||
|
@ -678,6 +738,8 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */,
|
||||
02EF76881BFFDE9E000D5BAD /* GrammarTests.mm in Sources */,
|
||||
02EF76861BFFDE37000D5BAD /* test.cpp in Sources */,
|
||||
0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */,
|
||||
02409DC21BCF11D6005F3B3E /* RealmJSCoreTests.m in Sources */,
|
||||
);
|
||||
|
@ -686,11 +748,6 @@
|
|||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
02313C471BCC4A43003F9107 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "GCDWebServers (iOS)";
|
||||
targetProxy = 02313C461BCC4A43003F9107 /* PBXContainerItemProxy */;
|
||||
};
|
||||
02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 02B58CB01AE99CEC009B348C /* RealmJS */;
|
||||
|
@ -701,6 +758,11 @@
|
|||
target = 02B58CB01AE99CEC009B348C /* RealmJS */;
|
||||
targetProxy = 02B58CBE1AE99CEC009B348C /* PBXContainerItemProxy */;
|
||||
};
|
||||
02D0F2D51C037C1700B4FC45 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "GCDWebServers (iOS)";
|
||||
targetProxy = 02D0F2D41C037C1700B4FC45 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
|
@ -922,7 +984,7 @@
|
|||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
|
||||
DEFINES_MODULE = YES;
|
||||
DEFINES_MODULE = NO;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
|
@ -936,6 +998,7 @@
|
|||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/vendor/PEGTL",
|
||||
"$(SRCROOT)/vendor",
|
||||
);
|
||||
INFOPLIST_FILE = src/Info.plist;
|
||||
|
@ -961,7 +1024,7 @@
|
|||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
|
||||
DEFINES_MODULE = YES;
|
||||
DEFINES_MODULE = NO;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
|
@ -970,6 +1033,7 @@
|
|||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/vendor/PEGTL",
|
||||
"$(SRCROOT)/vendor",
|
||||
);
|
||||
INFOPLIST_FILE = src/Info.plist;
|
||||
|
@ -993,11 +1057,7 @@
|
|||
02B58CCB1AE99CEC009B348C /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
build/iOS,
|
||||
);
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
|
@ -1019,11 +1079,7 @@
|
|||
02B58CCC1AE99CEC009B348C /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
build/iOS,
|
||||
);
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
INFOPLIST_FILE = tests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
|
@ -1092,7 +1148,7 @@
|
|||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
|
||||
DEFINES_MODULE = YES;
|
||||
DEFINES_MODULE = NO;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
|
@ -1106,6 +1162,7 @@
|
|||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/vendor/PEGTL",
|
||||
"$(SRCROOT)/vendor",
|
||||
);
|
||||
INFOPLIST_FILE = src/Info.plist;
|
||||
|
@ -1129,11 +1186,7 @@
|
|||
02F9EE1E1B6BF66300C807E8 /* GCov_Build */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
build/iOS,
|
||||
);
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
|
|
|
@ -211,6 +211,13 @@ template<> JSValueRef RJSAccessor::from_datetime(JSContextRef ctx, DateTime dt)
|
|||
|
||||
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array);
|
||||
|
||||
template<> size_t RJSAccessor::to_existing_object_index(JSContextRef ctx, JSValueRef &val) {
|
||||
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
|
||||
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
|
||||
return RJSGetInternal<Object *>(object)->row().get_index();
|
||||
}
|
||||
throw std::runtime_error("object is not a Realm Object");
|
||||
}
|
||||
template<> size_t RJSAccessor::to_object_index(JSContextRef ctx, SharedRealm realm, JSValueRef &val, const std::string &type, bool try_update) {
|
||||
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
|
||||
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
|
|
@ -259,7 +259,7 @@ JSValueRef RealmGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
|
|||
|
||||
JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
RJSValidateArgumentRange(argumentCount, 1, 2);
|
||||
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
|
||||
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
|
||||
|
@ -267,8 +267,12 @@ JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef this
|
|||
return RJSResultsCreate(ctx, sharedRealm, className);
|
||||
}
|
||||
else {
|
||||
std::string predicate = RJSValidatedStringForValue(ctx, arguments[1], "predicate");
|
||||
return RJSResultsCreate(ctx, sharedRealm, className, predicate);
|
||||
std::string query = RJSValidatedStringForValue(ctx, arguments[1], "predicate");
|
||||
std::vector<JSValueRef> args;
|
||||
for (size_t i = 2; i < argumentCount; i++) {
|
||||
args.push_back(arguments[i]);
|
||||
}
|
||||
return RJSResultsCreate(ctx, sharedRealm, className, query, args);
|
||||
}
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#import "RJSObject.hpp"
|
||||
#import "object_accessor.hpp"
|
||||
#import "results.hpp"
|
||||
#import "parser.hpp"
|
||||
#import "query_builder.hpp"
|
||||
|
||||
using namespace realm;
|
||||
|
||||
|
@ -103,22 +105,18 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
|
|||
}
|
||||
|
||||
|
||||
void RLMUpdateQueryWithPredicate(realm::Query *query, NSPredicate *predicate, realm::Schema &schema, realm::ObjectSchema &objectSchema);
|
||||
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className, std::string queryString) {
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className, std::string queryString, std::vector<JSValueRef> args) {
|
||||
TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className);
|
||||
Query query = table->where();
|
||||
Schema &schema = *realm->config().schema;
|
||||
auto object_schema = realm->config().schema->find(className);
|
||||
if (object_schema == realm->config().schema->end()) {
|
||||
auto object_schema = schema.find(className);
|
||||
if (object_schema == schema.end()) {
|
||||
throw std::runtime_error("Object type '" + className + "' not present in Realm.");
|
||||
}
|
||||
@try {
|
||||
RLMUpdateQueryWithPredicate(&query, [NSPredicate predicateWithFormat:@(queryString.c_str())], schema, *object_schema);
|
||||
}
|
||||
@catch(NSException *ex) {
|
||||
throw std::runtime_error(ex.description.UTF8String);
|
||||
}
|
||||
parser::Predicate predicate = parser::parse(queryString);
|
||||
query_builder::ArgumentConverter<JSValueRef, JSContextRef> arguments(ctx, args);
|
||||
query_builder::apply_predicate(query, predicate, arguments, schema, object_schema->name);
|
||||
|
||||
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
|
||||
}
|
||||
|
|
@ -11,4 +11,4 @@ namespace realm {
|
|||
|
||||
JSClassRef RJSResultsClass();
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query);
|
||||
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query, std::vector<JSValueRef> args);
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#import "RJSUtil.hpp"
|
||||
|
||||
using namespace realm;
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, RJSException &exp) {
|
||||
JSValueRef value = exp.exception();
|
||||
return JSObjectMakeError(ctx, 1, &value, NULL);
|
||||
}
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, std::exception &exp) {
|
||||
if (RJSException *rjsExp = dynamic_cast<RJSException *>(&exp)) {
|
||||
return RJSMakeError(ctx, *rjsExp);
|
||||
}
|
||||
return RJSMakeError(ctx, exp.what());
|
||||
}
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message) {
|
||||
JSValueRef value = RJSValueForString(ctx, message);
|
||||
return JSObjectMakeError(ctx, 1, &value, NULL);
|
||||
}
|
||||
|
||||
std::string RJSTypeGet(PropertyType propertyType) {
|
||||
switch (propertyType) {
|
||||
case PropertyTypeBool: return "bool";
|
||||
case PropertyTypeInt: return "int";
|
||||
case PropertyTypeFloat: return "float";
|
||||
case PropertyTypeDouble:return "double";
|
||||
case PropertyTypeString:return "string";
|
||||
case PropertyTypeDate: return "date";
|
||||
case PropertyTypeData: return "data";
|
||||
case PropertyTypeObject:return "object";
|
||||
case PropertyTypeArray: return "list";
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string RJSStringForJSString(JSStringRef jsString) {
|
||||
std::string str;
|
||||
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
|
||||
str.resize(maxSize);
|
||||
str.resize(JSStringGetUTF8CString(jsString, &str[0], maxSize) - 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value) {
|
||||
JSValueRef *exception;
|
||||
JSStringRef jsString = JSValueToStringCopy(ctx, value, exception);
|
||||
if (!jsString) {
|
||||
throw RJSException(ctx, *exception);
|
||||
}
|
||||
|
||||
std::string string = RJSStringForJSString(jsString);
|
||||
JSStringRelease(jsString);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name) {
|
||||
if (!JSValueIsString(ctx, value)) {
|
||||
if (name) {
|
||||
throw std::invalid_argument((std::string)"'" + name + "' must be of type 'String'");
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("JSValue must be of type 'String'");
|
||||
}
|
||||
}
|
||||
|
||||
return RJSStringForValue(ctx, value);
|
||||
}
|
||||
|
||||
JSStringRef RJSStringForString(const std::string &str) {
|
||||
return JSStringCreateWithUTF8CString(str.c_str());
|
||||
}
|
||||
|
||||
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str) {
|
||||
JSStringRef jsStr = RJSStringForString(str);
|
||||
JSValueRef value = JSValueMakeString(ctx, jsStr);
|
||||
JSStringRelease(jsStr);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool RJSIsValueArray(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef arrayString = JSStringCreateWithUTF8CString("Array");
|
||||
return RJSIsValueObjectOfType(ctx, value, arrayString);
|
||||
}
|
||||
|
||||
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef arrayString = JSStringCreateWithUTF8CString("ArrayBuffer");
|
||||
return RJSIsValueObjectOfType(ctx, value, arrayString);
|
||||
}
|
||||
|
||||
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef dateString = JSStringCreateWithUTF8CString("Date");
|
||||
return RJSIsValueObjectOfType(ctx, value, dateString);
|
||||
}
|
||||
|
639
src/RJSUtil.mm
639
src/RJSUtil.mm
|
@ -1,639 +0,0 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#import "RJSUtil.hpp"
|
||||
|
||||
using namespace realm;
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, RJSException &exp) {
|
||||
JSValueRef value = exp.exception();
|
||||
return JSObjectMakeError(ctx, 1, &value, NULL);
|
||||
}
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, std::exception &exp) {
|
||||
if (RJSException *rjsExp = dynamic_cast<RJSException *>(&exp)) {
|
||||
return RJSMakeError(ctx, *rjsExp);
|
||||
}
|
||||
return RJSMakeError(ctx, exp.what());
|
||||
}
|
||||
|
||||
JSValueRef RJSMakeError(JSContextRef ctx, const std::string &message) {
|
||||
JSValueRef value = RJSValueForString(ctx, message);
|
||||
return JSObjectMakeError(ctx, 1, &value, NULL);
|
||||
}
|
||||
|
||||
std::string RJSTypeGet(PropertyType propertyType) {
|
||||
switch (propertyType) {
|
||||
case PropertyTypeBool: return "bool";
|
||||
case PropertyTypeInt: return "int";
|
||||
case PropertyTypeFloat: return "float";
|
||||
case PropertyTypeDouble:return "double";
|
||||
case PropertyTypeString:return "string";
|
||||
case PropertyTypeDate: return "date";
|
||||
case PropertyTypeData: return "data";
|
||||
case PropertyTypeObject:return "object";
|
||||
case PropertyTypeArray: return "list";
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string RJSStringForJSString(JSStringRef jsString) {
|
||||
std::string str;
|
||||
size_t maxSize = JSStringGetMaximumUTF8CStringSize(jsString);
|
||||
str.resize(maxSize);
|
||||
str.resize(JSStringGetUTF8CString(jsString, &str[0], maxSize) - 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string RJSStringForValue(JSContextRef ctx, JSValueRef value) {
|
||||
JSValueRef *exception;
|
||||
JSStringRef jsString = JSValueToStringCopy(ctx, value, exception);
|
||||
if (!jsString) {
|
||||
throw RJSException(ctx, *exception);
|
||||
}
|
||||
|
||||
std::string string = RJSStringForJSString(jsString);
|
||||
JSStringRelease(jsString);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
std::string RJSValidatedStringForValue(JSContextRef ctx, JSValueRef value, const char * name) {
|
||||
if (!JSValueIsString(ctx, value)) {
|
||||
if (name) {
|
||||
throw std::invalid_argument((std::string)"'" + name + "' must be of type 'STRING'");
|
||||
}
|
||||
else {
|
||||
throw std::invalid_argument("JSValue must be of type 'STRING'");
|
||||
}
|
||||
}
|
||||
|
||||
return RJSStringForValue(ctx, value);
|
||||
}
|
||||
|
||||
JSStringRef RJSStringForString(const std::string &str) {
|
||||
return JSStringCreateWithUTF8CString(str.c_str());
|
||||
}
|
||||
|
||||
JSValueRef RJSValueForString(JSContextRef ctx, const std::string &str) {
|
||||
JSStringRef jsStr = RJSStringForString(str);
|
||||
JSValueRef value = JSValueMakeString(ctx, jsStr);
|
||||
JSStringRelease(jsStr);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool RJSIsValueArray(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef arrayString = JSStringCreateWithUTF8CString("Array");
|
||||
return RJSIsValueObjectOfType(ctx, value, arrayString);
|
||||
}
|
||||
|
||||
bool RJSIsValueArrayBuffer(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef arrayString = JSStringCreateWithUTF8CString("ArrayBuffer");
|
||||
return RJSIsValueObjectOfType(ctx, value, arrayString);
|
||||
}
|
||||
|
||||
bool RJSIsValueDate(JSContextRef ctx, JSValueRef value) {
|
||||
static JSStringRef dateString = JSStringCreateWithUTF8CString("Date");
|
||||
return RJSIsValueObjectOfType(ctx, value, dateString);
|
||||
}
|
||||
|
||||
|
||||
#include <realm.hpp>
|
||||
#include "object_store.hpp"
|
||||
|
||||
// check a precondition and throw an exception if it is not met
|
||||
// this should be used iff the condition being false indicates a bug in the caller
|
||||
// of the function checking its preconditions
|
||||
static void RLMPrecondition(bool condition, NSString *name, NSString *format, ...) {
|
||||
if (__builtin_expect(condition, 1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
NSString *reason = [[NSString alloc] initWithFormat:format arguments:args];
|
||||
va_end(args);
|
||||
|
||||
throw std::runtime_error(reason.UTF8String);
|
||||
}
|
||||
|
||||
// FIXME: TrueExpression and FalseExpression should be supported by core in some way
|
||||
struct TrueExpression : realm::Expression {
|
||||
size_t find_first(size_t start, size_t end) const override
|
||||
{
|
||||
if (start != end)
|
||||
return start;
|
||||
|
||||
return realm::not_found;
|
||||
}
|
||||
void set_table() override {}
|
||||
const realm::Table* get_table() const override { return nullptr; }
|
||||
};
|
||||
|
||||
struct FalseExpression : realm::Expression {
|
||||
size_t find_first(size_t, size_t) const override { return realm::not_found; }
|
||||
void set_table() override {}
|
||||
const realm::Table* get_table() const override { return nullptr; }
|
||||
};
|
||||
|
||||
NSString *operatorName(NSPredicateOperatorType operatorType)
|
||||
{
|
||||
switch (operatorType) {
|
||||
case NSLessThanPredicateOperatorType:
|
||||
return @"<";
|
||||
case NSLessThanOrEqualToPredicateOperatorType:
|
||||
return @"<=";
|
||||
case NSGreaterThanPredicateOperatorType:
|
||||
return @">";
|
||||
case NSGreaterThanOrEqualToPredicateOperatorType:
|
||||
return @">=";
|
||||
case NSEqualToPredicateOperatorType:
|
||||
return @"==";
|
||||
case NSNotEqualToPredicateOperatorType:
|
||||
return @"!=";
|
||||
case NSMatchesPredicateOperatorType:
|
||||
return @"MATCHES";
|
||||
case NSLikePredicateOperatorType:
|
||||
return @"LIKE";
|
||||
case NSBeginsWithPredicateOperatorType:
|
||||
return @"BEGINSWITH";
|
||||
case NSEndsWithPredicateOperatorType:
|
||||
return @"ENDSWITH";
|
||||
case NSInPredicateOperatorType:
|
||||
return @"IN";
|
||||
case NSContainsPredicateOperatorType:
|
||||
return @"CONTAINS";
|
||||
case NSBetweenPredicateOperatorType:
|
||||
return @"BETWEENS";
|
||||
case NSCustomSelectorPredicateOperatorType:
|
||||
return @"custom selector";
|
||||
}
|
||||
|
||||
return [NSString stringWithFormat:@"unknown operator %lu", (unsigned long)operatorType];
|
||||
}
|
||||
|
||||
// add a clause for numeric constraints based on operator type
|
||||
template <typename A, typename B>
|
||||
void add_numeric_constraint_to_query(realm::Query& query,
|
||||
realm::PropertyType datatype,
|
||||
NSPredicateOperatorType operatorType,
|
||||
A lhs,
|
||||
B rhs)
|
||||
{
|
||||
switch (operatorType) {
|
||||
case NSLessThanPredicateOperatorType:
|
||||
query.and_query(lhs < rhs);
|
||||
break;
|
||||
case NSLessThanOrEqualToPredicateOperatorType:
|
||||
query.and_query(lhs <= rhs);
|
||||
break;
|
||||
case NSGreaterThanPredicateOperatorType:
|
||||
query.and_query(lhs > rhs);
|
||||
break;
|
||||
case NSGreaterThanOrEqualToPredicateOperatorType:
|
||||
query.and_query(lhs >= rhs);
|
||||
break;
|
||||
case NSEqualToPredicateOperatorType:
|
||||
query.and_query(lhs == rhs);
|
||||
break;
|
||||
case NSNotEqualToPredicateOperatorType:
|
||||
query.and_query(lhs != rhs);
|
||||
break;
|
||||
default: {
|
||||
NSString *error = [NSString stringWithFormat:@"Operator '%@' not supported for type %s", operatorName(operatorType), realm::string_for_property_type(datatype)];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void add_bool_constraint_to_query(realm::Query &query, NSPredicateOperatorType operatorType, A lhs, B rhs) {
|
||||
switch (operatorType) {
|
||||
case NSEqualToPredicateOperatorType:
|
||||
query.and_query(lhs == rhs);
|
||||
break;
|
||||
case NSNotEqualToPredicateOperatorType:
|
||||
query.and_query(lhs != rhs);
|
||||
break;
|
||||
default: {
|
||||
NSString *error = [NSString stringWithFormat:@"Operator '%@' not supported for bool type", operatorName(operatorType)];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_string_constraint_to_query(realm::Query &query,
|
||||
NSPredicateOperatorType operatorType,
|
||||
NSComparisonPredicateOptions predicateOptions,
|
||||
realm::Columns<realm::String> &&column,
|
||||
NSString *value) {
|
||||
bool caseSensitive = !(predicateOptions & NSCaseInsensitivePredicateOption);
|
||||
bool diacriticInsensitive = (predicateOptions & NSDiacriticInsensitivePredicateOption);
|
||||
RLMPrecondition(!diacriticInsensitive, @"Invalid predicate option",
|
||||
@"NSDiacriticInsensitivePredicateOption not supported for string type");
|
||||
|
||||
realm::StringData sd = value.UTF8String;
|
||||
switch (operatorType) {
|
||||
case NSBeginsWithPredicateOperatorType:
|
||||
query.and_query(column.begins_with(sd, caseSensitive));
|
||||
break;
|
||||
case NSEndsWithPredicateOperatorType:
|
||||
query.and_query(column.ends_with(sd, caseSensitive));
|
||||
break;
|
||||
case NSContainsPredicateOperatorType:
|
||||
query.and_query(column.contains(sd, caseSensitive));
|
||||
break;
|
||||
case NSEqualToPredicateOperatorType:
|
||||
query.and_query(column.equal(sd, caseSensitive));
|
||||
break;
|
||||
case NSNotEqualToPredicateOperatorType:
|
||||
query.and_query(column.not_equal(sd, caseSensitive));
|
||||
break;
|
||||
default: {
|
||||
NSString *error = [NSString stringWithFormat:@"Operator '%@' not supported for string type", operatorName(operatorType)];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_string_constraint_to_query(realm::Query& query,
|
||||
NSPredicateOperatorType operatorType,
|
||||
NSComparisonPredicateOptions predicateOptions,
|
||||
NSString *value,
|
||||
realm::Columns<realm::String>&& column) {
|
||||
switch (operatorType) {
|
||||
case NSEqualToPredicateOperatorType:
|
||||
case NSNotEqualToPredicateOperatorType:
|
||||
add_string_constraint_to_query(query, operatorType, predicateOptions, std::move(column), value);
|
||||
break;
|
||||
default: {
|
||||
NSString *error = [NSString stringWithFormat:@"Operator '%@' is not supported for string type with key path on right side of operator",
|
||||
operatorName(operatorType)];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T *RLMDynamicCast(__unsafe_unretained id obj) {
|
||||
if ([obj isKindOfClass:[T class]]) {
|
||||
return obj;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
id value_from_constant_expression_or_value(id value) {
|
||||
if (NSExpression *exp = RLMDynamicCast<NSExpression>(value)) {
|
||||
RLMPrecondition(exp.expressionType == NSConstantValueExpressionType,
|
||||
@"Invalid value",
|
||||
@"Expressions within predicate aggregates must be constant values");
|
||||
return exp.constantValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// iterate over an array of subpredicates, using @func to build a query from each
|
||||
// one and ORing them together
|
||||
template<typename Func>
|
||||
void process_or_group(realm::Query &query, id array, Func&& func) {
|
||||
RLMPrecondition([array conformsToProtocol:@protocol(NSFastEnumeration)],
|
||||
@"Invalid value", @"IN clause requires an array of items");
|
||||
|
||||
query.group();
|
||||
|
||||
bool first = true;
|
||||
for (id item in array) {
|
||||
if (!first) {
|
||||
query.Or();
|
||||
}
|
||||
first = false;
|
||||
|
||||
func(item);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
// Queries can't be empty, so if there's zero things in the OR group
|
||||
// validation will fail. Work around this by adding an expression which
|
||||
// will never find any rows in a table.
|
||||
query.and_query(new FalseExpression);
|
||||
}
|
||||
|
||||
query.end_group();
|
||||
}
|
||||
|
||||
template <typename RequestedType, typename TableGetter>
|
||||
struct ColumnOfTypeHelper {
|
||||
static realm::Columns<RequestedType> convert(TableGetter&& table, NSUInteger idx)
|
||||
{
|
||||
return table()->template column<RequestedType>(idx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ColumnOfTypeHelper<realm::DateTime, TableGetter> {
|
||||
static realm::Columns<realm::Int> convert(TableGetter&& table, NSUInteger idx)
|
||||
{
|
||||
return table()->template column<realm::Int>(idx);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RequestedType, typename TableGetter>
|
||||
struct ValueOfTypeHelper;
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<realm::DateTime, TableGetter> {
|
||||
static realm::Int convert(TableGetter&&, id value)
|
||||
{
|
||||
return [value timeIntervalSince1970];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<bool, TableGetter> {
|
||||
static bool convert(TableGetter&&, id value)
|
||||
{
|
||||
return [value boolValue];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<realm::Double, TableGetter> {
|
||||
static realm::Double convert(TableGetter&&, id value)
|
||||
{
|
||||
return [value doubleValue];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<realm::Float, TableGetter> {
|
||||
static realm::Float convert(TableGetter&&, id value)
|
||||
{
|
||||
return [value floatValue];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<realm::Int, TableGetter> {
|
||||
static realm::Int convert(TableGetter&&, id value)
|
||||
{
|
||||
return [value longLongValue];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueOfTypeHelper<realm::String, TableGetter> {
|
||||
static id convert(TableGetter&&, id value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RequestedType, typename Value, typename TableGetter>
|
||||
auto value_of_type_for_query(TableGetter&& tables, Value&& value)
|
||||
{
|
||||
const bool isColumnIndex = std::is_same<NSUInteger, typename std::remove_reference<Value>::type>::value;
|
||||
using helper = std::conditional_t<isColumnIndex,
|
||||
ColumnOfTypeHelper<RequestedType, TableGetter>,
|
||||
ValueOfTypeHelper<RequestedType, TableGetter>>;
|
||||
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
void add_constraint_to_query(realm::Query &query, realm::PropertyType type,
|
||||
NSPredicateOperatorType operatorType,
|
||||
NSComparisonPredicateOptions predicateOptions,
|
||||
std::vector<NSUInteger> linkColumns, T... values)
|
||||
{
|
||||
static_assert(sizeof...(T) == 2, "add_constraint_to_query accepts only two values as arguments");
|
||||
|
||||
auto table = [&] {
|
||||
realm::TableRef& tbl = query.get_table();
|
||||
for (NSUInteger col : linkColumns) {
|
||||
tbl->link(col); // mutates m_link_chain on table
|
||||
}
|
||||
return tbl.get();
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case realm::PropertyTypeBool:
|
||||
add_bool_constraint_to_query(query, operatorType, value_of_type_for_query<bool>(table, values)...);
|
||||
break;
|
||||
case realm::PropertyTypeDate:
|
||||
add_numeric_constraint_to_query(query, type, operatorType, value_of_type_for_query<realm::DateTime>(table, values)...);
|
||||
break;
|
||||
case realm::PropertyTypeDouble:
|
||||
add_numeric_constraint_to_query(query, type, operatorType, value_of_type_for_query<realm::Double>(table, values)...);
|
||||
break;
|
||||
case realm::PropertyTypeFloat:
|
||||
add_numeric_constraint_to_query(query, type, operatorType, value_of_type_for_query<realm::Float>(table, values)...);
|
||||
break;
|
||||
case realm::PropertyTypeInt:
|
||||
add_numeric_constraint_to_query(query, type, operatorType, value_of_type_for_query<realm::Int>(table, values)...);
|
||||
break;
|
||||
case realm::PropertyTypeString:
|
||||
case realm::PropertyTypeData:
|
||||
add_string_constraint_to_query(query, operatorType, predicateOptions, value_of_type_for_query<realm::String>(table, values)...);
|
||||
break;
|
||||
default: {
|
||||
NSString *error = [NSString stringWithFormat:@"Object type %s not supported", realm::string_for_property_type(type)];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
realm::Property *get_property_from_key_path(realm::Schema &schema, realm::ObjectSchema &desc,
|
||||
NSString *keyPath, std::vector<NSUInteger> &indexes, bool isAny)
|
||||
{
|
||||
realm::Property *prop = nullptr;
|
||||
|
||||
NSString *prevPath = nil;
|
||||
NSUInteger start = 0, length = keyPath.length, end = NSNotFound;
|
||||
do {
|
||||
end = [keyPath rangeOfString:@"." options:0 range:{start, length - start}].location;
|
||||
NSString *path = [keyPath substringWithRange:{start, end == NSNotFound ? length - start : end - start}];
|
||||
if (prop) {
|
||||
RLMPrecondition(prop->type == realm::PropertyTypeObject || prop->type == realm::PropertyTypeArray,
|
||||
@"Invalid value", @"Property '%@' is not a link in object of type '%s'", prevPath, desc.name.c_str());
|
||||
indexes.push_back(prop->table_column);
|
||||
prop = desc.property_for_name(path.UTF8String);
|
||||
RLMPrecondition(prop, @"Invalid property name",
|
||||
@"Property '%@' not found in object of type '%s'", path, desc.name.c_str());
|
||||
}
|
||||
else {
|
||||
prop = desc.property_for_name(path.UTF8String);
|
||||
RLMPrecondition(prop, @"Invalid property name",
|
||||
@"Property '%@' not found in object of type '%s'", path, desc.name.c_str());
|
||||
|
||||
if (isAny) {
|
||||
RLMPrecondition(prop->type == realm::PropertyTypeArray,
|
||||
@"Invalid predicate",
|
||||
@"ANY modifier can only be used for RLMArray properties");
|
||||
}
|
||||
else {
|
||||
RLMPrecondition(prop->type != realm::PropertyTypeArray,
|
||||
@"Invalid predicate",
|
||||
@"RLMArray predicates must contain the ANY modifier");
|
||||
}
|
||||
}
|
||||
|
||||
if (prop->object_type.length()) {
|
||||
desc = *schema.find(prop->object_type);
|
||||
}
|
||||
prevPath = path;
|
||||
start = end + 1;
|
||||
} while (end != NSNotFound);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
void update_query_with_value_expression(realm::Schema &schema,
|
||||
realm::ObjectSchema &desc,
|
||||
realm::Query &query,
|
||||
NSString *keyPath,
|
||||
id value,
|
||||
NSComparisonPredicate *pred)
|
||||
{
|
||||
bool isAny = pred.comparisonPredicateModifier == NSAnyPredicateModifier;
|
||||
std::vector<NSUInteger> indexes;
|
||||
realm::Property *prop = get_property_from_key_path(schema, desc, keyPath, indexes, isAny);
|
||||
|
||||
NSUInteger index = prop->table_column;
|
||||
|
||||
// check to see if this is a between query
|
||||
if (pred.predicateOperatorType == NSBetweenPredicateOperatorType) {
|
||||
throw std::runtime_error("BETWEEN queries not supported");
|
||||
}
|
||||
|
||||
// turn IN into ored together ==
|
||||
if (pred.predicateOperatorType == NSInPredicateOperatorType) {
|
||||
process_or_group(query, value, [&](id item) {
|
||||
id normalized = value_from_constant_expression_or_value(item);
|
||||
add_constraint_to_query(query, prop->type, NSEqualToPredicateOperatorType,
|
||||
pred.options, indexes, index, normalized);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (pred.leftExpression.expressionType == NSKeyPathExpressionType) {
|
||||
add_constraint_to_query(query, prop->type, pred.predicateOperatorType,
|
||||
pred.options, indexes, index, value);
|
||||
} else {
|
||||
add_constraint_to_query(query, prop->type, pred.predicateOperatorType,
|
||||
pred.options, indexes, value, index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void update_query_with_predicate(NSPredicate *predicate, realm::Schema &schema, realm::ObjectSchema &objectSchema, realm::Query &query)
|
||||
{
|
||||
// Compound predicates.
|
||||
if ([predicate isMemberOfClass:[NSCompoundPredicate class]]) {
|
||||
NSCompoundPredicate *comp = (NSCompoundPredicate *)predicate;
|
||||
|
||||
switch ([comp compoundPredicateType]) {
|
||||
case NSAndPredicateType:
|
||||
if (comp.subpredicates.count) {
|
||||
// Add all of the subpredicates.
|
||||
query.group();
|
||||
for (NSPredicate *subp in comp.subpredicates) {
|
||||
update_query_with_predicate(subp, schema, objectSchema, query);
|
||||
}
|
||||
query.end_group();
|
||||
} else {
|
||||
// NSCompoundPredicate's documentation states that an AND predicate with no subpredicates evaluates to TRUE.
|
||||
query.and_query(new TrueExpression);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSOrPredicateType: {
|
||||
// Add all of the subpredicates with ors inbetween.
|
||||
process_or_group(query, comp.subpredicates, [&](__unsafe_unretained NSPredicate *const subp) {
|
||||
update_query_with_predicate(subp, schema, objectSchema, query);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case NSNotPredicateType:
|
||||
// Add the negated subpredicate
|
||||
query.Not();
|
||||
update_query_with_predicate(comp.subpredicates.firstObject, schema, objectSchema, query);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Invalid compound predicate type - Only support AND, OR and NOT predicate types");
|
||||
}
|
||||
}
|
||||
else if ([predicate isMemberOfClass:[NSComparisonPredicate class]]) {
|
||||
NSComparisonPredicate *compp = (NSComparisonPredicate *)predicate;
|
||||
|
||||
// check modifier
|
||||
RLMPrecondition(compp.comparisonPredicateModifier != NSAllPredicateModifier,
|
||||
@"Invalid predicate", @"ALL modifier not supported");
|
||||
|
||||
NSExpressionType exp1Type = compp.leftExpression.expressionType;
|
||||
NSExpressionType exp2Type = compp.rightExpression.expressionType;
|
||||
|
||||
if (compp.comparisonPredicateModifier == NSAnyPredicateModifier) {
|
||||
// for ANY queries
|
||||
RLMPrecondition(exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType,
|
||||
@"Invalid predicate",
|
||||
@"Predicate with ANY modifier must compare a KeyPath with RLMArray with a value");
|
||||
}
|
||||
|
||||
if (compp.predicateOperatorType == NSBetweenPredicateOperatorType || compp.predicateOperatorType == NSInPredicateOperatorType) {
|
||||
// Inserting an array via %@ gives NSConstantValueExpressionType, but
|
||||
// including it directly gives NSAggregateExpressionType
|
||||
if (exp1Type != NSKeyPathExpressionType || (exp2Type != NSAggregateExpressionType && exp2Type != NSConstantValueExpressionType)) {
|
||||
NSString * error = [NSString stringWithFormat:@"Predicate with %s operator must compare a KeyPath with an aggregate with two values", compp.predicateOperatorType == NSBetweenPredicateOperatorType ? "BETWEEN" : "IN"];
|
||||
throw std::runtime_error(error.UTF8String);
|
||||
}
|
||||
exp2Type = NSConstantValueExpressionType;
|
||||
}
|
||||
|
||||
if (exp1Type == NSKeyPathExpressionType && exp2Type == NSConstantValueExpressionType) {
|
||||
// comparing keypath to value
|
||||
update_query_with_value_expression(schema, objectSchema, query, compp.leftExpression.keyPath,
|
||||
compp.rightExpression.constantValue, compp);
|
||||
}
|
||||
else if (exp1Type == NSConstantValueExpressionType && exp2Type == NSKeyPathExpressionType) {
|
||||
// comparing value to keypath
|
||||
update_query_with_value_expression(schema, objectSchema, query, compp.rightExpression.keyPath,
|
||||
compp.leftExpression.constantValue, compp);
|
||||
}
|
||||
//if (exp1Type == NSKeyPathExpressionType && exp2Type == NSKeyPathExpressionType) {
|
||||
// both expression are KeyPaths
|
||||
// update_query_with_column_expression(objectSchema, query, compp.leftExpression.keyPath,
|
||||
// compp.rightExpression.keyPath, compp);
|
||||
//}
|
||||
else {
|
||||
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
||||
}
|
||||
}
|
||||
else if ([predicate isEqual:[NSPredicate predicateWithValue:YES]]) {
|
||||
query.and_query(new TrueExpression);
|
||||
} else if ([predicate isEqual:[NSPredicate predicateWithValue:NO]]) {
|
||||
query.and_query(new FalseExpression);
|
||||
}
|
||||
else {
|
||||
// invalid predicate type
|
||||
throw std::runtime_error("Only support compound, comparison, and constant predicates");
|
||||
}
|
||||
}
|
||||
|
||||
void RLMUpdateQueryWithPredicate(realm::Query *query, NSPredicate *predicate, realm::Schema &schema, realm::ObjectSchema &objectSchema)
|
||||
{
|
||||
// passing a nil predicate is a no-op
|
||||
if (!predicate) {
|
||||
return;
|
||||
}
|
||||
|
||||
RLMPrecondition([predicate isKindOfClass:NSPredicate.class], @"Invalid argument", @"predicate must be an NSPredicate object");
|
||||
|
||||
update_query_with_predicate(predicate, schema, objectSchema, *query);
|
||||
|
||||
// Test the constructed query in core
|
||||
std::string validateMessage = query->validate();
|
||||
RLMPrecondition(validateMessage.empty(), @"Invalid query", @"%.*s", (int)validateMessage.size(), validateMessage.c_str());
|
||||
}
|
|
@ -76,6 +76,9 @@ namespace realm {
|
|||
static size_t to_object_index(ContextType ctx, SharedRealm realm, ValueType &val, const std::string &type, bool try_update);
|
||||
static ValueType from_object(ContextType ctx, Object);
|
||||
|
||||
// object index for an existing object
|
||||
static size_t to_existing_object_index(ContextType ctx, ValueType &val);
|
||||
|
||||
// list value acessors
|
||||
static size_t list_size(ContextType ctx, ValueType &val);
|
||||
static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#ifndef REALM_OBJECT_STORE_HPP
|
||||
#define REALM_OBJECT_STORE_HPP
|
||||
|
||||
#include "schema.hpp"
|
||||
#include "object_schema.hpp"
|
||||
#include "property.hpp"
|
||||
|
||||
|
@ -29,7 +30,6 @@
|
|||
|
||||
namespace realm {
|
||||
class ObjectSchemaValidationException;
|
||||
class Schema;
|
||||
|
||||
class ObjectStore {
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,330 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <pegtl.hh>
|
||||
#include <pegtl/analyze.hh>
|
||||
#include <pegtl/trace.hh>
|
||||
|
||||
using namespace pegtl;
|
||||
|
||||
namespace realm {
|
||||
namespace parser {
|
||||
|
||||
// strings
|
||||
struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {};
|
||||
struct escaped_char : one< '"', '\'', '\\', '/', 'b', 'f', 'n', 'r', 't', '0' > {};
|
||||
struct escaped : sor< escaped_char, unicode > {};
|
||||
struct unescaped : utf8::range< 0x20, 0x10FFFF > {};
|
||||
struct chars : if_then_else< one< '\\' >, must< escaped >, unescaped > {};
|
||||
struct dq_string_content : until< at< one< '"' > >, must< chars > > {};
|
||||
struct dq_string : seq< one< '"' >, must< dq_string_content >, any > {};
|
||||
|
||||
struct sq_string_content : until< at< one< '\'' > >, must< chars > > {};
|
||||
struct sq_string : seq< one< '\'' >, must< sq_string_content >, any > {};
|
||||
|
||||
// numbers
|
||||
struct minus : opt< one< '-' > > {};
|
||||
struct dot : one< '.' > {};
|
||||
|
||||
struct float_num : sor<
|
||||
seq< plus< digit >, dot, star< digit > >,
|
||||
seq< star< digit >, dot, plus< digit > >
|
||||
> {};
|
||||
struct hex_num : seq< one< '0' >, one< 'x', 'X' >, plus< xdigit > > {};
|
||||
struct int_num : plus< digit > {};
|
||||
|
||||
struct number : seq< minus, sor< float_num, hex_num, int_num > > {};
|
||||
|
||||
struct true_value : pegtl_istring_t("true") {};
|
||||
struct false_value : pegtl_istring_t("false") {};
|
||||
|
||||
// key paths
|
||||
struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {};
|
||||
|
||||
// argument
|
||||
struct argument_index : plus< digit > {};
|
||||
struct argument : seq< one< '$' >, must< argument_index > > {};
|
||||
|
||||
// expressions and operators
|
||||
struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {};
|
||||
|
||||
struct eq : sor< two< '=' >, one< '=' > > {};
|
||||
struct noteq : pegtl::string< '!', '=' > {};
|
||||
struct lteq : pegtl::string< '<', '=' > {};
|
||||
struct lt : one< '<' > {};
|
||||
struct gteq : pegtl::string< '>', '=' > {};
|
||||
struct gt : one< '>' > {};
|
||||
struct contains : pegtl_istring_t("contains") {};
|
||||
struct begins : pegtl_istring_t("beginswith") {};
|
||||
struct ends : pegtl_istring_t("endswith") {};
|
||||
|
||||
template<typename A, typename B>
|
||||
struct pad_plus : seq< plus< B >, A, plus< B > > {};
|
||||
|
||||
struct padded_oper : pad_plus< sor< contains, begins, ends >, blank > {};
|
||||
struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {};
|
||||
|
||||
// predicates
|
||||
struct comparison_pred : seq< expr, sor< padded_oper, symbolic_oper >, expr > {};
|
||||
|
||||
struct pred;
|
||||
struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {};
|
||||
struct true_pred : pegtl_istring_t("truepredicate") {};
|
||||
struct false_pred : pegtl_istring_t("falsepredicate") {};
|
||||
|
||||
struct not_pre : seq< sor< one< '!' >, pegtl_istring_t("not") > > {};
|
||||
struct atom_pred : seq< opt< not_pre >, pad< sor< group_pred, true_pred, false_pred, comparison_pred >, blank > > {};
|
||||
|
||||
struct and_op : pad< sor< two< '&' >, pegtl_istring_t("and") >, blank > {};
|
||||
struct or_op : pad< sor< two< '|' >, pegtl_istring_t("or") >, blank > {};
|
||||
|
||||
struct or_ext : if_must< or_op, pred > {};
|
||||
struct and_ext : if_must< and_op, pred > {};
|
||||
struct and_pred : seq< atom_pred, star< and_ext > > {};
|
||||
|
||||
struct pred : seq< and_pred, star< or_ext > > {};
|
||||
|
||||
// state
|
||||
struct ParserState
|
||||
{
|
||||
std::vector<Predicate *> predicate_stack;
|
||||
Predicate ¤t() {
|
||||
return *predicate_stack.back();
|
||||
}
|
||||
|
||||
bool negate_next = false;
|
||||
|
||||
void addExpression(Expression && exp)
|
||||
{
|
||||
if (current().type == Predicate::Type::Comparison) {
|
||||
current().cmpr.expr[1] = std::move(exp);
|
||||
predicate_stack.pop_back();
|
||||
}
|
||||
else {
|
||||
Predicate p(Predicate::Type::Comparison);
|
||||
p.cmpr.expr[0] = std::move(exp);
|
||||
if (negate_next) {
|
||||
p.negate = true;
|
||||
negate_next = false;
|
||||
}
|
||||
current().cpnd.sub_predicates.emplace_back(std::move(p));
|
||||
predicate_stack.push_back(¤t().cpnd.sub_predicates.back());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// rules
|
||||
template< typename Rule >
|
||||
struct action : nothing< Rule > {};
|
||||
|
||||
#ifdef REALM_PARSER_PRINT_TOKENS
|
||||
#define DEBUG_PRINT_TOKEN(string) std::cout << string << std::endl
|
||||
#else
|
||||
#define DEBUG_PRINT_TOKEN(string)
|
||||
#endif
|
||||
|
||||
template<> struct action< and_ext >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN("<and>");
|
||||
|
||||
// if we were put into an OR group we need to rearrange
|
||||
auto ¤t = state.current();
|
||||
if (current.type == Predicate::Type::Or) {
|
||||
auto &sub_preds = current.cpnd.sub_predicates;
|
||||
auto &second_last = sub_preds[sub_preds.size()-2];
|
||||
if (second_last.type == Predicate::Type::And) {
|
||||
// if we are in an OR group and second to last predicate group is
|
||||
// an AND group then move the last predicate inside
|
||||
second_last.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
|
||||
sub_preds.pop_back();
|
||||
}
|
||||
else {
|
||||
// otherwise combine last two into a new AND group
|
||||
Predicate pred(Predicate::Type::And);
|
||||
pred.cpnd.sub_predicates.emplace_back(std::move(second_last));
|
||||
pred.cpnd.sub_predicates.emplace_back(std::move(sub_preds.back()));
|
||||
sub_preds.pop_back();
|
||||
sub_preds.pop_back();
|
||||
sub_preds.push_back(std::move(pred));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct action< or_ext >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN("<or>");
|
||||
|
||||
// if already an OR group do nothing
|
||||
auto ¤t = state.current();
|
||||
if (current.type == Predicate::Type::Or) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if only two predicates in the group, then convert to OR
|
||||
auto &sub_preds = state.current().cpnd.sub_predicates;
|
||||
if (sub_preds.size()) {
|
||||
current.type = Predicate::Type::Or;
|
||||
return;
|
||||
}
|
||||
|
||||
// split the current group into to groups which are ORed together
|
||||
Predicate pred1(Predicate::Type::And), pred2(Predicate::Type::And);
|
||||
pred1.cpnd.sub_predicates.insert(sub_preds.begin(), sub_preds.back());
|
||||
pred2.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
|
||||
|
||||
current.type = Predicate::Type::Or;
|
||||
sub_preds.clear();
|
||||
sub_preds.emplace_back(std::move(pred1));
|
||||
sub_preds.emplace_back(std::move(pred2));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define EXPRESSION_ACTION(rule, type) \
|
||||
template<> struct action< rule > { \
|
||||
static void apply( const input & in, ParserState & state ) { \
|
||||
DEBUG_PRINT_TOKEN(in.string()); \
|
||||
state.addExpression(Expression(type, in.string())); }};
|
||||
|
||||
EXPRESSION_ACTION(dq_string_content, Expression::Type::String)
|
||||
EXPRESSION_ACTION(sq_string_content, Expression::Type::String)
|
||||
EXPRESSION_ACTION(key_path, Expression::Type::KeyPath)
|
||||
EXPRESSION_ACTION(number, Expression::Type::Number)
|
||||
EXPRESSION_ACTION(true_value, Expression::Type::True)
|
||||
EXPRESSION_ACTION(false_value, Expression::Type::False)
|
||||
EXPRESSION_ACTION(argument_index, Expression::Type::Argument)
|
||||
|
||||
|
||||
template<> struct action< true_pred >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN(in.string());
|
||||
state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::True);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct action< false_pred >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN(in.string());
|
||||
state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::False);
|
||||
}
|
||||
};
|
||||
|
||||
#define OPERATOR_ACTION(rule, oper) \
|
||||
template<> struct action< rule > { \
|
||||
static void apply( const input & in, ParserState & state ) { \
|
||||
DEBUG_PRINT_TOKEN(in.string()); \
|
||||
state.current().cmpr.op = oper; }};
|
||||
|
||||
OPERATOR_ACTION(eq, Predicate::Operator::Equal)
|
||||
OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual)
|
||||
OPERATOR_ACTION(gteq, Predicate::Operator::GreaterThanOrEqual)
|
||||
OPERATOR_ACTION(gt, Predicate::Operator::GreaterThan)
|
||||
OPERATOR_ACTION(lteq, Predicate::Operator::LessThanOrEqual)
|
||||
OPERATOR_ACTION(lt, Predicate::Operator::LessThan)
|
||||
OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith)
|
||||
OPERATOR_ACTION(ends, Predicate::Operator::EndsWith)
|
||||
OPERATOR_ACTION(contains, Predicate::Operator::Contains)
|
||||
|
||||
template<> struct action< one< '(' > >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN("<begin_group>");
|
||||
|
||||
Predicate group(Predicate::Type::And);
|
||||
if (state.negate_next) {
|
||||
group.negate = true;
|
||||
state.negate_next = false;
|
||||
}
|
||||
|
||||
state.current().cpnd.sub_predicates.emplace_back(std::move(group));
|
||||
state.predicate_stack.push_back(&state.current().cpnd.sub_predicates.back());
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct action< group_pred >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN("<end_group>");
|
||||
state.predicate_stack.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct action< not_pre >
|
||||
{
|
||||
static void apply( const input & in, ParserState & state )
|
||||
{
|
||||
DEBUG_PRINT_TOKEN("<not>");
|
||||
state.negate_next = true;
|
||||
}
|
||||
};
|
||||
|
||||
template< typename Rule >
|
||||
struct error_message_control : pegtl::normal< Rule >
|
||||
{
|
||||
static const std::string error_message;
|
||||
|
||||
template< typename Input, typename ... States >
|
||||
static void raise( const Input & in, States && ... )
|
||||
{
|
||||
throw pegtl::parse_error( error_message, in );
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
const std::string error_message_control< chars >::error_message = "Invalid characters in string constant.";
|
||||
|
||||
template< typename Rule>
|
||||
const std::string error_message_control< Rule >::error_message = "Invalid predicate.";
|
||||
|
||||
Predicate parse(const std::string &query)
|
||||
{
|
||||
Predicate out_predicate(Predicate::Type::And);
|
||||
|
||||
ParserState state;
|
||||
state.predicate_stack.push_back(&out_predicate);
|
||||
|
||||
pegtl::parse< must< pred, eof >, action, error_message_control >(query, query, state);
|
||||
if (out_predicate.type == Predicate::Type::And && out_predicate.cpnd.sub_predicates.size() == 1) {
|
||||
return std::move(out_predicate.cpnd.sub_predicates.back());
|
||||
}
|
||||
return std::move(out_predicate);
|
||||
}
|
||||
|
||||
void analyzeGrammar()
|
||||
{
|
||||
analyze<pred>();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef REALM_PARSER_HPP
|
||||
#define REALM_PARSER_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace realm {
|
||||
class Schema;
|
||||
|
||||
namespace parser {
|
||||
struct Expression
|
||||
{
|
||||
enum class Type { Number, String, KeyPath, Argument, True, False } type;
|
||||
std::string s;
|
||||
Expression() {}
|
||||
Expression(Type t, std::string s) : type(t), s(s) {}
|
||||
};
|
||||
|
||||
struct Predicate
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
Comparison,
|
||||
Or,
|
||||
And,
|
||||
True,
|
||||
False
|
||||
} type = Type::And;
|
||||
|
||||
enum class Operator
|
||||
{
|
||||
None,
|
||||
Equal,
|
||||
NotEqual,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
BeginsWith,
|
||||
EndsWith,
|
||||
Contains
|
||||
};
|
||||
|
||||
struct Comparison
|
||||
{
|
||||
Operator op = Operator::None;
|
||||
Expression expr[2];
|
||||
~Comparison() {}
|
||||
};
|
||||
|
||||
struct Compound
|
||||
{
|
||||
std::vector<Predicate> sub_predicates;
|
||||
};
|
||||
|
||||
Comparison cmpr;
|
||||
Compound cpnd;
|
||||
|
||||
bool negate = false;
|
||||
|
||||
Predicate(Type t) : type(t) {}
|
||||
};
|
||||
|
||||
Predicate parse(const std::string &query);
|
||||
|
||||
void analyzeGrammar();
|
||||
bool testGrammar();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // REALM_PARSER_HPP
|
|
@ -0,0 +1,250 @@
|
|||
{
|
||||
|
||||
"dateTests" : {
|
||||
"schema" : [{
|
||||
"name": "DateObject",
|
||||
"properties": [{ "name": "date", "type": "date" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "DateObject", "value": [10000] },
|
||||
{ "type": "DateObject", "value": [10001] },
|
||||
{ "type": "DateObject", "value": [10002] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 2, "DateObject", "date < $0", [2, "date"]],
|
||||
["QueryCount", 3, "DateObject", "date <= $0", [2, "date"]],
|
||||
["QueryCount", 2, "DateObject", "date > $0", [0, "date"]],
|
||||
["QueryCount", 3, "DateObject", "date >= $0", [0, "date"]],
|
||||
["QueryCount", 1, "DateObject", "date == $0", [0, "date"]],
|
||||
["QueryCount", 2, "DateObject", "date != $0", [0, "date"]],
|
||||
|
||||
["QueryThrows", "DateObject", "date == 'not a date'"],
|
||||
["QueryThrows", "DateObject", "date == 1"],
|
||||
["QueryThrows", "DateObject", "date == $0", 1]
|
||||
]
|
||||
},
|
||||
|
||||
"boolTests" : {
|
||||
"schema" : [{
|
||||
"name": "BoolObject",
|
||||
"properties": [{ "name": "boolCol", "type": "bool" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "BoolObject", "value": [false] },
|
||||
{ "type": "BoolObject", "value": [true] },
|
||||
{ "type": "BoolObject", "value": [true] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 2, "BoolObject", "boolCol == true"],
|
||||
["QueryCount", 1, "BoolObject", "boolCol==false"],
|
||||
["QueryCount", 1, "BoolObject", "boolCol != true"],
|
||||
["QueryCount", 2, "BoolObject", "true == boolCol"],
|
||||
["QueryCount", 2, "BoolObject", "boolCol == TRUE"],
|
||||
["QueryCount", 1, "BoolObject", "boolCol == FALSE"],
|
||||
["QueryCount", 2, "BoolObject", "boolCol == $0", true],
|
||||
["QueryCount", 1, "BoolObject", "boolCol == $0", false],
|
||||
["QueryCount", 0, "BoolObject", "boolCol == true && boolCol == false"],
|
||||
["QueryCount", 3, "BoolObject", "boolCol == true || boolCol == false"],
|
||||
|
||||
["QueryThrows", "BoolObject", "boolCol == 0"],
|
||||
["QueryThrows", "BoolObject", "boolCol == 1"],
|
||||
["QueryThrows", "BoolObject", "boolCol == 'not a bool'"],
|
||||
["QueryThrows", "BoolObject", "boolCol == $0", "not a bool"],
|
||||
["QueryThrows", "BoolObject", "boolCol > true"],
|
||||
["QueryThrows", "BoolObject", "boolCol >= true"],
|
||||
["QueryThrows", "BoolObject", "boolCol < true"],
|
||||
["QueryThrows", "BoolObject", "boolCol <= true"],
|
||||
["QueryThrows", "BoolObject", "boolCol BEGINSWITH true"],
|
||||
["QueryThrows", "BoolObject", "boolCol CONTAINS true"],
|
||||
["QueryThrows", "BoolObject", "boolCol ENDSWITH true"]
|
||||
]
|
||||
},
|
||||
|
||||
"intTests" : {
|
||||
"schema" : [{
|
||||
"name": "IntObject",
|
||||
"properties": [{ "name": "intCol", "type": "int" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "IntObject", "value": [-1] },
|
||||
{ "type": "IntObject", "value": [0] },
|
||||
{ "type": "IntObject", "value": [100] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 1, "IntObject", "intCol == -1"],
|
||||
["QueryCount", 1, "IntObject", "intCol==0"],
|
||||
["QueryCount", 0, "IntObject", "1 == intCol"],
|
||||
["QueryCount", 2, "IntObject", "intCol != 0"],
|
||||
["QueryCount", 2, "IntObject", "intCol > -1"],
|
||||
["QueryCount", 3, "IntObject", "intCol >= -1"],
|
||||
["QueryCount", 2, "IntObject", "intCol < 100"],
|
||||
["QueryCount", 3, "IntObject", "intCol <= 100"],
|
||||
["QueryCount", 1, "IntObject", "intCol > 0x1F"],
|
||||
["QueryCount", 1, "IntObject", "intCol == $0", 100],
|
||||
|
||||
["QueryThrows", "IntObject", "intCol == 'not an int'"],
|
||||
["QueryThrows", "IntObject", "intCol == true"],
|
||||
["QueryThrows", "IntObject", "intCol == $0", "not an int"],
|
||||
["QueryThrows", "IntObject", "intCol BEGINSWITH 1"],
|
||||
["QueryThrows", "IntObject", "intCol CONTAINS 1"],
|
||||
["QueryThrows", "IntObject", "intCol ENDSWITH 1"]
|
||||
]
|
||||
},
|
||||
|
||||
"floatTests" : {
|
||||
"schema" : [{
|
||||
"name": "FloatObject",
|
||||
"properties": [{ "name": "floatCol", "type": "float" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "FloatObject", "value": [-1.001] },
|
||||
{ "type": "FloatObject", "value": [0.0] },
|
||||
{ "type": "FloatObject", "value": [100.2] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 1, "FloatObject", "floatCol == -1.001"],
|
||||
["QueryCount", 1, "FloatObject", "floatCol = 0"],
|
||||
["QueryCount", 0, "FloatObject", "1 == floatCol"],
|
||||
["QueryCount", 2, "FloatObject", "floatCol != 0"],
|
||||
["QueryCount", 2, "FloatObject", "floatCol > -1.001"],
|
||||
["QueryCount", 3, "FloatObject", "floatCol >= -1.001"],
|
||||
["QueryCount", 2, "FloatObject", "floatCol < 100.2"],
|
||||
["QueryCount", 3, "FloatObject", "floatCol <= 100.2"],
|
||||
["QueryCount", 1, "FloatObject", "floatCol > 0x1F"],
|
||||
["QueryCount", 1, "FloatObject", "floatCol == $0", 100.2],
|
||||
|
||||
["QueryThrows", "FloatObject", "floatCol == 'not a float'"],
|
||||
["QueryThrows", "FloatObject", "floatCol == true"],
|
||||
["QueryThrows", "FloatObject", "floatCol == $0", "not a float"],
|
||||
["QueryThrows", "FloatObject", "floatCol BEGINSWITH 1"],
|
||||
["QueryThrows", "FloatObject", "floatCol CONTAINS 1"],
|
||||
["QueryThrows", "FloatObject", "floatCol ENDSWITH 1"],
|
||||
|
||||
["Disabled", "QueryThrows", "FloatObject", "floatCol = 3.5e+38"],
|
||||
["Disabled", "QueryThrows", "FloatObject", "floatCol = -3.5e+38"]
|
||||
]
|
||||
},
|
||||
|
||||
"doubleTests" : {
|
||||
"schema" : [{
|
||||
"name": "DoubleObject",
|
||||
"properties": [{ "name": "doubleCol", "type": "double" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "DoubleObject", "value": [-1.001] },
|
||||
{ "type": "DoubleObject", "value": [0.0] },
|
||||
{ "type": "DoubleObject", "value": [100.2] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 1, "DoubleObject", "doubleCol == -1.001"],
|
||||
["QueryCount", 1, "DoubleObject", "doubleCol == 0"],
|
||||
["QueryCount", 0, "DoubleObject", "1 == doubleCol"],
|
||||
["QueryCount", 2, "DoubleObject", "doubleCol != 0"],
|
||||
["QueryCount", 2, "DoubleObject", "doubleCol > -1.001"],
|
||||
["QueryCount", 3, "DoubleObject", "doubleCol >= -1.001"],
|
||||
["QueryCount", 2, "DoubleObject", "doubleCol < 100.2"],
|
||||
["QueryCount", 3, "DoubleObject", "doubleCol <= 100.2"],
|
||||
["QueryCount", 1, "DoubleObject", "doubleCol > 0x1F"],
|
||||
["QueryCount", 1, "DoubleObject", "doubleCol == $0", 100.2],
|
||||
|
||||
["QueryThrows", "DoubleObject", "doubleCol == 'not a double'"],
|
||||
["QueryThrows", "DoubleObject", "doubleCol == true"],
|
||||
["QueryThrows", "DoubleObject", "doubleCol == $0", "not a double"],
|
||||
["QueryThrows", "DoubleObject", "doubleCol BEGINSWITH 1"],
|
||||
["QueryThrows", "DoubleObject", "doubleCol CONTAINS 1"],
|
||||
["QueryThrows", "DoubleObject", "doubleCol ENDSWITH 1"]
|
||||
]
|
||||
},
|
||||
|
||||
"stringTests" : {
|
||||
"schema" : [{
|
||||
"name": "StringObject",
|
||||
"properties": [{ "name": "stringCol", "type": "string" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "StringObject", "value": ["A"] },
|
||||
{ "type": "StringObject", "value": ["a"] },
|
||||
{ "type": "StringObject", "value": ["a"] },
|
||||
{ "type": "StringObject", "value": ["C"] },
|
||||
{ "type": "StringObject", "value": ["c"] },
|
||||
{ "type": "StringObject", "value": ["abc"] },
|
||||
{ "type": "StringObject", "value": ["ABC"] },
|
||||
{ "type": "StringObject", "value": [""] },
|
||||
{ "type": "StringObject", "value": ["\\\"\\n\\0\\r\\\\'"] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 2, "StringObject", "stringCol == 'a'"],
|
||||
["QueryCount", 1, "StringObject", "'c' == stringCol"],
|
||||
["QueryCount", 2, "StringObject", "stringCol == \"a\""],
|
||||
["QueryCount", 1, "StringObject", "stringCol=='abc'"],
|
||||
["QueryCount", 1, "StringObject", "stringCol == ''"],
|
||||
["QueryCount", 8, "StringObject", "stringCol != ''"],
|
||||
["QueryCount", 1, "StringObject", "stringCol == \"\\\"\\n\\0\\r\\\\'\""],
|
||||
["QueryCount", 3, "StringObject", "stringCol BEGINSWITH 'a'"],
|
||||
["QueryCount", 1, "StringObject", "stringCol beginswith 'ab'"],
|
||||
["QueryCount", 0, "StringObject", "stringCol BEGINSWITH 'abcd'"],
|
||||
["QueryCount", 2, "StringObject", "stringCol BEGINSWITH 'A'"],
|
||||
["QueryCount", 2, "StringObject", "stringCol ENDSWITH 'c'"],
|
||||
["QueryCount", 1, "StringObject", "stringCol endswith 'bc'"],
|
||||
["QueryCount", 9, "StringObject", "stringCol ENDSWITH ''"],
|
||||
["QueryCount", 1, "StringObject", "stringCol CONTAINS 'b'"],
|
||||
["QueryCount", 2, "StringObject", "stringCol contains 'c'"],
|
||||
["QueryCount", 9, "StringObject", "stringCol CONTAINS ''"],
|
||||
["QueryCount", 2, "StringObject", "stringCol == $0", "a"],
|
||||
["QueryCount", 2, "StringObject", "stringCol ENDSWITH $0", "c"],
|
||||
|
||||
["QueryThrows", "StringObject", "stringCol == true"],
|
||||
["QueryThrows", "StringObject", "stringCol == 123"],
|
||||
["QueryThrows", "StringObject", "stringCol CONTAINS $0", 1],
|
||||
|
||||
["Disabled", "QueryCount", 3, "StringObject", "stringCol ==[c] 'a'"],
|
||||
["Disabled", "QueryCount", 5, "StringObject", "stringCol BEGINSWITH[c] 'A'"],
|
||||
["Disabled", "QueryCount", 4, "StringObject", "stringCol ENDSWITH[c] 'c'"],
|
||||
["Disabled", "QueryCount", 2, "StringObject", "stringCol CONTAINS[c] 'B'"]
|
||||
]
|
||||
},
|
||||
|
||||
"binaryTests" : {
|
||||
"schema" : [{
|
||||
"name": "BinaryObject",
|
||||
"properties": [{ "name": "binaryCol", "type": "data" }]
|
||||
}],
|
||||
"objects": [
|
||||
{ "type": "BinaryObject", "value": [[1, 100, 233, 255, 0]] },
|
||||
{ "type": "BinaryObject", "value": [[1, 100]] },
|
||||
{ "type": "BinaryObject", "value": [[100]] },
|
||||
{ "type": "BinaryObject", "value": [[]] },
|
||||
{ "type": "BinaryObject", "value": [[255, 0]] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 1, "BinaryObject", "binaryCol == $0", [1, "binaryCol"]],
|
||||
["QueryCount", 1, "BinaryObject", "$0 == binaryCol", [2, "binaryCol"]],
|
||||
["QueryCount", 4, "BinaryObject", "binaryCol != $0", [0, "binaryCol"]],
|
||||
["QueryCount", 1, "BinaryObject", "binaryCol BEGINSWITH $0", [0, "binaryCol"]],
|
||||
["QueryCount", 2, "BinaryObject", "binaryCol BEGINSWITH $0", [1, "binaryCol"]],
|
||||
["QueryCount", 2, "BinaryObject", "binaryCol ENDSWITH $0", [4, "binaryCol"]],
|
||||
["QueryCount", 3, "BinaryObject", "binaryCol CONTAINS $0", [2, "binaryCol"]]
|
||||
]
|
||||
},
|
||||
|
||||
"objectTests" : {
|
||||
"schema" : [
|
||||
{ "name": "IntObject", "properties": [{ "name": "intCol", "type": "int" }] },
|
||||
{ "name": "LinkObject", "properties": [{ "name": "linkCol", "type": "IntObject" }] }
|
||||
],
|
||||
"objects": [
|
||||
{ "type": "LinkObject", "value": [[1]] },
|
||||
{ "type": "LinkObject", "value": [[2]] },
|
||||
{ "type": "LinkObject", "value": [null] }
|
||||
],
|
||||
"tests": [
|
||||
["QueryCount", 1, "LinkObject", "linkCol == $0", [0, "linkCol"]],
|
||||
["QueryCount", 1, "LinkObject", "$0 == linkCol", [1, "linkCol"]],
|
||||
["QueryCount", 2, "LinkObject", "linkCol != $0", [0, "linkCol"]],
|
||||
|
||||
["QueryThrows", "LinkObject", "linkCol > $0", [0, "linkCol"]],
|
||||
["QueryThrows", "LinkObject", "intCol = $0", [0, "linkCol"]]
|
||||
]
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,496 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "query_builder.hpp"
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <realm.hpp>
|
||||
#include "object_store.hpp"
|
||||
#include "schema.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace realm {
|
||||
namespace query_builder {
|
||||
using namespace parser;
|
||||
|
||||
// check a precondition and throw an exception if it is not met
|
||||
// this should be used iff the condition being false indicates a bug in the caller
|
||||
// of the function checking its preconditions
|
||||
#define precondition(condition, message) if (!__builtin_expect(condition, 1)) { throw std::runtime_error(message); }
|
||||
|
||||
// FIXME: TrueExpression and FalseExpression should be supported by core in some way
|
||||
struct TrueExpression : realm::Expression {
|
||||
size_t find_first(size_t start, size_t end) const override
|
||||
{
|
||||
if (start != end)
|
||||
return start;
|
||||
|
||||
return not_found;
|
||||
}
|
||||
void set_table() override {}
|
||||
const Table* get_table() const override { return nullptr; }
|
||||
};
|
||||
|
||||
struct FalseExpression : realm::Expression {
|
||||
size_t find_first(size_t, size_t) const override { return not_found; }
|
||||
void set_table() override {}
|
||||
const Table* get_table() const override { return nullptr; }
|
||||
};
|
||||
|
||||
using KeyPath = std::vector<std::string>;
|
||||
KeyPath key_path_from_string(const std::string &s) {
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
KeyPath key_path;
|
||||
while (std::getline(ss, item, '.')) {
|
||||
key_path.push_back(item);
|
||||
}
|
||||
return key_path;
|
||||
}
|
||||
|
||||
struct PropertyExpression
|
||||
{
|
||||
Property *prop = nullptr;
|
||||
std::vector<size_t> indexes;
|
||||
std::function<Table *()> table_getter;
|
||||
|
||||
PropertyExpression(Query &query, Schema &schema, Schema::iterator desc, const std::string &key_path_string)
|
||||
{
|
||||
KeyPath key_path = key_path_from_string(key_path_string);
|
||||
for (size_t index = 0; index < key_path.size(); index++) {
|
||||
if (prop) {
|
||||
precondition(prop->type == PropertyTypeObject || prop->type == PropertyTypeArray,
|
||||
(std::string)"Property '" + key_path[index] + "' is not a link in object of type '" + desc->name + "'");
|
||||
indexes.push_back(prop->table_column);
|
||||
|
||||
}
|
||||
prop = desc->property_for_name(key_path[index]);
|
||||
precondition(prop != nullptr, "No property '" + key_path[index] + "' on object of type '" + desc->name + "'");
|
||||
|
||||
if (prop->object_type.size()) {
|
||||
desc = schema.find(prop->object_type);
|
||||
}
|
||||
}
|
||||
|
||||
table_getter = [&] {
|
||||
TableRef& tbl = query.get_table();
|
||||
for (size_t col : indexes) {
|
||||
tbl->link(col); // mutates m_link_chain on table
|
||||
}
|
||||
return tbl.get();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// add a clause for numeric constraints based on operator type
|
||||
template <typename A, typename B>
|
||||
void add_numeric_constraint_to_query(Query& query,
|
||||
Predicate::Operator operatorType,
|
||||
A lhs,
|
||||
B rhs)
|
||||
{
|
||||
switch (operatorType) {
|
||||
case Predicate::Operator::LessThan:
|
||||
query.and_query(lhs < rhs);
|
||||
break;
|
||||
case Predicate::Operator::LessThanOrEqual:
|
||||
query.and_query(lhs <= rhs);
|
||||
break;
|
||||
case Predicate::Operator::GreaterThan:
|
||||
query.and_query(lhs > rhs);
|
||||
break;
|
||||
case Predicate::Operator::GreaterThanOrEqual:
|
||||
query.and_query(lhs >= rhs);
|
||||
break;
|
||||
case Predicate::Operator::Equal:
|
||||
query.and_query(lhs == rhs);
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.and_query(lhs != rhs);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported operator for numeric queries.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void add_bool_constraint_to_query(Query &query, Predicate::Operator operatorType, A lhs, B rhs) {
|
||||
switch (operatorType) {
|
||||
case Predicate::Operator::Equal:
|
||||
query.and_query(lhs == rhs);
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.and_query(lhs != rhs);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported operator for numeric queries.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_string_constraint_to_query(Query &query,
|
||||
Predicate::Operator op,
|
||||
Columns<String> &&column,
|
||||
std::string &&value) {
|
||||
bool case_sensitive = true;
|
||||
switch (op) {
|
||||
case Predicate::Operator::BeginsWith:
|
||||
query.and_query(column.begins_with(value, case_sensitive));
|
||||
break;
|
||||
case Predicate::Operator::EndsWith:
|
||||
query.and_query(column.ends_with(value, case_sensitive));
|
||||
break;
|
||||
case Predicate::Operator::Contains:
|
||||
query.and_query(column.contains(value, case_sensitive));
|
||||
break;
|
||||
case Predicate::Operator::Equal:
|
||||
query.and_query(column.equal(value, case_sensitive));
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.and_query(column.not_equal(value, case_sensitive));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported operator for string queries.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_string_constraint_to_query(realm::Query &query,
|
||||
Predicate::Operator op,
|
||||
std::string &&value,
|
||||
Columns<String> &&column) {
|
||||
bool case_sensitive = true;
|
||||
switch (op) {
|
||||
case Predicate::Operator::Equal:
|
||||
query.and_query(column.equal(value, case_sensitive));
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.and_query(column.not_equal(value, case_sensitive));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Substring comparison not supported for keypath substrings.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_binary_constraint_to_query(Query &query,
|
||||
Predicate::Operator op,
|
||||
Columns<Binary> &&column,
|
||||
std::string &&value) {
|
||||
switch (op) {
|
||||
case Predicate::Operator::BeginsWith:
|
||||
query.begins_with(column.m_column, BinaryData(value));
|
||||
break;
|
||||
case Predicate::Operator::EndsWith:
|
||||
query.ends_with(column.m_column, BinaryData(value));
|
||||
break;
|
||||
case Predicate::Operator::Contains:
|
||||
query.contains(column.m_column, BinaryData(value));
|
||||
break;
|
||||
case Predicate::Operator::Equal:
|
||||
query.equal(column.m_column, BinaryData(value));
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.not_equal(column.m_column, BinaryData(value));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported operator for binary queries.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_binary_constraint_to_query(realm::Query &query,
|
||||
Predicate::Operator op,
|
||||
std::string value,
|
||||
Columns<Binary> &&column) {
|
||||
switch (op) {
|
||||
case Predicate::Operator::Equal:
|
||||
query.equal(column.m_column, BinaryData(value));
|
||||
break;
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.not_equal(column.m_column, BinaryData(value));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Substring comparison not supported for keypath substrings.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_link_constraint_to_query(realm::Query &query,
|
||||
Predicate::Operator op,
|
||||
PropertyExpression &prop_expr,
|
||||
size_t row_index) {
|
||||
precondition(prop_expr.indexes.empty(), "KeyPath queries not supported for object comparisons.");
|
||||
switch (op) {
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.Not();
|
||||
case Predicate::Operator::Equal:
|
||||
query.links_to(prop_expr.prop->table_column, row_index);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Only 'equal' and 'not equal' operators supported for object comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
void add_link_constraint_to_query(realm::Query &query,
|
||||
Predicate::Operator op,
|
||||
PropertyExpression &prop_expr,
|
||||
realm::null) {
|
||||
precondition(prop_expr.indexes.empty(), "KeyPath queries not supported for object comparisons.");
|
||||
switch (op) {
|
||||
case Predicate::Operator::NotEqual:
|
||||
query.Not();
|
||||
case Predicate::Operator::Equal:
|
||||
query.and_query(query.get_table()->column<Link>(prop_expr.prop->table_column).is_null());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Only 'equal' and 'not equal' operators supported for object comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
auto link_argument(PropertyExpression &propExpr, parser::Expression &argExpr, Arguments &args)
|
||||
{
|
||||
return args.object_index_for_argument(std::stoi(argExpr.s));
|
||||
}
|
||||
|
||||
auto link_argument(parser::Expression &argExpr, PropertyExpression &propExpr, Arguments &args)
|
||||
{
|
||||
return args.object_index_for_argument(std::stoi(argExpr.s));
|
||||
}
|
||||
|
||||
|
||||
template <typename RetType, typename TableGetter>
|
||||
struct ColumnGetter {
|
||||
static Columns<RetType> convert(TableGetter&& table, const PropertyExpression & expr, Arguments &args)
|
||||
{
|
||||
return table()->template column<RetType>(expr.prop->table_column);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RequestedType, typename TableGetter>
|
||||
struct ValueGetter;
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<DateTime, TableGetter> {
|
||||
static Int convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type != parser::Expression::Type::Argument) {
|
||||
throw std::runtime_error("You must pass in a date argument to compare");
|
||||
}
|
||||
DateTime dt = args.datetime_for_argument(std::stoi(value.s));
|
||||
return dt.get_datetime();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<bool, TableGetter> {
|
||||
static bool convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.bool_for_argument(std::stoi(value.s));
|
||||
}
|
||||
if (value.type != parser::Expression::Type::True && value.type != parser::Expression::Type::False) {
|
||||
throw std::runtime_error("Attempting to compare bool property to a non-bool value");
|
||||
}
|
||||
return value.type == parser::Expression::Type::True;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<Double, TableGetter> {
|
||||
static Double convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.double_for_argument(std::stoi(value.s));
|
||||
}
|
||||
return std::stod(value.s);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<Float, TableGetter> {
|
||||
static Float convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.float_for_argument(std::stoi(value.s));
|
||||
}
|
||||
return std::stof(value.s);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<Int, TableGetter> {
|
||||
static Int convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.long_for_argument(std::stoi(value.s));
|
||||
}
|
||||
return std::stoll(value.s);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<String, TableGetter> {
|
||||
static std::string convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.string_for_argument(std::stoi(value.s));
|
||||
}
|
||||
if (value.type != parser::Expression::Type::String) {
|
||||
throw std::runtime_error("Attempting to compare String property to a non-String value");
|
||||
}
|
||||
return value.s;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TableGetter>
|
||||
struct ValueGetter<Binary, TableGetter> {
|
||||
static std::string convert(TableGetter&&, const parser::Expression & value, Arguments &args)
|
||||
{
|
||||
if (value.type == parser::Expression::Type::Argument) {
|
||||
return args.binary_for_argument(std::stoi(value.s));
|
||||
}
|
||||
throw std::runtime_error("Binary properties must be compared against a binary argument.");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename RetType, typename Value, typename TableGetter>
|
||||
auto value_of_type_for_query(TableGetter&& tables, Value&& value, Arguments &args)
|
||||
{
|
||||
const bool isColumn = std::is_same<PropertyExpression, typename std::remove_reference<Value>::type>::value;
|
||||
using helper = std::conditional_t<isColumn, ColumnGetter<RetType, TableGetter>, ValueGetter<RetType, TableGetter>>;
|
||||
return helper::convert(std::forward<TableGetter>(tables), std::forward<Value>(value), args);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
void do_add_comparison_to_query(Query &query, Schema &schema, ObjectSchema &object_schema, Predicate::Operator op,
|
||||
PropertyExpression &expr, A &lhs, B &rhs, Arguments &args)
|
||||
{
|
||||
auto type = expr.prop->type;
|
||||
switch (type) {
|
||||
case PropertyTypeBool:
|
||||
add_bool_constraint_to_query(query, op, value_of_type_for_query<bool>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<bool>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeDate:
|
||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<DateTime>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<DateTime>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeDouble:
|
||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Double>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<Double>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeFloat:
|
||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Float>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<Float>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeInt:
|
||||
add_numeric_constraint_to_query(query, op, value_of_type_for_query<Int>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<Int>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeString:
|
||||
add_string_constraint_to_query(query, op, value_of_type_for_query<String>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<String>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeData:
|
||||
add_binary_constraint_to_query(query, op, value_of_type_for_query<Binary>(expr.table_getter, lhs, args),
|
||||
value_of_type_for_query<Binary>(expr.table_getter, rhs, args));
|
||||
break;
|
||||
case PropertyTypeObject:
|
||||
case PropertyTypeArray:
|
||||
add_link_constraint_to_query(query, op, expr, link_argument(lhs, rhs, args));
|
||||
break;
|
||||
default: {
|
||||
throw std::runtime_error((std::string)"Object type " + string_for_property_type(type) + " not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_comparison_to_query(Query &query, Predicate &pred, Arguments &args, Schema &schema, const std::string &type)
|
||||
{
|
||||
Predicate::Comparison &cmpr = pred.cmpr;
|
||||
auto t0 = cmpr.expr[0].type, t1 = cmpr.expr[1].type;
|
||||
auto object_schema = schema.find(type);
|
||||
if (t0 == parser::Expression::Type::KeyPath && t1 != parser::Expression::Type::KeyPath) {
|
||||
PropertyExpression expr(query, schema, object_schema, cmpr.expr[0].s);
|
||||
do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, expr, cmpr.expr[1], args);
|
||||
}
|
||||
else if (t0 != parser::Expression::Type::KeyPath && t1 == parser::Expression::Type::KeyPath) {
|
||||
PropertyExpression expr(query, schema, object_schema, cmpr.expr[1].s);
|
||||
do_add_comparison_to_query(query, schema, *object_schema, cmpr.op, expr, cmpr.expr[0], expr, args);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Predicate expressions must compare a keypath and another keypath or a constant value");
|
||||
}
|
||||
}
|
||||
|
||||
void update_query_with_predicate(Query &query, Predicate &pred, Arguments &arguments, Schema &schema, const std::string &type)
|
||||
{
|
||||
if (pred.negate) {
|
||||
query.Not();
|
||||
}
|
||||
|
||||
switch (pred.type) {
|
||||
case Predicate::Type::And:
|
||||
query.group();
|
||||
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||
update_query_with_predicate(query, sub, arguments, schema, type);
|
||||
}
|
||||
if (!pred.cpnd.sub_predicates.size()) {
|
||||
query.and_query(new TrueExpression);
|
||||
}
|
||||
query.end_group();
|
||||
break;
|
||||
|
||||
case Predicate::Type::Or:
|
||||
query.group();
|
||||
for (auto &sub : pred.cpnd.sub_predicates) {
|
||||
query.Or();
|
||||
update_query_with_predicate(query, sub, arguments, schema, type);
|
||||
}
|
||||
if (!pred.cpnd.sub_predicates.size()) {
|
||||
query.and_query(new FalseExpression);
|
||||
}
|
||||
query.end_group();
|
||||
break;
|
||||
|
||||
case Predicate::Type::Comparison: {
|
||||
add_comparison_to_query(query, pred, arguments, schema, type);
|
||||
break;
|
||||
}
|
||||
case Predicate::Type::True:
|
||||
query.and_query(new TrueExpression);
|
||||
break;
|
||||
|
||||
case Predicate::Type::False:
|
||||
query.and_query(new FalseExpression);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Invalid predicate type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void apply_predicate(Query &query, Predicate &predicate, Arguments &arguments, Schema &schema, std::string objectType)
|
||||
{
|
||||
update_query_with_predicate(query, predicate, arguments, schema, objectType);
|
||||
|
||||
// Test the constructed query in core
|
||||
std::string validateMessage = query.validate();
|
||||
precondition(validateMessage.empty(), validateMessage.c_str());
|
||||
}
|
||||
|
||||
}}
|
|
@ -0,0 +1,80 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 Realm Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef REALM_QUERY_BUILDER_HPP
|
||||
#define REALM_QUERY_BUILDER_HPP
|
||||
|
||||
#include <string>
|
||||
#include "parser.hpp"
|
||||
#include "object_accessor.hpp"
|
||||
|
||||
namespace realm {
|
||||
class Query;
|
||||
class Schema;
|
||||
|
||||
namespace query_builder {
|
||||
class Arguments;
|
||||
|
||||
void apply_predicate(Query &query, parser::Predicate &predicate, Arguments &arguments, Schema &schema, std::string objectType);
|
||||
|
||||
class Arguments
|
||||
{
|
||||
public:
|
||||
virtual bool bool_for_argument(size_t argument_index) = 0;
|
||||
virtual long long long_for_argument(size_t argument_index) = 0;
|
||||
virtual float float_for_argument(size_t argument_index) = 0;
|
||||
virtual double double_for_argument(size_t argument_index) = 0;
|
||||
virtual std::string string_for_argument(size_t argument_index) = 0;
|
||||
virtual std::string binary_for_argument(size_t argument_index) = 0;
|
||||
virtual DateTime datetime_for_argument(size_t argument_index) = 0;
|
||||
virtual size_t object_index_for_argument(size_t argument_index) = 0;
|
||||
virtual bool is_argument_null(size_t argument_index) = 0;
|
||||
};
|
||||
|
||||
template<typename ValueType, typename ContextType>
|
||||
class ArgumentConverter : public Arguments
|
||||
{
|
||||
public:
|
||||
ArgumentConverter(ContextType context, std::vector<ValueType> arguments) : m_arguments(arguments), m_ctx(context) {};
|
||||
|
||||
using Accessor = realm::NativeAccessor<ValueType, ContextType>;
|
||||
virtual bool bool_for_argument(size_t argument_index) { return Accessor::to_bool(m_ctx, argument_at(argument_index)); }
|
||||
virtual long long long_for_argument(size_t argument_index) { return Accessor::to_long(m_ctx, argument_at(argument_index)); }
|
||||
virtual float float_for_argument(size_t argument_index) { return Accessor::to_float(m_ctx, argument_at(argument_index)); }
|
||||
virtual double double_for_argument(size_t argument_index) { return Accessor::to_double(m_ctx, argument_at(argument_index)); }
|
||||
virtual std::string string_for_argument(size_t argument_index) { return Accessor::to_string(m_ctx, argument_at(argument_index)); }
|
||||
virtual std::string binary_for_argument(size_t argument_index) { return Accessor::to_binary(m_ctx, argument_at(argument_index)); }
|
||||
virtual DateTime datetime_for_argument(size_t argument_index) { return Accessor::to_datetime(m_ctx, argument_at(argument_index)); }
|
||||
virtual size_t object_index_for_argument(size_t argument_index) { return Accessor::to_existing_object_index(m_ctx, argument_at(argument_index)); }
|
||||
virtual bool is_argument_null(size_t argument_index) { return Accessor::is_null(m_ctx, argument_at(argument_index)); }
|
||||
|
||||
private:
|
||||
std::vector<ValueType> m_arguments;
|
||||
ContextType m_ctx;
|
||||
|
||||
ValueType &argument_at(size_t index) {
|
||||
if (index >= m_arguments.size()) {
|
||||
throw std::out_of_range((std::string)"Argument index " + std::to_string(index) + " out of range 0.." + std::to_string(m_arguments.size()-1));
|
||||
}
|
||||
return m_arguments[index];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // REALM_QUERY_BUILDER_HPP
|
|
@ -0,0 +1,166 @@
|
|||
|
||||
#include "parser.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
static std::vector<std::string> valid_queries = {
|
||||
// true/false predicates
|
||||
"truepredicate",
|
||||
"falsepredicate",
|
||||
" TRUEPREDICATE ",
|
||||
" FALSEPREDICATE ",
|
||||
|
||||
// characters/strings
|
||||
"\"\" = ''",
|
||||
"'azAZ09/ :()[]{}<>,.^@-+=*&~`' = '\\\" \\' \\\\ \\/ \\b \\f \\n \\r \\t \\0'",
|
||||
"\"azAZ09/\" = \"\\\" \\' \\\\ \\/ \\b \\f \\n \\r \\t \\0\"",
|
||||
"'\\uffFf' = '\\u0020'",
|
||||
"'\\u01111' = 'asdf\\u0111asdf'",
|
||||
|
||||
// expressions (numbers, bools, keypaths, arguments)
|
||||
"-1 = 12",
|
||||
"0 = 001",
|
||||
"0x0 = -0X398235fcAb",
|
||||
"10. = -.034",
|
||||
"10.0 = 5.034",
|
||||
"true = false",
|
||||
"_ = a",
|
||||
"_a = _.aZ",
|
||||
"a09._br.z = __-__.Z-9",
|
||||
"$0 = $19",
|
||||
"$0=$0",
|
||||
|
||||
// operators
|
||||
"0=0",
|
||||
"0 = 0",
|
||||
"0!=0",
|
||||
"0 != 0",
|
||||
"0==0",
|
||||
"0 == 0",
|
||||
"0>0",
|
||||
"0 > 0",
|
||||
"0>=0",
|
||||
"0 >= 0",
|
||||
"0<0",
|
||||
"0 < 0",
|
||||
"0<=0",
|
||||
"0 <= 0",
|
||||
"0 contains 0",
|
||||
"0 BeGiNsWiTh 0",
|
||||
"0 ENDSWITH 0",
|
||||
|
||||
// atoms/groups
|
||||
"(0=0)",
|
||||
"( 0=0 )",
|
||||
"((0=0))",
|
||||
"!0=0",
|
||||
"! 0=0",
|
||||
"!(0=0)",
|
||||
"! (0=0)",
|
||||
"NOT0=0", // keypath NOT0
|
||||
"not 0=0",
|
||||
"NOT(0=0)",
|
||||
"not (0=0)",
|
||||
"NOT (!0=0)",
|
||||
|
||||
// compound
|
||||
"a==a && a==a",
|
||||
"a==a || a==a",
|
||||
"a==a&&a==a||a=a",
|
||||
"a==a and a==a",
|
||||
"a==a OR a==a",
|
||||
"and=='AND'&&'or'=='||'",
|
||||
"and == or && ORE > GRAND",
|
||||
"a=1AND NOTb=2",
|
||||
};
|
||||
|
||||
static std::vector<std::string> invalid_queries = {
|
||||
"predicate",
|
||||
"'\\a' = ''", // invalid escape
|
||||
|
||||
// invalid unicode
|
||||
"'\\u0' = ''",
|
||||
|
||||
// invalid strings
|
||||
"\"' = ''",
|
||||
"\" = ''",
|
||||
"' = ''",
|
||||
|
||||
// expressions
|
||||
"03a = 1",
|
||||
"1..0 = 1",
|
||||
"1.0. = 1",
|
||||
"1-0 = 1",
|
||||
"0x = 1",
|
||||
"truey = false",
|
||||
"- = a",
|
||||
"a..b = a",
|
||||
"a$a = a",
|
||||
"{} = $0",
|
||||
"$-1 = $0",
|
||||
"$a = $0",
|
||||
"$ = $",
|
||||
|
||||
// operators
|
||||
"0===>0",
|
||||
"0 <> 0",
|
||||
"0 contains1",
|
||||
"endswith 0",
|
||||
|
||||
// atoms/groups
|
||||
"0=0)",
|
||||
"(0=0",
|
||||
"(0=0))",
|
||||
"! =0",
|
||||
"NOTNOT(0=0)",
|
||||
"(!!0=0)",
|
||||
"0=0 !",
|
||||
|
||||
// compound
|
||||
"a==a & a==a",
|
||||
"a==a | a==a",
|
||||
"a==a &| a==a",
|
||||
"a==a && OR a==a",
|
||||
"a==aORa==a",
|
||||
//"a=1ANDNOT b=2",
|
||||
|
||||
"truepredicate &&",
|
||||
"truepredicate & truepredicate",
|
||||
};
|
||||
|
||||
namespace realm {
|
||||
namespace parser {
|
||||
|
||||
bool testGrammar()
|
||||
{
|
||||
bool success = true;
|
||||
for (auto &query : valid_queries) {
|
||||
std::cout << "valid query: " << query << std::endl;
|
||||
try {
|
||||
realm::parser::parse(query);
|
||||
} catch (std::exception &ex) {
|
||||
std::cout << "FAILURE - " << ex.what() << std::endl;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &query : invalid_queries) {
|
||||
std::cout << "invalid query: " << query << std::endl;
|
||||
try {
|
||||
realm::parser::parse(query);
|
||||
} catch (std::exception &ex) {
|
||||
// std::cout << "message: " << ex.what() << std::endl;
|
||||
continue;
|
||||
}
|
||||
std::cout << "FAILURE - query should throw an exception" << std::endl;
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# /bin/sh
|
||||
llvm-g++ -std=c++11 -I ../../../vendor/PEGTL/ -o test test.cpp parser.cpp
|
||||
./test
|
|
@ -0,0 +1,19 @@
|
|||
/* Copyright 2015 Realm Inc - All Rights Reserved
|
||||
* Proprietary and Confidential
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <RealmJS/RealmJS.h>
|
||||
#import "parser.hpp"
|
||||
|
||||
@interface GrammerTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation GrammerTests
|
||||
|
||||
- (void)testGrammer {
|
||||
realm::parser::analyzeGrammar();
|
||||
XCTAssertTrue(realm::parser::testGrammar());
|
||||
}
|
||||
|
||||
@end
|
File diff suppressed because it is too large
Load Diff
|
@ -12,5 +12,6 @@
|
|||
- (void)addGlobalModuleObject:(id)object forName:(NSString *)name;
|
||||
|
||||
- (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error;
|
||||
- (JSValue *)loadJSONFromURL:(NSURL *)url error:(NSError **)error;
|
||||
|
||||
@end
|
||||
|
|
|
@ -42,14 +42,18 @@ static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomai
|
|||
NSURL *url = [[NSURL URLWithString:name relativeToURL:baseURL] absoluteURL];
|
||||
BOOL isDirectory;
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory]) {
|
||||
if (!isDirectory) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory] && isDirectory) {
|
||||
url = [url URLByAppendingPathComponent:@"index.js"];
|
||||
} else {
|
||||
url = [url URLByAppendingPathExtension:@"js"];
|
||||
if ([[url pathExtension] isEqualToString:@"json"]) {
|
||||
return [self loadJSONFromURL:url error:error];
|
||||
}
|
||||
else if ([[url pathExtension] length] == 0) {
|
||||
url = [url URLByAppendingPathExtension:@"js"];
|
||||
}
|
||||
else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return [self loadModuleFromURL:url error:error];
|
||||
|
@ -136,6 +140,34 @@ static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomai
|
|||
return exports;
|
||||
}
|
||||
|
||||
- (JSValue *)loadJSONFromURL:(NSURL *)url error:(NSError **)error {
|
||||
url = url.absoluteURL;
|
||||
url = url.standardizedURL ?: url;
|
||||
|
||||
NSString *path = url.path;
|
||||
JSValue *exports = self.modules[path];
|
||||
if (exports) {
|
||||
return exports;
|
||||
}
|
||||
|
||||
NSString *source = [NSString stringWithContentsOfURL:url usedEncoding:NULL error:error];
|
||||
if (!source) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
JSContext *context = self.context;
|
||||
JSValueRef json = JSValueMakeFromJSONString(context.JSGlobalContextRef, JSStringCreateWithUTF8CString(source.UTF8String));
|
||||
if (!json) {
|
||||
*error = [NSError errorWithDomain:RJSModuleLoaderErrorDomain code:1 userInfo:@{
|
||||
NSLocalizedDescriptionKey: @"Invalid JSON"
|
||||
}];
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.modules[path] = [JSValue valueWithJSValueRef:json inContext:context];
|
||||
return self.modules[path];
|
||||
}
|
||||
|
||||
- (JSValue *)loadGlobalModule:(NSString *)name relativeToURL:(NSURL *)baseURL error:(NSError **)error {
|
||||
JSValue *exports = self.globalModules[name];
|
||||
if (exports || !baseURL) {
|
||||
|
|
|
@ -614,7 +614,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "rm -rf ./node_modules/realm ./node_modules/realm-tests\nnpm install realm realm-tests";
|
||||
shellScript = "rm -rf ../node_modules/realm ../node_modules/realm-tests\nnpm install realm realm-tests\ncp ../../../src/object-store/parser/queryTests.json ../node_modules/realm-tests\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
@ -669,10 +669,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
|
@ -691,10 +688,7 @@
|
|||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(inherited)",
|
||||
);
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
INFOPLIST_FILE = ReactTestsTests/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
|
|
|
@ -235,12 +235,12 @@ module.exports = BaseTest.extend({
|
|||
},
|
||||
|
||||
testRealmObjects: function() {
|
||||
var realm = new Realm({schema: [schemas.PersonObject]});
|
||||
var realm = new Realm({schema: [schemas.PersonObject, schemas.DefaultValues, schemas.TestObject]});
|
||||
realm.write(function() {
|
||||
realm.create('PersonObject', ['Ari', 10]);
|
||||
realm.create('PersonObject', ['Tim', 11]);
|
||||
realm.create('PersonObject', ['Ari', 10, false]);
|
||||
realm.create('PersonObject', ['Tim', 11, false]);
|
||||
realm.create('PersonObject', {'name': 'Bjarne', 'age': 12});
|
||||
realm.create('PersonObject', {'name': 'Alex', 'age': 12});
|
||||
realm.create('PersonObject', {'name': 'Alex', 'age': 12, 'married': true});
|
||||
});
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
|
@ -268,7 +268,25 @@ module.exports = BaseTest.extend({
|
|||
TestCase.assertEqual(realm.objects('PersonObject', 'age < 12').length, 2);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'age > 10 && age < 13').length, 3);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'age >= 11 && age < 13').length, 3);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'name = "Tim"').length, 1);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'name = \'Tim\'').length, 1);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'married == TRUE').length, 1);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'married == false').length, 3);
|
||||
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'name = $0', 'Tim').length, 1);
|
||||
TestCase.assertEqual(realm.objects('PersonObject', 'age > $1 && age < $0', 13, 10).length, 3);
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects('PersonObject', 'age > $2 && age < $0', 13, 10)
|
||||
});
|
||||
|
||||
realm.write(function() {
|
||||
realm.create('DefaultValuesObject', {'dateCol': new Date(3)});
|
||||
realm.create('DefaultValuesObject', {'dateCol': new Date(4)});
|
||||
realm.create('DefaultValuesObject', {'dateCol': new Date(5)});
|
||||
});
|
||||
|
||||
TestCase.assertEqual(realm.objects('DefaultValuesObject', 'dateCol > $0', new Date(4)).length, 1);
|
||||
TestCase.assertEqual(realm.objects('DefaultValuesObject', 'dateCol <= $0', new Date(4)).length, 2);
|
||||
},
|
||||
|
||||
testNotifications: function() {
|
||||
|
|
|
@ -24,8 +24,8 @@ module.exports = BaseTest.extend({
|
|||
testResultsSubscript: function() {
|
||||
var realm = new Realm({schema: [schemas.PersonObject]});
|
||||
realm.write(function() {
|
||||
realm.create('PersonObject', ['name1', 1]);
|
||||
realm.create('PersonObject', ['name2', 2]);
|
||||
realm.create('PersonObject', ['name1', 1, false]);
|
||||
realm.create('PersonObject', ['name2', 2, false]);
|
||||
});
|
||||
|
||||
var people = realm.objects('PersonObject');
|
||||
|
|
|
@ -8,6 +8,7 @@ exports.ArrayTests = require('./ArrayTests');
|
|||
exports.ObjectTests = require('./ObjectTests');
|
||||
exports.RealmTests = require('./RealmTests');
|
||||
exports.ResultsTests = require('./ResultsTests');
|
||||
exports.QueryTests = require('./QueryTests');
|
||||
|
||||
var SPECIAL_METHODS = {
|
||||
beforeEach: true,
|
||||
|
|
|
@ -17,8 +17,9 @@ function PersonObject() {}
|
|||
PersonObject.prototype.schema = {
|
||||
name: 'PersonObject',
|
||||
properties: [
|
||||
{name: 'name', type: Realm.Types.STRING},
|
||||
{name: 'age', type: Realm.Types.DOUBLE},
|
||||
{name: 'name', type: Realm.Types.STRING},
|
||||
{name: 'age', type: Realm.Types.DOUBLE},
|
||||
{name: 'married', type: Realm.Types.BOOL, default: false}
|
||||
]
|
||||
};
|
||||
PersonObject.prototype.description = function() {
|
||||
|
@ -102,3 +103,35 @@ exports.DefaultValues = {
|
|||
{name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]},
|
||||
]
|
||||
};
|
||||
|
||||
exports.QueryObject = {
|
||||
name: 'QueryObject',
|
||||
properties: [
|
||||
{name: 'bool1', type: Realm.Types.BOOL},
|
||||
{name: 'bool2', type: Realm.Types.BOOL},
|
||||
{name: 'int1', type: Realm.Types.INT},
|
||||
{name: 'int2', type: Realm.Types.INT},
|
||||
{name: 'float1', type: Realm.Types.FLOAT},
|
||||
{name: 'float2', type: Realm.Types.FLOAT},
|
||||
{name: 'double1', type: Realm.Types.DOUBLE},
|
||||
{name: 'double2', type: Realm.Types.DOUBLE},
|
||||
{name: 'string1', type: Realm.Types.STRING},
|
||||
{name: 'string2', type: Realm.Types.STRING},
|
||||
]
|
||||
};
|
||||
|
||||
exports.NullQueryObject = {
|
||||
name: 'NullQueryObject',
|
||||
properties: [
|
||||
{name: 'bool1', type: Realm.Types.BOOL},
|
||||
{name: 'bool2', type: Realm.Types.BOOL},
|
||||
{name: 'int1', type: Realm.Types.INT},
|
||||
{name: 'int2', type: Realm.Types.INT},
|
||||
{name: 'float1', type: Realm.Types.FLOAT},
|
||||
{name: 'float2', type: Realm.Types.FLOAT},
|
||||
{name: 'double1', type: Realm.Types.DOUBLE},
|
||||
{name: 'double2', type: Realm.Types.DOUBLE},
|
||||
{name: 'string1', type: Realm.Types.STRING},
|
||||
{name: 'string2', type: Realm.Types.STRING},
|
||||
]
|
||||
};
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 3c33e9f056e41adc97422c42d75d9388693e255e
|
||||
Subproject commit c98941121a4b96a4fa4ad785790a4a3e119227a5
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 498cb70f5b60b9d87d7f4864104155339daf561b
|
Loading…
Reference in New Issue