Merge pull request #128 from realm/al-parser

C++ query parser
This commit is contained in:
Ari Lazier 2015-11-23 10:38:02 -08:00
commit eb3c973947
29 changed files with 3598 additions and 756 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "vendor/GCDWebServer"] [submodule "vendor/GCDWebServer"]
path = vendor/GCDWebServer path = vendor/GCDWebServer
url = https://github.com/swisspol/GCDWebServer.git url = https://github.com/swisspol/GCDWebServer.git
[submodule "vendor/PEGTL"]
path = vendor/PEGTL
url = https://github.com/ColinH/PEGTL.git

View File

@ -19,15 +19,15 @@
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSList.cpp */; }; 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, ); }; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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, ); }; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 0270BC861B7D020100010E03 /* schemas.js in Resources */ = {isa = PBXBuildFile; fileRef = 0270BC7F1B7D020100010E03 /* schemas.js */; };
0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; }; 0270BC871B7D023200010E03 /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
0270BCD11B7D067300010E03 /* RealmReact.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BCD01B7D067300010E03 /* RealmReact.mm */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 02B29A311B7CF86D008A7E6B /* RealmJS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CB11AE99CEC009B348C /* RealmJS.framework */; };
02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; 02B58CCE1AE99D4D009B348C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; };
02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; }; 02C0864E1BCDB27000942F9C /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02C0864C1BCDB27000942F9C /* list.cpp */; };
02C0864F1BCDB27000942F9C /* list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02C0864D1BCDB27000942F9C /* list.hpp */; }; 02C0864F1BCDB27000942F9C /* list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02C0864D1BCDB27000942F9C /* list.hpp */; };
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02D0F23A1BF6C95200B4FC45 /* binding_context.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 */; }; 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */ = {isa = PBXBuildFile; fileRef = 02D456D91B7E59A500EE1299 /* ArrayTests.js */; };
02D8D1F71B601984006DB49D /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02B58CCD1AE99D4D009B348C /* JavaScriptCore.framework */; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */; };
F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; }; F68A278E1BC30F0A0063D40A /* index.js in Resources */ = {isa = PBXBuildFile; fileRef = F68A278D1BC30F0A0063D40A /* index.js */; };
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6BB7DEF1BF681BC00D0A69E /* base64.cpp */; }; F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6BB7DEF1BF681BC00D0A69E /* base64.cpp */; };
@ -70,42 +78,35 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
02313C461BCC4A43003F9107 /* PBXContainerItemProxy */ = { 021CEA351BFD1BA000D69390 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = CEE28CEE1AE0051F00F4023C;
remoteInfo = "GCDWebServers (iOS)";
};
02A3C78D1BC4317A00B1A7BE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 2; proxyType = 2;
remoteGlobalIDString = 8DD76FB20486AB0100D96B5E; remoteGlobalIDString = 8DD76FB20486AB0100D96B5E;
remoteInfo = "GCDWebServer (Mac)"; remoteInfo = "GCDWebServer (Mac)";
}; };
02A3C78F1BC4317A00B1A7BE /* PBXContainerItemProxy */ = { 021CEA371BFD1BA000D69390 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 2; proxyType = 2;
remoteGlobalIDString = E221125A1690B4DE0048D2B2; remoteGlobalIDString = E221125A1690B4DE0048D2B2;
remoteInfo = "GCDWebServer (iOS)"; remoteInfo = "GCDWebServer (iOS)";
}; };
02A3C7911BC4317A00B1A7BE /* PBXContainerItemProxy */ = { 021CEA391BFD1BA000D69390 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 2; proxyType = 2;
remoteGlobalIDString = CEE28CD11AE004D800F4023C; remoteGlobalIDString = CEE28CD11AE004D800F4023C;
remoteInfo = "GCDWebServers (Mac)"; remoteInfo = "GCDWebServers (Mac)";
}; };
02A3C7931BC4317A00B1A7BE /* PBXContainerItemProxy */ = { 021CEA3B1BFD1BA000D69390 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 2; proxyType = 2;
remoteGlobalIDString = CEE28CEF1AE0051F00F4023C; remoteGlobalIDString = CEE28CEF1AE0051F00F4023C;
remoteInfo = "GCDWebServers (iOS)"; remoteInfo = "GCDWebServers (iOS)";
}; };
02A3C7951BC4317A00B1A7BE /* PBXContainerItemProxy */ = { 021CEA3D1BFD1BA000D69390 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; containerPortal = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
proxyType = 2; proxyType = 2;
@ -126,6 +127,27 @@
remoteGlobalIDString = 02B58CB01AE99CEC009B348C; remoteGlobalIDString = 02B58CB01AE99CEC009B348C;
remoteInfo = RealmJS; 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 */ = { 02EE6D891BD87E310016A82E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 02EE6D781BD87E310016A82E /* ReactTests.xcodeproj */; containerPortal = 02EE6D781BD87E310016A82E /* ReactTests.xcodeproj */;
@ -149,7 +171,7 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 10; dstSubfolderSpec = 10;
files = ( files = (
F67191381BCE231100AD0939 /* GCDWebServers.framework in Embed Frameworks */, 02D0F2D61C037C3400B4FC45 /* GCDWebServers.framework in Embed Frameworks */,
F64426C51BCDB1E200A81210 /* RealmJS.framework in Embed Frameworks */, F64426C51BCDB1E200A81210 /* RealmJS.framework in Embed Frameworks */,
); );
name = "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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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; }; 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; }; 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; }; 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 */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup 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 */ = { 0270BC3D1B7CFBFD00010E03 /* RealmJS */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -279,6 +323,10 @@
029445921BDEDF40006D1617 /* transact_log_handler.hpp */, 029445921BDEDF40006D1617 /* transact_log_handler.hpp */,
029445951BDEDF46006D1617 /* external_commit_helper.cpp */, 029445951BDEDF46006D1617 /* external_commit_helper.cpp */,
029445961BDEDF46006D1617 /* external_commit_helper.hpp */, 029445961BDEDF46006D1617 /* external_commit_helper.hpp */,
02786E311BF1065000937061 /* parser.cpp */,
02786E321BF1065000937061 /* parser.hpp */,
0294465C1BF27DE6006D1617 /* query_builder.cpp */,
0294465D1BF27DE6006D1617 /* query_builder.hpp */,
0270BC3E1B7CFC0D00010E03 /* RealmJS.h */, 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */,
0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */, 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */,
02258FB11BC6E2D00075F13A /* RealmRPC.hpp */, 02258FB11BC6E2D00075F13A /* RealmRPC.hpp */,
@ -286,15 +334,15 @@
0270BC401B7CFC0D00010E03 /* RJSList.cpp */, 0270BC401B7CFC0D00010E03 /* RJSList.cpp */,
0270BC411B7CFC0D00010E03 /* RJSList.hpp */, 0270BC411B7CFC0D00010E03 /* RJSList.hpp */,
0270BC421B7CFC0D00010E03 /* RJSObject.hpp */, 0270BC421B7CFC0D00010E03 /* RJSObject.hpp */,
0270BC431B7CFC0D00010E03 /* RJSObject.mm */, 0270BC431B7CFC0D00010E03 /* RJSObject.cpp */,
0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */, 0270BC441B7CFC0D00010E03 /* RJSRealm.hpp */,
0270BC451B7CFC0D00010E03 /* RJSRealm.mm */, 0270BC451B7CFC0D00010E03 /* RJSRealm.mm */,
0270BC461B7CFC0D00010E03 /* RJSResults.hpp */, 0270BC461B7CFC0D00010E03 /* RJSResults.hpp */,
0270BC471B7CFC0D00010E03 /* RJSResults.mm */, 0270BC471B7CFC0D00010E03 /* RJSResults.cpp */,
0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */, 0270BC481B7CFC0D00010E03 /* RJSSchema.hpp */,
0270BC491B7CFC0D00010E03 /* RJSSchema.mm */, 0270BC491B7CFC0D00010E03 /* RJSSchema.cpp */,
0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */, 0270BC4A1B7CFC0D00010E03 /* RJSUtil.hpp */,
0270BC4B1B7CFC0D00010E03 /* RJSUtil.mm */, 0270BC4B1B7CFC0D00010E03 /* RJSUtil.cpp */,
0270BC5A1B7CFC1300010E03 /* Info.plist */, 0270BC5A1B7CFC1300010E03 /* Info.plist */,
); );
name = RealmJS; name = RealmJS;
@ -310,18 +358,6 @@
name = RealmReact; name = RealmReact;
sourceTree = "<group>"; 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 = { 02B58CA71AE99CEB009B348C = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -355,6 +391,8 @@
F64E1EF01BC3510E00E0E150 /* util.js */, F64E1EF01BC3510E00E0E150 /* util.js */,
02D456D91B7E59A500EE1299 /* ArrayTests.js */, 02D456D91B7E59A500EE1299 /* ArrayTests.js */,
0270BC791B7D020100010E03 /* ObjectTests.js */, 0270BC791B7D020100010E03 /* ObjectTests.js */,
02E9A9F01BFA84F100939F86 /* QueryTests.js */,
02EF76751BFFD41F000D5BAD /* queryTests.json */,
0270BC7C1B7D020100010E03 /* RealmTests.js */, 0270BC7C1B7D020100010E03 /* RealmTests.js */,
0270BC7D1B7D020100010E03 /* ResultsTests.js */, 0270BC7D1B7D020100010E03 /* ResultsTests.js */,
0270BC7A1B7D020100010E03 /* RealmJSTests.h */, 0270BC7A1B7D020100010E03 /* RealmJSTests.h */,
@ -362,6 +400,8 @@
02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */, 02409DC11BCF11D6005F3B3E /* RealmJSCoreTests.m */,
F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */, F68A278A1BC2722A0063D40A /* RJSModuleLoader.h */,
F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */, F68A278B1BC2722A0063D40A /* RJSModuleLoader.m */,
02EF76871BFFDE9E000D5BAD /* GrammarTests.mm */,
02EF76851BFFDE37000D5BAD /* test.cpp */,
); );
path = RealmJSTests; path = RealmJSTests;
sourceTree = "<group>"; sourceTree = "<group>";
@ -406,6 +446,7 @@
0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */, 0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */,
02258FB31BC6E2D00075F13A /* RealmRPC.hpp in Headers */, 02258FB31BC6E2D00075F13A /* RealmRPC.hpp in Headers */,
0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */, 0270BC4F1B7CFC0D00010E03 /* RJSList.hpp in Headers */,
0294465F1BF27DE6006D1617 /* query_builder.hpp in Headers */,
0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */, 0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */,
02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */, 02D0F23B1BF6C95200B4FC45 /* binding_context.hpp in Headers */,
0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */, 0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */,
@ -414,6 +455,7 @@
0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */, 0270BC501B7CFC0D00010E03 /* RJSObject.hpp in Headers */,
02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */, 02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */,
0270BC6C1B7CFC1C00010E03 /* object_store.hpp in Headers */, 0270BC6C1B7CFC1C00010E03 /* object_store.hpp in Headers */,
02786E341BF1065100937061 /* parser.hpp in Headers */,
0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */, 0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */,
F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */, F6BB7DF21BF681BC00D0A69E /* base64.hpp in Headers */,
029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */, 029445941BDEDF40006D1617 /* transact_log_handler.hpp in Headers */,
@ -450,7 +492,7 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
02313C471BCC4A43003F9107 /* PBXTargetDependency */, 02D0F2D51C037C1700B4FC45 /* PBXTargetDependency */,
02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */, 02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */,
); );
name = RealmReact; name = RealmReact;
@ -527,7 +569,7 @@
projectDirPath = ""; projectDirPath = "";
projectReferences = ( projectReferences = (
{ {
ProductGroup = 02A3C7851BC4317A00B1A7BE /* Products */; ProductGroup = 021CEA2D1BFD1BA000D69390 /* Products */;
ProjectRef = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */; ProjectRef = 02A3C7841BC4317A00B1A7BE /* GCDWebServer.xcodeproj */;
}, },
{ {
@ -545,39 +587,53 @@
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXReferenceProxy section */ /* Begin PBXReferenceProxy section */
02A3C78E1BC4317A00B1A7BE /* GCDWebServer */ = { 021CEA361BFD1BA000D69390 /* GCDWebServer */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable"; fileType = "compiled.mach-o.executable";
path = GCDWebServer; path = GCDWebServer;
remoteRef = 02A3C78D1BC4317A00B1A7BE /* PBXContainerItemProxy */; remoteRef = 021CEA351BFD1BA000D69390 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
02A3C7901BC4317A00B1A7BE /* GCDWebServer.app */ = { 021CEA381BFD1BA000D69390 /* GCDWebServer.app */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = wrapper.application; fileType = wrapper.application;
path = GCDWebServer.app; path = GCDWebServer.app;
remoteRef = 02A3C78F1BC4317A00B1A7BE /* PBXContainerItemProxy */; remoteRef = 021CEA371BFD1BA000D69390 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
02A3C7921BC4317A00B1A7BE /* GCDWebServers.framework */ = { 021CEA3A1BFD1BA000D69390 /* GCDWebServers.framework */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = wrapper.framework; fileType = wrapper.framework;
path = GCDWebServers.framework; path = GCDWebServers.framework;
remoteRef = 02A3C7911BC4317A00B1A7BE /* PBXContainerItemProxy */; remoteRef = 021CEA391BFD1BA000D69390 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
02A3C7941BC4317A00B1A7BE /* GCDWebServers.framework */ = { 021CEA3C1BFD1BA000D69390 /* GCDWebServers.framework */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = wrapper.framework; fileType = wrapper.framework;
path = GCDWebServers.framework; path = GCDWebServers.framework;
remoteRef = 02A3C7931BC4317A00B1A7BE /* PBXContainerItemProxy */; remoteRef = 021CEA3B1BFD1BA000D69390 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
02A3C7961BC4317A00B1A7BE /* Tests.xctest */ = { 021CEA3E1BFD1BA000D69390 /* Tests.xctest */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = wrapper.cfbundle; fileType = wrapper.cfbundle;
path = Tests.xctest; 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; sourceTree = BUILT_PRODUCTS_DIR;
}; };
02EE6D8A1BD87E310016A82E /* ReactTests.app */ = { 02EE6D8A1BD87E310016A82E /* ReactTests.app */ = {
@ -609,12 +665,14 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F64E1EF11BC3510E00E0E150 /* util.js in Resources */, F64E1EF11BC3510E00E0E150 /* util.js in Resources */,
02E9A9F11BFA84F100939F86 /* QueryTests.js in Resources */,
0270BC851B7D020100010E03 /* asserts.js in Resources */, 0270BC851B7D020100010E03 /* asserts.js in Resources */,
0270BC811B7D020100010E03 /* ObjectTests.js in Resources */, 0270BC811B7D020100010E03 /* ObjectTests.js in Resources */,
02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */, 02D456DA1B7E59A500EE1299 /* ArrayTests.js in Resources */,
0270BC861B7D020100010E03 /* schemas.js in Resources */, 0270BC861B7D020100010E03 /* schemas.js in Resources */,
F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */, F6F405F81BCF0C1A00A1E24F /* base-test.js in Resources */,
F68A278E1BC30F0A0063D40A /* index.js in Resources */, F68A278E1BC30F0A0063D40A /* index.js in Resources */,
02EF76761BFFD41F000D5BAD /* queryTests.json in Resources */,
0270BC831B7D020100010E03 /* RealmTests.js in Resources */, 0270BC831B7D020100010E03 /* RealmTests.js in Resources */,
0270BC841B7D020100010E03 /* ResultsTests.js in Resources */, 0270BC841B7D020100010E03 /* ResultsTests.js in Resources */,
); );
@ -652,19 +710,21 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */, 0270BC571B7CFC0D00010E03 /* RJSSchema.cpp in Sources */,
0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */, 0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */,
02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */, 02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */,
0270BC6E1B7CFC1C00010E03 /* results.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 */, 0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */,
02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */, 02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */,
029445931BDEDF40006D1617 /* transact_log_handler.cpp in Sources */, 029445931BDEDF40006D1617 /* transact_log_handler.cpp in Sources */,
02258FB41BC6E2D00075F13A /* RealmRPC.cpp in Sources */, 02258FB41BC6E2D00075F13A /* RealmRPC.cpp in Sources */,
0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */, 0270BC591B7CFC0D00010E03 /* RJSUtil.cpp in Sources */,
0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */, 0270BC551B7CFC0D00010E03 /* RJSResults.cpp in Sources */,
02C0864E1BCDB27000942F9C /* list.cpp in Sources */, 02C0864E1BCDB27000942F9C /* list.cpp in Sources */,
0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */, 0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */,
0294465E1BF27DE6006D1617 /* query_builder.cpp in Sources */,
0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */, 0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */,
F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */, F6BB7DF11BF681BC00D0A69E /* base64.cpp in Sources */,
0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */, 0270BC4E1B7CFC0D00010E03 /* RJSList.cpp in Sources */,
@ -678,6 +738,8 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */, F68A278C1BC2722A0063D40A /* RJSModuleLoader.m in Sources */,
02EF76881BFFDE9E000D5BAD /* GrammarTests.mm in Sources */,
02EF76861BFFDE37000D5BAD /* test.cpp in Sources */,
0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */, 0270BC821B7D020100010E03 /* RealmJSTests.mm in Sources */,
02409DC21BCF11D6005F3B3E /* RealmJSCoreTests.m in Sources */, 02409DC21BCF11D6005F3B3E /* RealmJSCoreTests.m in Sources */,
); );
@ -686,11 +748,6 @@
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
02313C471BCC4A43003F9107 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "GCDWebServers (iOS)";
targetProxy = 02313C461BCC4A43003F9107 /* PBXContainerItemProxy */;
};
02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */ = { 02B29A301B7CF7ED008A7E6B /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 02B58CB01AE99CEC009B348C /* RealmJS */; target = 02B58CB01AE99CEC009B348C /* RealmJS */;
@ -701,6 +758,11 @@
target = 02B58CB01AE99CEC009B348C /* RealmJS */; target = 02B58CB01AE99CEC009B348C /* RealmJS */;
targetProxy = 02B58CBE1AE99CEC009B348C /* PBXContainerItemProxy */; targetProxy = 02B58CBE1AE99CEC009B348C /* PBXContainerItemProxy */;
}; };
02D0F2D51C037C1700B4FC45 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = "GCDWebServers (iOS)";
targetProxy = 02D0F2D41C037C1700B4FC45 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
@ -922,7 +984,7 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LANGUAGE_STANDARD = "c++14";
DEFINES_MODULE = YES; DEFINES_MODULE = NO;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
@ -936,6 +998,7 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/vendor/PEGTL",
"$(SRCROOT)/vendor", "$(SRCROOT)/vendor",
); );
INFOPLIST_FILE = src/Info.plist; INFOPLIST_FILE = src/Info.plist;
@ -961,7 +1024,7 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LANGUAGE_STANDARD = "c++14";
DEFINES_MODULE = YES; DEFINES_MODULE = NO;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
@ -970,6 +1033,7 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/vendor/PEGTL",
"$(SRCROOT)/vendor", "$(SRCROOT)/vendor",
); );
INFOPLIST_FILE = src/Info.plist; INFOPLIST_FILE = src/Info.plist;
@ -993,11 +1057,7 @@
02B58CCB1AE99CEC009B348C /* Debug */ = { 02B58CCB1AE99CEC009B348C /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = "$(inherited)";
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
build/iOS,
);
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
@ -1019,11 +1079,7 @@
02B58CCC1AE99CEC009B348C /* Release */ = { 02B58CCC1AE99CEC009B348C /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = "$(inherited)";
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
build/iOS,
);
HEADER_SEARCH_PATHS = ""; HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = tests/Info.plist; INFOPLIST_FILE = tests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -1092,7 +1148,7 @@
buildSettings = { buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES; APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LANGUAGE_STANDARD = "c++14";
DEFINES_MODULE = YES; DEFINES_MODULE = NO;
DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1; DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath"; DYLIB_INSTALL_NAME_BASE = "@rpath";
@ -1106,6 +1162,7 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/vendor/PEGTL",
"$(SRCROOT)/vendor", "$(SRCROOT)/vendor",
); );
INFOPLIST_FILE = src/Info.plist; INFOPLIST_FILE = src/Info.plist;
@ -1129,11 +1186,7 @@
02F9EE1E1B6BF66300C807E8 /* GCov_Build */ = { 02F9EE1E1B6BF66300C807E8 /* GCov_Build */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = "$(inherited)";
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
build/iOS,
);
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",

View File

@ -211,6 +211,13 @@ template<> JSValueRef RJSAccessor::from_datetime(JSContextRef ctx, DateTime dt)
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array); 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) { 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); JSObjectRef object = RJSValidatedValueToObject(ctx, val);
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) { if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {

View File

@ -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) { JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try { try {
RJSValidateArgumentRange(argumentCount, 1, 2); RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType"); std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject); SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
@ -267,8 +267,12 @@ JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef this
return RJSResultsCreate(ctx, sharedRealm, className); return RJSResultsCreate(ctx, sharedRealm, className);
} }
else { else {
std::string predicate = RJSValidatedStringForValue(ctx, arguments[1], "predicate"); std::string query = RJSValidatedStringForValue(ctx, arguments[1], "predicate");
return RJSResultsCreate(ctx, sharedRealm, className, 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) { catch (std::exception &exp) {

View File

@ -6,6 +6,8 @@
#import "RJSObject.hpp" #import "RJSObject.hpp"
#import "object_accessor.hpp" #import "object_accessor.hpp"
#import "results.hpp" #import "results.hpp"
#import "parser.hpp"
#import "query_builder.hpp"
using namespace realm; 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, std::vector<JSValueRef> args) {
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className, std::string queryString) {
TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className); TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className);
Query query = table->where(); Query query = table->where();
Schema &schema = *realm->config().schema; Schema &schema = *realm->config().schema;
auto object_schema = realm->config().schema->find(className); auto object_schema = schema.find(className);
if (object_schema == realm->config().schema->end()) { if (object_schema == schema.end()) {
throw std::runtime_error("Object type '" + className + "' not present in Realm."); throw std::runtime_error("Object type '" + className + "' not present in Realm.");
} }
@try { parser::Predicate predicate = parser::parse(queryString);
RLMUpdateQueryWithPredicate(&query, [NSPredicate predicateWithFormat:@(queryString.c_str())], schema, *object_schema); query_builder::ArgumentConverter<JSValueRef, JSContextRef> arguments(ctx, args);
} query_builder::apply_predicate(query, predicate, arguments, schema, object_schema->name);
@catch(NSException *ex) {
throw std::runtime_error(ex.description.UTF8String);
}
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query))); return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
} }

View File

@ -11,4 +11,4 @@ namespace realm {
JSClassRef RJSResultsClass(); JSClassRef RJSResultsClass();
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className); 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);

100
src/RJSUtil.cpp Normal file
View File

@ -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);
}

View File

@ -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());
}

View File

@ -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 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); 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 // list value acessors
static size_t list_size(ContextType ctx, ValueType &val); static size_t list_size(ContextType ctx, ValueType &val);
static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index); static ValueType list_value_at_index(ContextType ctx, ValueType &val, size_t index);

View File

@ -19,6 +19,7 @@
#ifndef REALM_OBJECT_STORE_HPP #ifndef REALM_OBJECT_STORE_HPP
#define REALM_OBJECT_STORE_HPP #define REALM_OBJECT_STORE_HPP
#include "schema.hpp"
#include "object_schema.hpp" #include "object_schema.hpp"
#include "property.hpp" #include "property.hpp"
@ -29,7 +30,6 @@
namespace realm { namespace realm {
class ObjectSchemaValidationException; class ObjectSchemaValidationException;
class Schema;
class ObjectStore { class ObjectStore {
public: public:

View File

@ -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 &current() {
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(&current().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 &current = 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 &current = 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>();
}
}}

View File

@ -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

View File

@ -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"]]
]
}
}

View File

@ -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());
}
}}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
# /bin/sh
llvm-g++ -std=c++11 -I ../../../vendor/PEGTL/ -o test test.cpp parser.cpp
./test

19
tests/GrammarTests.mm Normal file
View File

@ -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

1800
tests/QueryTests.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -12,5 +12,6 @@
- (void)addGlobalModuleObject:(id)object forName:(NSString *)name; - (void)addGlobalModuleObject:(id)object forName:(NSString *)name;
- (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error; - (JSValue *)loadModuleFromURL:(NSURL *)url error:(NSError **)error;
- (JSValue *)loadJSONFromURL:(NSURL *)url error:(NSError **)error;
@end @end

View File

@ -42,15 +42,19 @@ static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomai
NSURL *url = [[NSURL URLWithString:name relativeToURL:baseURL] absoluteURL]; NSURL *url = [[NSURL URLWithString:name relativeToURL:baseURL] absoluteURL];
BOOL isDirectory; BOOL isDirectory;
if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory]) { if ([[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDirectory] && isDirectory) {
if (!isDirectory) {
return nil;
}
url = [url URLByAppendingPathComponent:@"index.js"]; url = [url URLByAppendingPathComponent:@"index.js"];
} else { } else {
if ([[url pathExtension] isEqualToString:@"json"]) {
return [self loadJSONFromURL:url error:error];
}
else if ([[url pathExtension] length] == 0) {
url = [url URLByAppendingPathExtension:@"js"]; url = [url URLByAppendingPathExtension:@"js"];
} }
else {
return nil;
}
}
return [self loadModuleFromURL:url error:error]; return [self loadModuleFromURL:url error:error];
} }
@ -136,6 +140,34 @@ static NSString * const RJSModuleLoaderErrorDomain = @"RJSModuleLoaderErrorDomai
return exports; 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 *)loadGlobalModule:(NSString *)name relativeToURL:(NSURL *)baseURL error:(NSError **)error {
JSValue *exports = self.globalModules[name]; JSValue *exports = self.globalModules[name];
if (exports || !baseURL) { if (exports || !baseURL) {

View File

@ -614,7 +614,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; 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 */ /* End PBXShellScriptBuildPhase section */
@ -669,10 +669,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = "$(inherited)";
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = ( GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
@ -691,10 +688,7 @@
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = "$(inherited)";
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = ReactTestsTests/Info.plist; INFOPLIST_FILE = ReactTestsTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.2; IPHONEOS_DEPLOYMENT_TARGET = 8.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";

View File

@ -235,12 +235,12 @@ module.exports = BaseTest.extend({
}, },
testRealmObjects: function() { testRealmObjects: function() {
var realm = new Realm({schema: [schemas.PersonObject]}); var realm = new Realm({schema: [schemas.PersonObject, schemas.DefaultValues, schemas.TestObject]});
realm.write(function() { realm.write(function() {
realm.create('PersonObject', ['Ari', 10]); realm.create('PersonObject', ['Ari', 10, false]);
realm.create('PersonObject', ['Tim', 11]); realm.create('PersonObject', ['Tim', 11, false]);
realm.create('PersonObject', {'name': 'Bjarne', 'age': 12}); 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() { 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 < 12').length, 2);
TestCase.assertEqual(realm.objects('PersonObject', 'age > 10 && age < 13').length, 3); 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', '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', '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() { testNotifications: function() {

View File

@ -24,8 +24,8 @@ module.exports = BaseTest.extend({
testResultsSubscript: function() { testResultsSubscript: function() {
var realm = new Realm({schema: [schemas.PersonObject]}); var realm = new Realm({schema: [schemas.PersonObject]});
realm.write(function() { realm.write(function() {
realm.create('PersonObject', ['name1', 1]); realm.create('PersonObject', ['name1', 1, false]);
realm.create('PersonObject', ['name2', 2]); realm.create('PersonObject', ['name2', 2, false]);
}); });
var people = realm.objects('PersonObject'); var people = realm.objects('PersonObject');

View File

@ -8,6 +8,7 @@ exports.ArrayTests = require('./ArrayTests');
exports.ObjectTests = require('./ObjectTests'); exports.ObjectTests = require('./ObjectTests');
exports.RealmTests = require('./RealmTests'); exports.RealmTests = require('./RealmTests');
exports.ResultsTests = require('./ResultsTests'); exports.ResultsTests = require('./ResultsTests');
exports.QueryTests = require('./QueryTests');
var SPECIAL_METHODS = { var SPECIAL_METHODS = {
beforeEach: true, beforeEach: true,

View File

@ -19,6 +19,7 @@ PersonObject.prototype.schema = {
properties: [ properties: [
{name: 'name', type: Realm.Types.STRING}, {name: 'name', type: Realm.Types.STRING},
{name: 'age', type: Realm.Types.DOUBLE}, {name: 'age', type: Realm.Types.DOUBLE},
{name: 'married', type: Realm.Types.BOOL, default: false}
] ]
}; };
PersonObject.prototype.description = function() { PersonObject.prototype.description = function() {
@ -102,3 +103,35 @@ exports.DefaultValues = {
{name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]}, {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},
]
};

2
vendor/GCDWebServer vendored

@ -1 +1 @@
Subproject commit 3c33e9f056e41adc97422c42d75d9388693e255e Subproject commit c98941121a4b96a4fa4ad785790a4a3e119227a5

1
vendor/PEGTL vendored Submodule

@ -0,0 +1 @@
Subproject commit 498cb70f5b60b9d87d7f4864104155339daf561b