├── .gitignore ├── LICENSE ├── README.md ├── SQLite3-WinRT.sln ├── SQLite3Component ├── Common.cpp ├── Common.h ├── Constants.cpp ├── Constants.h ├── Database.cpp ├── Database.h ├── SQLite3Component.vcxproj ├── Statement.cpp ├── Statement.h ├── res │ ├── component_manifest.h │ └── component_manifest.rc ├── sqlite3.c └── sqlite3.h └── SQLite3JS ├── SQLite3JS.jsproj ├── SQLite3JS_TemporaryKey.pfx ├── config.js ├── default.html ├── examples ├── blobs.html └── blobs.js ├── images ├── logo.png ├── smalllogo.png ├── splashscreen.png ├── storelogo.png └── widelogo.png ├── js ├── SQLite3.js └── tests │ ├── background.js │ ├── jasmineRunner.js │ └── string.monkeypatch.js ├── lib ├── jasmine-1.3.1 │ ├── MIT.LICENSE │ ├── jasmine-html.js │ ├── jasmine.css │ └── jasmine.js ├── jasmine-reporters │ └── jasmine.junit_reporter.js └── jslint │ └── jslint.js ├── package.appxmanifest ├── spec └── SQLite3Spec.js └── strings └── en-US ├── resources.resjson └── secondary.resjson /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.sdf 3 | *.opensdf 4 | *.filters 5 | *.suo 6 | 7 | Debug/ 8 | Release/ 9 | ipch/ 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012,2013 doo GmbH 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQLite3-WinRT 2 | 3 | Async SQLite for (JavaScript) Windows Store apps. 4 | 5 | ## Changelog 6 | 7 | ### 1.3.4 8 | 9 | #### Support for blobs 10 | 11 | This allows you to insert blobs into your database and read them back as BASE64 encoded values in your JSON result. 12 | See [the blob example](https://github.com/doo/SQLite3-WinRT/tree/master/SQLite3JS/examples/blobs.js) how to use it in your apps. 13 | If you need an IBuffer back from the db you can use [CryptographicBuffer.DecodeFromBase64String](http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.cryptographicbuffer.decodefrombase64string). 14 | 15 | 16 | ### 1.1.2 17 | 18 | Some minor API changes: 19 | 20 | 1. `getLastInsertRowId()` function becomes `lastInsertRowId` property 21 | 2. `getAutocommit()` function becomes `autoCommit` property 22 | 3. `getLastError()` function becomes `lastError` property 23 | 4. `enableSharedCache()` function becomes `sharedCache` property 24 | 25 | 26 | ### 1.1.0 27 | 28 | This version introduces a **breaking API change** along with some enhancements: 29 | 30 | 1. `runAsync` no longer returns the database for chained calls. Instead it will now return the number of rows affected by the executed SQL statement. 31 | 2. A special collation sequence, `WINLOCALE` is introduced. It uses the sorting behaviour of the currently active system locale. The locale can be overridden by setting `db.collationLanguage`. 32 | 3. We also now implemented a `regexp` function based on the STL (TR1) regex functionality. You can now use the `REGEXP` operator, see the SQLite documentation for further information. 33 | 34 | As usual, you should look at our unit tests if you are unsure how to use this new functionality. 35 | 36 | 37 | ## Status 38 | 39 | We finally consider _SQLite3-WinRT_ ready for production use and it is already 40 | being used by certified apps published in the Windows Store including, of course [our own application](http://apps.microsoft.com/webpdp/app/doo/28631302-9666-4ee3-aaf4-e52c493370e8). 41 | Support for BLOBs and an API for transaction management are still on our to-do list - unfortunately with a very low priority. Feedback and contributions are highly appreciated, feel free to open issues or pull requests on GitHub. 42 | 43 | 44 | ## Setup 45 | 46 | _SQLite3-WinRT_ consists of two parts, a WinRT component named 47 | _SQLite3Component_ and a JavaScript namespace called _SQLite3JS_ that builds 48 | upon the _SQLite3Component_. 49 | 50 | Therefore, in order to use _SQLite3JS_ in a JavaScript app, the 51 | _SQLite3Component_ project `SQLite3Component\SQLite3Component.vcxproj` must be 52 | added to the app's solution using _FILE > Add > Existing Project..._. 53 | A reference to _SQLite3Component_ must be added to the app's project using 54 | _PROJECT > Add Reference..._. Now, the _SQLite3JS_ source 55 | `SQLite3JS\js\SQLite3.js` can be used in the app's project. 56 | 57 | Note for users of Visual Studio 2012 Express: To compile the WinRT component 58 | successfully, please install the [Windows SDK][1]. 59 | 60 | [1]: http://msdn.microsoft.com/en-us/windows/desktop/hh852363.aspx 61 | 62 | 63 | ## Usage 64 | 65 | The _SQLite3JS_ namespace provides an async JavaScript API for SQLite. It is built 66 | around the `Database` object that can be obtained using `SQLite3JS.openAsync()`. 67 | The API was inspired by [node-sqlite3][2]. 68 | 69 | [2]: https://github.com/developmentseed/node-sqlite3/ 70 | 71 | ### Example 72 | 73 | var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\db.sqlite'; 74 | SQLite3JS.openAsync(dbPath) 75 | .then(function (db) { 76 | return db.runAsync('CREATE TABLE Item (name TEXT, price REAL, id INT PRIMARY KEY)') 77 | .then(function () { 78 | return db.runAsync('INSERT INTO Item (name, price, id) VALUES (?, ?, ?)', ['Mango', 4.6, 123]); 79 | }) 80 | .then(function () { 81 | return db.eachAsync('SELECT * FROM Item', function (row) { 82 | console.log('Get a ' + row.name + ' for $' + row.price); 83 | }); 84 | }) 85 | .then(function () { 86 | db.close(); 87 | }); 88 | }); 89 | 90 | 91 | ## License 92 | 93 | Copyright (c) 2012,2013 doo GmbH 94 | 95 | Licensed under the MIT License, see LICENSE file. 96 | -------------------------------------------------------------------------------- /SQLite3-WinRT.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SQLite3Component", "SQLite3Component\SQLite3Component.vcxproj", "{4CF1AE34-D183-409B-90C3-D62167CFF25D}" 5 | EndProject 6 | Project("{262852C6-CD72-467D-83FE-5EEB1973A190}") = "SQLite3JS", "SQLite3JS\SQLite3JS.jsproj", "{1A1E8060-A03C-449C-931C-6BCEEC16E82F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|ARM = Release|ARM 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|ARM.ActiveCfg = Debug|ARM 19 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|ARM.Build.0 = Debug|ARM 20 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|x64.ActiveCfg = Debug|x64 21 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|x64.Build.0 = Debug|x64 22 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|x86.ActiveCfg = Debug|Win32 23 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Debug|x86.Build.0 = Debug|Win32 24 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|ARM.ActiveCfg = Release|ARM 25 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|ARM.Build.0 = Release|ARM 26 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|x64.ActiveCfg = Release|x64 27 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|x64.Build.0 = Release|x64 28 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|x86.ActiveCfg = Release|Win32 29 | {4CF1AE34-D183-409B-90C3-D62167CFF25D}.Release|x86.Build.0 = Release|Win32 30 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|ARM.ActiveCfg = Debug|ARM 31 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|ARM.Build.0 = Debug|ARM 32 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|ARM.Deploy.0 = Debug|ARM 33 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x64.ActiveCfg = Debug|x64 34 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x64.Build.0 = Debug|x64 35 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x64.Deploy.0 = Debug|x64 36 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x86.ActiveCfg = Debug|x86 37 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x86.Build.0 = Debug|x86 38 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Debug|x86.Deploy.0 = Debug|x86 39 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|ARM.ActiveCfg = Release|ARM 40 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|ARM.Build.0 = Release|ARM 41 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|ARM.Deploy.0 = Release|ARM 42 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x64.ActiveCfg = Release|x64 43 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x64.Build.0 = Release|x64 44 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x64.Deploy.0 = Release|x64 45 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x86.ActiveCfg = Release|x86 46 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x86.Build.0 = Release|x86 47 | {1A1E8060-A03C-449C-931C-6BCEEC16E82F}.Release|x86.Deploy.0 = Release|x86 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /SQLite3Component/Common.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "Common.h" 4 | 5 | namespace SQLite3 { 6 | void throwSQLiteError(int resultCode, Platform::String^ message) { 7 | HRESULT hresult; 8 | switch (resultCode) { 9 | case SQLITE_ERROR: hresult = E_FAIL; break; 10 | case SQLITE_ABORT: hresult = E_ABORT; break; 11 | case SQLITE_BUSY: hresult = HRESULT_FROM_WIN32(ERROR_BUSY); break; 12 | case SQLITE_LOCKED: hresult = HRESULT_FROM_WIN32(ERROR_LOCK_VIOLATION); break; 13 | case SQLITE_NOMEM: hresult = E_OUTOFMEMORY; break; 14 | case SQLITE_READONLY: hresult = HRESULT_FROM_WIN32(ERROR_FILE_READ_ONLY); break; 15 | case SQLITE_INTERRUPT: hresult = HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED); break; 16 | case SQLITE_IOERR: hresult = HRESULT_FROM_WIN32(ERROR_IO_DEVICE); break; 17 | case SQLITE_CORRUPT: hresult = HRESULT_FROM_WIN32(ERROR_DATABASE_FAILURE); break; /* The database disk image is malformed */ 18 | case SQLITE_NOTFOUND: hresult = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION); break; /* Unknown opcode in sqlite3_file_control() */ 19 | case SQLITE_FULL: hresult = HRESULT_FROM_WIN32(ERROR_DATABASE_FULL); break; /* Insertion failed because database is full */ 20 | case SQLITE_CANTOPEN: hresult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); break; /* Unable to open the database file */ 21 | case SQLITE_PROTOCOL: hresult = E_INVALID_PROTOCOL_OPERATION; break;/* Database lock protocol error */ 22 | case SQLITE_EMPTY: hresult = HRESULT_FROM_WIN32(ERROR_EMPTY); break; /* Database is empty */ 23 | case SQLITE_SCHEMA: hresult = E_CHANGED_STATE; break;/* The database schema changed */ 24 | /*case SQLITE_TOOBIG: hresult = break;/* String or BLOB exceeds size limit */ 25 | /*case SQLITE_CONSTRAINT: hresult = break;/* Abort due to constraint violation */ 26 | case SQLITE_MISMATCH: hresult = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); break;/* Data type mismatch */ 27 | /*case SQLITE_MISUSE: hresult = break;/* Library used incorrectly */ 28 | case SQLITE_NOLFS: hresult = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); break;/* Uses OS features not supported on host */ 29 | case SQLITE_AUTH: hresult = HRESULT_FROM_WIN32(ERROR_NOT_AUTHENTICATED); break;/* Authorization denied */ 30 | case SQLITE_FORMAT: hresult = HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT); break;/* Auxiliary database format error */ 31 | case SQLITE_RANGE: hresult = E_BOUNDS; break;/* 2nd parameter to sqlite3_bind out of range */ 32 | case SQLITE_NOTADB: hresult = HRESULT_FROM_WIN32(ERROR_DATABASE_DOES_NOT_EXIST); break; /* File opened that is not a database file */ 33 | default: 34 | hresult = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, resultCode); 35 | hresult |= 0x20000000; // Set "customer-defined" bit 36 | } 37 | OutputDebugStringW(message->Data()); 38 | OutputDebugStringW(L"\n"); 39 | throw ref new Platform::COMException(hresult, message); 40 | } 41 | 42 | std::wstring ToWString(const char* utf8String, unsigned int length) { 43 | DWORD numCharacters = MultiByteToWideChar(CP_UTF8, 0, utf8String, length, nullptr, 0); 44 | auto wideText = new std::wstring::value_type[numCharacters]; 45 | MultiByteToWideChar(CP_UTF8, 0, utf8String, length, wideText, numCharacters); 46 | std::wstring result(wideText); 47 | delete[] wideText; 48 | return result; 49 | } 50 | 51 | Platform::String^ ToPlatformString(const char* utf8String, unsigned int length) { 52 | return ref new Platform::String(ToWString(utf8String, length).data()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /SQLite3Component/Common.h: -------------------------------------------------------------------------------- 1 | #pragma once; 2 | 3 | #include 4 | #include 5 | #include 6 | #include "sqlite3.h" 7 | 8 | namespace SQLite3 { 9 | ref class Database; 10 | class Statement; 11 | typedef std::unique_ptr StatementPtr; 12 | 13 | typedef Windows::Foundation::Collections::IVectorView ParameterVector; 14 | typedef std::vector SafeParameterVector; 15 | 16 | typedef Windows::Foundation::Collections::PropertySet ParameterMap; 17 | 18 | public delegate void EachCallback(Platform::String^); 19 | 20 | using Windows::Foundation::IAsyncAction; 21 | using Windows::Foundation::IAsyncOperation; 22 | 23 | void throwSQLiteError(int resultCode, Platform::String^ message = nullptr); 24 | std::wstring ToWString(const char* utf8String, unsigned int length = -1); 25 | Platform::String^ ToPlatformString(const char* utf8String, unsigned int length = -1); 26 | 27 | template 28 | Microsoft::WRL::ComPtr winrt_as(Platform::Object^ const from) { 29 | Microsoft::WRL::ComPtr to; 30 | if (S_OK != (reinterpret_cast(from)->QueryInterface(to.GetAddressOf()))) { 31 | return nullptr; 32 | } 33 | else { 34 | return to; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SQLite3Component/Constants.cpp: -------------------------------------------------------------------------------- 1 | #include "Constants.h" 2 | -------------------------------------------------------------------------------- /SQLite3Component/Constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sqlite3.h" 4 | 5 | namespace SQLite3 { 6 | public ref class Datatype sealed { 7 | public: 8 | static property int Integer { int get() { return SQLITE_INTEGER; } } 9 | static property int Float { int get() { return SQLITE_FLOAT; } } 10 | static property int Text { int get() { return SQLITE_TEXT; } } 11 | static property int Blob { int get() { return SQLITE_BLOB; } } 12 | static property int Null { int get() { return SQLITE_NULL; } } 13 | }; 14 | 15 | public ref class ResultCode sealed { 16 | public: 17 | static property int Ok { int get() { return SQLITE_OK; } } 18 | static property int Error { int get() { return SQLITE_ERROR; } } 19 | static property int Internal { int get() { return SQLITE_INTERNAL; } } 20 | static property int Perm { int get() { return SQLITE_PERM; } } 21 | static property int Abort { int get() { return SQLITE_ABORT; } } 22 | static property int Busy { int get() { return SQLITE_BUSY; } } 23 | static property int Locked { int get() { return SQLITE_LOCKED; } } 24 | static property int NoMem { int get() { return SQLITE_NOMEM; } } 25 | static property int ReadOnly { int get() { return SQLITE_READONLY; } } 26 | static property int Interrupt { int get() { return SQLITE_INTERRUPT; } } 27 | static property int IoErr { int get() { return SQLITE_IOERR; } } 28 | static property int Corrupt { int get() { return SQLITE_CORRUPT; } } 29 | static property int NotFound { int get() { return SQLITE_NOTFOUND; } } 30 | static property int Full { int get() { return SQLITE_FULL; } } 31 | static property int CantOpen { int get() { return SQLITE_CANTOPEN; } } 32 | static property int Protocol { int get() { return SQLITE_PROTOCOL; } } 33 | static property int Empty { int get() { return SQLITE_EMPTY; } } 34 | static property int Schema { int get() { return SQLITE_SCHEMA; } } 35 | static property int TooBig { int get() { return SQLITE_TOOBIG; } } 36 | static property int Constraint { int get() { return SQLITE_CONSTRAINT; } } 37 | static property int Mismatch { int get() { return SQLITE_MISMATCH; } } 38 | static property int Misuse { int get() { return SQLITE_MISUSE; } } 39 | static property int NoLfs { int get() { return SQLITE_NOLFS; } } 40 | static property int Auth { int get() { return SQLITE_AUTH; } } 41 | static property int Format { int get() { return SQLITE_FORMAT; } } 42 | static property int Range { int get() { return SQLITE_RANGE; } } 43 | static property int NotADb { int get() { return SQLITE_NOTADB; } } 44 | static property int Row { int get() { return SQLITE_ROW; } } 45 | static property int Done { int get() { return SQLITE_DONE; } } 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /SQLite3Component/Database.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "Database.h" 10 | #include "Statement.h" 11 | 12 | using Windows::UI::Core::CoreDispatcher; 13 | using Windows::UI::Core::CoreDispatcherPriority; 14 | using Windows::UI::Core::CoreWindow; 15 | using Windows::UI::Core::DispatchedHandler; 16 | 17 | using Windows::Foundation::IAsyncAction; 18 | using Windows::Foundation::IAsyncOperation; 19 | 20 | namespace SQLite3 { 21 | static int WinLocaleCollateUtf16(void *data, int str1Length, const void* str1Data, int str2Length, const void* str2Data) { 22 | Database^ db = reinterpret_cast(data); 23 | Platform::String^ language = db->CollationLanguage; 24 | int compareResult = CompareStringEx(language ? language->Data() : LOCALE_NAME_USER_DEFAULT, 25 | LINGUISTIC_IGNORECASE|LINGUISTIC_IGNOREDIACRITIC|SORT_DIGITSASNUMBERS, 26 | (LPCWCH)str1Data, str1Length/sizeof(wchar_t), 27 | (LPCWCH)str2Data, str2Length/sizeof(wchar_t), 28 | NULL, NULL, 0); 29 | if (compareResult == 0) { 30 | throw ref new Platform::InvalidArgumentException(); 31 | } 32 | return compareResult-2; 33 | } 34 | 35 | static int WinLocaleCollateUtf8(void* data, int str1Length, const void* str1Data, int str2Length, const void* str2Data) { 36 | std::wstring string1 = ToWString((const char*)str1Data, str1Length); 37 | std::wstring string2 = ToWString((const char*)str2Data, str2Length); 38 | // SQLite expects unsigned int argument but length returns size_t (unsigned machine word). I think its safe to cast this warning away here 39 | // since "no one ever needs strings bigger than 2 GB in size". If they do, they have to fix the signature and internals of SQLite themself. 40 | return WinLocaleCollateUtf16(data, (int)(string1.length()*sizeof(wchar_t)), string1.c_str(), (int)(string2.length()*sizeof(wchar_t)), string2.c_str()); 41 | } 42 | 43 | static void SqliteRegexUtf16( sqlite3_context *context, int argc, sqlite3_value **argv ) { 44 | const wchar_t* patternText = (const wchar_t*) sqlite3_value_text16(argv[0]); 45 | std::wstring searchText((const wchar_t*) sqlite3_value_text16(argv[1])); 46 | std::wregex regex(patternText); 47 | sqlite3_result_int(context, std::regex_search(searchText.begin(), searchText.end(), regex) ? 1 : 0); 48 | } 49 | 50 | static SafeParameterVector CopyParameters(ParameterVector^ params) { 51 | SafeParameterVector paramsCopy; 52 | 53 | if (params) { 54 | std::copy(begin(params), end(params), std::back_inserter(paramsCopy)); 55 | } 56 | 57 | return paramsCopy; 58 | } 59 | 60 | static std::map resourceLoaders; 61 | static void TranslateUtf16(sqlite3_context *context, int argc, sqlite3_value **argv) { 62 | int param0Type = sqlite3_value_type(argv[0]); 63 | int param1Type = argc == 2 ? sqlite3_value_type(argv[1]) : -1; 64 | if (param0Type != SQLITE_TEXT || (argc == 2 && param1Type != SQLITE_TEXT)) { 65 | sqlite3_result_error(context, "Invalid parameters", -1); 66 | return; 67 | } 68 | Windows::ApplicationModel::Resources::ResourceLoader^ resourceLoader; 69 | const wchar_t* key; 70 | if (argc == 1) { 71 | static auto defaultResourceLoader = ref new Windows::ApplicationModel::Resources::ResourceLoader(); 72 | resourceLoader = defaultResourceLoader; 73 | 74 | key = (wchar_t*)sqlite3_value_text16(argv[0]); 75 | } else { 76 | auto resourceMapName = ref new Platform::String((wchar_t*)sqlite3_value_text16(argv[0])); 77 | resourceLoader = resourceLoaders[resourceMapName]; 78 | if (!resourceLoader) { 79 | resourceLoader = ref new Windows::ApplicationModel::Resources::ResourceLoader(resourceMapName); 80 | resourceLoaders[resourceMapName] = resourceLoader; 81 | } 82 | 83 | key = (wchar_t*)sqlite3_value_text16(argv[1]); 84 | } 85 | 86 | auto platformKey = ref new Platform::String(key); 87 | auto translation = resourceLoader->GetString(platformKey); 88 | sqlite3_result_text16(context, translation->Data(), (translation->Length()+1)*sizeof(wchar_t), SQLITE_TRANSIENT); 89 | } 90 | 91 | bool Database::sharedCache = false; 92 | 93 | IAsyncOperation^ Database::OpenAsync(Platform::String^ dbPath) { 94 | if (!dbPath->Length()) { 95 | throw ref new Platform::COMException(E_INVALIDARG, L"You must specify a path or :memory:"); 96 | } 97 | 98 | // Need to remember the current thread for later callbacks into JS 99 | CoreDispatcher^ dispatcher = CoreWindow::GetForCurrentThread()->Dispatcher; 100 | 101 | return Concurrency::create_async([dbPath, dispatcher]() { 102 | sqlite3* sqlite; 103 | int ret = sqlite3_open16(dbPath->Data(), &sqlite); 104 | 105 | if (ret != SQLITE_OK) { 106 | sqlite3_close(sqlite); 107 | throwSQLiteError(ret, dbPath); 108 | } 109 | 110 | return ref new Database(sqlite, dispatcher); 111 | }); 112 | } 113 | 114 | Database::Database(sqlite3* sqlite, CoreDispatcher^ dispatcher) 115 | : collationLanguage(nullptr) // will use user locale 116 | , dispatcher(dispatcher) 117 | , fireEvents(true) 118 | , changeHandlers(0) 119 | , insertChangeHandlers(0) 120 | , updateChangeHandlers(0) 121 | , deleteChangeHandlers(0) 122 | , sqlite(sqlite) { 123 | assert(sqlite); 124 | sqlite3_create_collation_v2(sqlite, "WINLOCALE", SQLITE_UTF16, reinterpret_cast(this), WinLocaleCollateUtf16, nullptr); 125 | sqlite3_create_collation_v2(sqlite, "WINLOCALE", SQLITE_UTF8, reinterpret_cast(this), WinLocaleCollateUtf8, nullptr); 126 | 127 | sqlite3_create_function_v2(sqlite, "APPTRANSLATE", 1, SQLITE_UTF16, NULL, TranslateUtf16, nullptr, nullptr, nullptr); 128 | sqlite3_create_function_v2(sqlite, "APPTRANSLATE", 2, SQLITE_UTF16, NULL, TranslateUtf16, nullptr, nullptr, nullptr); 129 | 130 | sqlite3_create_function_v2(sqlite, "REGEXP", 2, SQLITE_UTF16, NULL, SqliteRegexUtf16, nullptr, nullptr, nullptr); 131 | } 132 | 133 | Database::~Database() { 134 | sqlite3_close(sqlite); 135 | } 136 | 137 | void Database::addChangeHandler(int& handlerCount) { 138 | assert(changeHandlers >= 0); 139 | assert(handlerCount >= 0); 140 | ++handlerCount; 141 | if (changeHandlers++ == 0) { 142 | sqlite3_update_hook(sqlite, UpdateHook, reinterpret_cast(this)); 143 | } 144 | } 145 | 146 | void Database::removeChangeHandler(int& handlerCount) { 147 | assert(changeHandlers > 0); 148 | assert(handlerCount > 0); 149 | --handlerCount; 150 | if (--changeHandlers == 0) { 151 | sqlite3_update_hook(sqlite, nullptr, nullptr); 152 | } 153 | } 154 | 155 | void Database::UpdateHook(void* data, int action, char const* dbName, char const* tableName, sqlite3_int64 rowId) { 156 | assert(data); 157 | Database^ database = reinterpret_cast(data); 158 | database->OnChange(action, dbName, tableName, rowId); 159 | } 160 | 161 | IAsyncAction^ Database::VacuumAsync() { 162 | return Concurrency::create_async([this]() { 163 | bool oldFireEvents = fireEvents; 164 | fireEvents = false; 165 | // See http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/d778c6e0-c248-4a1a-9391-28d038247578 166 | // Too many dispatched events fill the Windows Message queue and this will raise an QUOTA_EXCEEDED error 167 | Concurrency::task(RunAsync("VACUUM", reinterpret_cast(nullptr))).get(); 168 | fireEvents = oldFireEvents; 169 | }); 170 | } 171 | 172 | void Database::OnChange(int action, char const* dbName, char const* tableName, sqlite3_int64 rowId) { 173 | if (fireEvents) { 174 | DispatchedHandler^ handler; 175 | 176 | switch (action) { 177 | case SQLITE_INSERT: 178 | if (insertChangeHandlers) { 179 | ChangeEvent event; 180 | event.RowId = rowId; 181 | event.TableName = ToPlatformString(tableName); 182 | handler = ref new DispatchedHandler([this, event]() { 183 | _Insert(this, event); 184 | }); 185 | } 186 | break; 187 | case SQLITE_UPDATE: 188 | if (updateChangeHandlers) { 189 | ChangeEvent event; 190 | event.RowId = rowId; 191 | event.TableName = ToPlatformString(tableName); 192 | handler = ref new DispatchedHandler([this, event]() { 193 | _Update(this, event); 194 | }); 195 | } 196 | break; 197 | case SQLITE_DELETE: 198 | if (deleteChangeHandlers) { 199 | ChangeEvent event; 200 | event.RowId = rowId; 201 | event.TableName = ToPlatformString(tableName); 202 | handler = ref new DispatchedHandler([this, event]() { 203 | _Delete(this, event); 204 | }); 205 | } 206 | break; 207 | } 208 | if (handler) { 209 | dispatcher->RunAsync(CoreDispatcherPriority::Normal, handler); 210 | } 211 | } 212 | } 213 | 214 | IAsyncOperation^ Database::RunAsyncVector(Platform::String^ sql, ParameterVector^ params) { 215 | return RunAsync(sql, CopyParameters(params)); 216 | } 217 | 218 | IAsyncOperation^ Database::RunAsyncMap(Platform::String^ sql, ParameterMap^ params) { 219 | return RunAsync(sql, params); 220 | } 221 | 222 | template 223 | IAsyncOperation^ Database::RunAsync(Platform::String^ sql, ParameterContainer params) { 224 | return Concurrency::create_async([this, sql, params] { 225 | try { 226 | StatementPtr statement = PrepareAndBind(sql, params); 227 | statement->Run(); 228 | return sqlite3_changes(sqlite); 229 | } catch (Platform::Exception^ e) { 230 | saveLastErrorMessage(); 231 | throw; 232 | } 233 | }); 234 | } 235 | 236 | IAsyncOperation^ Database::OneAsyncVector(Platform::String^ sql, ParameterVector^ params) { 237 | return OneAsync(sql, CopyParameters(params)); 238 | } 239 | 240 | IAsyncOperation^ Database::OneAsyncMap(Platform::String^ sql, ParameterMap^ params) { 241 | return OneAsync(sql, params); 242 | } 243 | 244 | template 245 | IAsyncOperation^ Database::OneAsync(Platform::String^ sql, ParameterContainer params) { 246 | return Concurrency::create_async([this, sql, params]() { 247 | try { 248 | StatementPtr statement = PrepareAndBind(sql, params); 249 | return statement->One(); 250 | } catch (Platform::Exception^ e) { 251 | saveLastErrorMessage(); 252 | throw; 253 | } 254 | }); 255 | } 256 | 257 | IAsyncOperation^ Database::AllAsyncMap(Platform::String^ sql, ParameterMap^ params) { 258 | return AllAsync(sql, params); 259 | } 260 | 261 | IAsyncOperation^ Database::AllAsyncVector(Platform::String^ sql, ParameterVector^ params) { 262 | return AllAsync(sql, CopyParameters(params)); 263 | } 264 | 265 | template 266 | IAsyncOperation^ Database::AllAsync(Platform::String^ sql, ParameterContainer params) { 267 | return Concurrency::create_async([this, sql, params]() { 268 | try { 269 | StatementPtr statement = PrepareAndBind(sql, params); 270 | return statement->All(); 271 | } catch (Platform::Exception^ e) { 272 | saveLastErrorMessage(); 273 | throw; 274 | } 275 | }); 276 | } 277 | 278 | IAsyncAction^ Database::EachAsyncVector(Platform::String^ sql, ParameterVector^ params, EachCallback^ callback) { 279 | return EachAsync(sql, CopyParameters(params), callback); 280 | } 281 | 282 | IAsyncAction^ Database::EachAsyncMap(Platform::String^ sql, ParameterMap^ params, EachCallback^ callback) { 283 | return EachAsync(sql, params, callback); 284 | } 285 | 286 | template 287 | IAsyncAction^ Database::EachAsync(Platform::String^ sql, ParameterContainer params, EachCallback^ callback) { 288 | return Concurrency::create_async([this, sql, params, callback] { 289 | try { 290 | StatementPtr statement = PrepareAndBind(sql, params); 291 | statement->Each(callback, dispatcher); 292 | } catch (Platform::Exception^ e) { 293 | saveLastErrorMessage(); 294 | throw; 295 | } 296 | }); 297 | } 298 | 299 | template 300 | StatementPtr Database::PrepareAndBind(Platform::String^ sql, ParameterContainer params) { 301 | StatementPtr statement = Statement::Prepare(sqlite, sql); 302 | statement->Bind(params); 303 | return statement; 304 | } 305 | 306 | void Database::saveLastErrorMessage() { 307 | if (sqlite3_errcode(sqlite) != SQLITE_OK) { 308 | lastErrorMessage = (WCHAR*)sqlite3_errmsg16(sqlite); 309 | } else { 310 | lastErrorMessage.clear(); 311 | } 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /SQLite3Component/Database.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sqlite3.h" 4 | #include "Common.h" 5 | 6 | namespace SQLite3 { 7 | public value struct ChangeEvent { 8 | Platform::String^ TableName; 9 | int64 RowId; 10 | }; 11 | 12 | public delegate void ChangeHandler(Platform::Object^ source, ChangeEvent event); 13 | 14 | public ref class Database sealed { 15 | public: 16 | static IAsyncOperation^ OpenAsync(Platform::String^ dbPath); 17 | 18 | static property bool SharedCache { 19 | bool get() { 20 | return sharedCache; 21 | }; 22 | 23 | void set(bool value) { 24 | int ret = sqlite3_enable_shared_cache(value); 25 | if (ret != SQLITE_OK) { 26 | throwSQLiteError(ret, ref new Platform::String(L"Could not set shared cache")); 27 | } 28 | }; 29 | } 30 | 31 | virtual ~Database(); 32 | 33 | Windows::Foundation::IAsyncOperation^ RunAsyncVector(Platform::String^ sql, ParameterVector^ params); 34 | Windows::Foundation::IAsyncOperation^ RunAsyncMap(Platform::String^ sql, ParameterMap^ params); 35 | Windows::Foundation::IAsyncOperation^ OneAsyncVector(Platform::String^ sql, ParameterVector^ params); 36 | Windows::Foundation::IAsyncOperation^ OneAsyncMap(Platform::String^ sql, ParameterMap^ params); 37 | Windows::Foundation::IAsyncOperation^ AllAsyncVector(Platform::String^ sql, ParameterVector^ params); 38 | Windows::Foundation::IAsyncOperation^ AllAsyncMap(Platform::String^ sql, ParameterMap^ params); 39 | Windows::Foundation::IAsyncAction^ EachAsyncVector(Platform::String^ sql, ParameterVector^ params, EachCallback^ callback); 40 | Windows::Foundation::IAsyncAction^ EachAsyncMap(Platform::String^ sql, ParameterMap^ params, EachCallback^ callback); 41 | 42 | Windows::Foundation::IAsyncAction^ VacuumAsync(); 43 | 44 | property Platform::String^ LastError { 45 | Platform::String^ get() { 46 | return ref new Platform::String(lastErrorMessage.c_str()); 47 | }; 48 | } 49 | 50 | property long long LastInsertRowId { 51 | long long get() { 52 | return sqlite3_last_insert_rowid(sqlite); 53 | }; 54 | } 55 | 56 | property bool AutoCommit { 57 | bool get() { 58 | return sqlite3_get_autocommit(sqlite) != 0; 59 | }; 60 | } 61 | 62 | event ChangeHandler^ Insert { 63 | Windows::Foundation::EventRegistrationToken add(ChangeHandler^ handler) { 64 | addChangeHandler(insertChangeHandlers); 65 | return _Insert += handler; 66 | } 67 | 68 | void remove(Windows::Foundation::EventRegistrationToken token) { 69 | _Insert -= token; 70 | removeChangeHandler(insertChangeHandlers); 71 | } 72 | } 73 | 74 | event ChangeHandler^ Update { 75 | Windows::Foundation::EventRegistrationToken add(ChangeHandler^ handler) { 76 | addChangeHandler(updateChangeHandlers); 77 | return _Update += handler; 78 | } 79 | 80 | void remove(Windows::Foundation::EventRegistrationToken token) { 81 | _Update -= token; 82 | removeChangeHandler(updateChangeHandlers); 83 | } 84 | } 85 | 86 | event ChangeHandler^ Delete { 87 | Windows::Foundation::EventRegistrationToken add(ChangeHandler^ handler) { 88 | addChangeHandler(deleteChangeHandlers); 89 | return _Delete += handler; 90 | } 91 | 92 | void remove(Windows::Foundation::EventRegistrationToken token) { 93 | _Delete -= token; 94 | removeChangeHandler(deleteChangeHandlers); 95 | } 96 | } 97 | 98 | property Platform::String^ CollationLanguage { 99 | Platform::String^ get() { 100 | return collationLanguage; 101 | } 102 | void set(Platform::String^ value) { 103 | collationLanguage = value; 104 | } 105 | } 106 | 107 | property bool FireEvents { 108 | bool get() { 109 | return fireEvents; 110 | }; 111 | void set(bool value) { 112 | fireEvents = value; 113 | }; 114 | } 115 | 116 | private: 117 | static bool sharedCache; 118 | Database(sqlite3* sqlite, Windows::UI::Core::CoreDispatcher^ dispatcher); 119 | 120 | template 121 | StatementPtr PrepareAndBind(Platform::String^ sql, ParameterContainer params); 122 | 123 | template 124 | Windows::Foundation::IAsyncOperation^ RunAsync(Platform::String^ sql, ParameterContainer params); 125 | template 126 | Windows::Foundation::IAsyncOperation^ OneAsync(Platform::String^ sql, ParameterContainer params); 127 | template 128 | Windows::Foundation::IAsyncOperation^ AllAsync(Platform::String^ sql, ParameterContainer params); 129 | template 130 | Windows::Foundation::IAsyncAction^ EachAsync(Platform::String^ sql, ParameterContainer params, EachCallback^ callback); 131 | 132 | static void __cdecl UpdateHook(void* data, int action, char const* dbName, char const* tableName, sqlite3_int64 rowId); 133 | void OnChange(int action, char const* dbName, char const* tableName, sqlite3_int64 rowId); 134 | 135 | bool fireEvents; 136 | Platform::String^ collationLanguage; 137 | Windows::UI::Core::CoreDispatcher^ dispatcher; 138 | sqlite3* sqlite; 139 | std::wstring lastErrorMessage; 140 | 141 | void saveLastErrorMessage(); 142 | 143 | event ChangeHandler^ _Insert; 144 | int insertChangeHandlers; 145 | event ChangeHandler^ _Update; 146 | int updateChangeHandlers; 147 | event ChangeHandler^ _Delete; 148 | int deleteChangeHandlers; 149 | 150 | int changeHandlers; 151 | void addChangeHandler(int& handlerCount); 152 | void removeChangeHandler(int& handlerCount); 153 | }; 154 | } 155 | -------------------------------------------------------------------------------- /SQLite3Component/SQLite3Component.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | false 35 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;%(PreprocessorDefinitions) 36 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;SQLITE_ENABLE_UNLOCK_NOTIFY;_WINRT_DLL;%(PreprocessorDefinitions) 37 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;%(PreprocessorDefinitions) 38 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 39 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 40 | SQLITE_ENABLE_FTS4;SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | $(VCTargetsPath11) 57 | {4cf1ae34-d183-409b-90c3-d62167cff25d} 58 | Win32Proj 59 | SQLite3Component 60 | SQLite3 61 | en-US 62 | 11.0 63 | true 64 | 65 | 66 | 67 | DynamicLibrary 68 | true 69 | v110 70 | 71 | 72 | DynamicLibrary 73 | true 74 | v110 75 | 76 | 77 | DynamicLibrary 78 | true 79 | v110 80 | 81 | 82 | DynamicLibrary 83 | false 84 | true 85 | v110 86 | 87 | 88 | DynamicLibrary 89 | false 90 | true 91 | v110 92 | 93 | 94 | DynamicLibrary 95 | false 96 | true 97 | v110 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | false 122 | 123 | 124 | false 125 | 126 | 127 | false 128 | 129 | 130 | false 131 | 132 | 133 | false 134 | 135 | 136 | false 137 | 138 | 139 | 140 | NotUsing 141 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;SQLITE_ENABLE_UNLOCK_NOTIFY;_WINRT_DLL;%(PreprocessorDefinitions) 142 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 143 | 144 | 145 | Console 146 | runtimeobject.lib;%(AdditionalDependencies) 147 | false 148 | 149 | 150 | 151 | 152 | NotUsing 153 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 154 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 155 | 156 | 157 | Console 158 | runtimeobject.lib;%(AdditionalDependencies) 159 | false 160 | 161 | 162 | 163 | 164 | NotUsing 165 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;%(PreprocessorDefinitions) 166 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 167 | 168 | 169 | Console 170 | runtimeobject.lib;%(AdditionalDependencies) 171 | false 172 | 173 | 174 | 175 | 176 | NotUsing 177 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 178 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 179 | 180 | 181 | Console 182 | runtimeobject.lib;%(AdditionalDependencies) 183 | false 184 | 185 | 186 | 187 | 188 | NotUsing 189 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;%(PreprocessorDefinitions) 190 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 191 | 192 | 193 | Console 194 | runtimeobject.lib;%(AdditionalDependencies) 195 | false 196 | NotSet 197 | 198 | 199 | 200 | 201 | NotUsing 202 | SQLITE_OS_WINRT;SQLITE_ENABLE_UNLOCK_NOTIFY;SQLITE_TEMP_STORE=2;_WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) 203 | $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) 204 | 205 | 206 | Console 207 | runtimeobject.lib;%(AdditionalDependencies) 208 | false 209 | NotSet 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /SQLite3Component/Statement.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "Statement.h" 13 | #include "Database.h" 14 | 15 | namespace SQLite3 { 16 | StatementPtr Statement::Prepare(sqlite3* sqlite, Platform::String^ sql) { 17 | sqlite3_stmt* statement; 18 | int ret = sqlite3_prepare16(sqlite, sql->Data(), -1, &statement, 0); 19 | 20 | if (ret != SQLITE_OK) { 21 | sqlite3_finalize(statement); 22 | throwSQLiteError(ret, sql); 23 | } 24 | 25 | return StatementPtr(new Statement(statement)); 26 | } 27 | 28 | Statement::Statement(sqlite3_stmt* statement) 29 | : statement(statement) { 30 | } 31 | 32 | Statement::~Statement() { 33 | sqlite3_finalize(statement); 34 | } 35 | 36 | void Statement::Bind(const SafeParameterVector& params) { 37 | for (SafeParameterVector::size_type i = 0; i < params.size(); ++i) { 38 | BindParameter(static_cast(i + 1), params[i]); 39 | } 40 | } 41 | 42 | void Statement::Bind(ParameterMap^ params) { 43 | if (!params) { 44 | return; 45 | } 46 | 47 | for (int i = 0; i < BindParameterCount(); ++i) { 48 | int index = i + 1; 49 | auto nameWithoutPrefix = BindParameterName(index).substr(1); 50 | auto name = ref new Platform::String(nameWithoutPrefix.data()); 51 | if (params->HasKey(name)) { 52 | BindParameter(index, params->Lookup(name)); 53 | } 54 | } 55 | } 56 | 57 | static inline uint64 FoundationTimeToUnixCompatible(Windows::Foundation::DateTime foundationTime) { 58 | return (foundationTime.UniversalTime / 10000) - 11644473600000; 59 | } 60 | 61 | void Statement::BindParameter(int index, Platform::Object^ value) { 62 | int result; 63 | if (value == nullptr) { 64 | result = sqlite3_bind_null(statement, index); 65 | } else { 66 | auto typeCode = Platform::Type::GetTypeCode(value->GetType()); 67 | switch (typeCode) { 68 | case Platform::TypeCode::DateTime: 69 | result = sqlite3_bind_int64(statement, index, FoundationTimeToUnixCompatible(static_cast(value))); 70 | break; 71 | case Platform::TypeCode::Double: 72 | result = sqlite3_bind_double(statement, index, static_cast(value)); 73 | break; 74 | case Platform::TypeCode::String: 75 | result = sqlite3_bind_text16(statement, index, static_cast(value)->Data(), -1, SQLITE_TRANSIENT); 76 | break; 77 | case Platform::TypeCode::Boolean: 78 | result = sqlite3_bind_int(statement, index, static_cast(value) ? 1 : 0); 79 | break; 80 | case Platform::TypeCode::Int8: 81 | case Platform::TypeCode::Int16: 82 | case Platform::TypeCode::Int32: 83 | case Platform::TypeCode::UInt8: 84 | case Platform::TypeCode::UInt16: 85 | case Platform::TypeCode::UInt32: 86 | result = sqlite3_bind_int(statement, index, static_cast(value)); 87 | break; 88 | case Platform::TypeCode::Int64: 89 | case Platform::TypeCode::UInt64: 90 | result = sqlite3_bind_int64(statement, index, static_cast(value)); 91 | break; 92 | case Platform::TypeCode::Object: { 93 | auto buffer= winrt_as(value); 94 | if (buffer) { 95 | auto byteBuffer= winrt_as(value); 96 | byte* blob; 97 | byteBuffer->Buffer(&blob); 98 | uint32 length; 99 | buffer->get_Length(&length); 100 | result = sqlite3_bind_blob(statement, index, blob, length, 0); 101 | } else { 102 | result = SQLITE_MISMATCH; 103 | } 104 | } 105 | break; 106 | default: 107 | result = SQLITE_MISMATCH; 108 | } 109 | } 110 | if (result != SQLITE_OK) { 111 | std::wostringstream message; 112 | message << L"Could not bind parameter " 113 | << index 114 | << L" to " 115 | << value->ToString()->Data() 116 | << L" because it has a wrong type " 117 | << value->GetType()->FullName->Data(); 118 | throwSQLiteError(result, ref new Platform::String(message.str().c_str())); 119 | } 120 | } 121 | 122 | int Statement::BindParameterCount() { 123 | return sqlite3_bind_parameter_count(statement); 124 | } 125 | 126 | std::wstring Statement::BindParameterName(int index) { 127 | return ToWString(sqlite3_bind_parameter_name(statement, index)); 128 | } 129 | 130 | void Statement::Run() { 131 | Step(); 132 | } 133 | 134 | Platform::String^ Statement::One() { 135 | std::wostringstream result; 136 | if (Step() == SQLITE_ROW) { 137 | GetRow(result); 138 | return ref new Platform::String(result.str().c_str()); 139 | } else { 140 | return nullptr; 141 | } 142 | } 143 | 144 | Platform::String^ Statement::All() { 145 | std::wostringstream result; 146 | result << L"["; 147 | auto stepResult = Step(); 148 | bool hasData = (stepResult == SQLITE_ROW); 149 | while (stepResult == SQLITE_ROW) { 150 | GetRow(result); 151 | result << L","; 152 | stepResult = Step(); 153 | } 154 | if (hasData) { 155 | std::streamoff pos = result.tellp(); 156 | result.seekp(pos-1); 157 | } 158 | result << L"]"; 159 | return ref new Platform::String(result.str().c_str()); 160 | } 161 | 162 | void Statement::Each(EachCallback^ callback, Windows::UI::Core::CoreDispatcher^ dispatcher) { 163 | while (Step() == SQLITE_ROW) { 164 | std::wostringstream output; 165 | GetRow(output); 166 | auto row = ref new Platform::String(output.str().c_str()); 167 | auto callbackTask = Concurrency::task( 168 | dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, 169 | ref new Windows::UI::Core::DispatchedHandler([row, callback]() { 170 | callback(row); 171 | })) 172 | ); 173 | callbackTask.get(); 174 | } 175 | } 176 | 177 | 178 | int Statement::Step() { 179 | int ret = sqlite3_step(statement); 180 | 181 | if (ret != SQLITE_ROW && ret != SQLITE_DONE) { 182 | throwSQLiteError(ret, ref new Platform::String(L"Could not step statement")); 183 | } 184 | 185 | return ret; 186 | } 187 | 188 | bool Statement::ReadOnly() const { 189 | return sqlite3_stmt_readonly(statement) != 0; 190 | } 191 | 192 | void writeEscaped(const std::wstring& s, std::wostringstream& out) { 193 | out << L'"'; 194 | for (std::wstring::const_iterator i = s.begin(), end = s.end(); i != end; ++i) { 195 | wchar_t c = *i; 196 | if (L' ' <= c && c <= L'~' && c != L'\\' && c != L'"') { 197 | out << *i; 198 | } 199 | else { 200 | out << L'\\'; 201 | switch(c) { 202 | case L'"': out << L'"'; break; 203 | case L'\\': out << L'\\'; break; 204 | case L'\t': out << L't'; break; 205 | case L'\r': out << L'r'; break; 206 | case L'\n': out << L'n'; break; 207 | default: 208 | out << L'u'; 209 | out << std::setw(4) << std::setfill(L'0') << std::hex << (WORD)c; 210 | } 211 | } 212 | } 213 | out << L'"'; 214 | } 215 | 216 | void Statement::GetRow(std::wostringstream& outstream) { 217 | outstream << L'{'; 218 | int columnCount = ColumnCount(); 219 | for (int i = 0; i < columnCount; ++i) { 220 | auto colName = static_cast(sqlite3_column_name16(statement, i)); 221 | auto colType = ColumnType(i); 222 | outstream << L'"' << colName << L"\":"; 223 | switch (colType) { 224 | case SQLITE_TEXT: { 225 | auto colValue = static_cast(sqlite3_column_text16(statement, i)); 226 | writeEscaped(colValue, outstream); 227 | } 228 | break; 229 | case SQLITE_INTEGER: 230 | case SQLITE_FLOAT: { 231 | auto colValue = static_cast(sqlite3_column_text16(statement, i)); 232 | outstream << colValue; 233 | } 234 | break; 235 | case SQLITE_BLOB: { 236 | auto blob = (byte*)sqlite3_column_blob(statement, i); 237 | const int blobSize = sqlite3_column_bytes(statement, i); 238 | Platform::ArrayReference blobArray(blob, blobSize); 239 | using Windows::Security::Cryptography::CryptographicBuffer; 240 | auto base64Text = CryptographicBuffer::EncodeToBase64String(CryptographicBuffer::CreateFromByteArray(blobArray)); 241 | outstream << L'"' << base64Text->Data() << L'"'; 242 | } 243 | break; 244 | case SQLITE_NULL: 245 | outstream << L"null"; 246 | break; 247 | } 248 | outstream << L','; 249 | } 250 | std::streamoff pos = outstream.tellp(); 251 | outstream.seekp(pos - 1l); 252 | outstream << L'}'; 253 | } 254 | 255 | int Statement::ColumnCount() { 256 | return sqlite3_column_count(statement); 257 | } 258 | 259 | int Statement::ColumnType(int index) { 260 | return sqlite3_column_type(statement, index); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /SQLite3Component/Statement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sqlite3.h" 4 | #include "Common.h" 5 | 6 | namespace SQLite3 { 7 | class Statement { 8 | public: 9 | static StatementPtr Prepare(sqlite3* sqlite, Platform::String^ sql); 10 | ~Statement(); 11 | 12 | void Bind(const SafeParameterVector& params); 13 | void Bind(ParameterMap^ params); 14 | 15 | void Run(); 16 | Platform::String^ One(); 17 | Platform::String^ All(); 18 | void Each(EachCallback^ callback, Windows::UI::Core::CoreDispatcher^ dispatcher); 19 | 20 | bool ReadOnly() const; 21 | 22 | private: 23 | Statement(sqlite3_stmt* statement); 24 | 25 | void BindParameter(int index, Platform::Object^ value); 26 | int BindParameterCount(); 27 | std::wstring BindParameterName(int index); 28 | 29 | int Step(); 30 | void GetRow(std::wostringstream& row); 31 | 32 | int ColumnCount(); 33 | int ColumnType(int index); 34 | 35 | private: 36 | HANDLE dbLockMutex; 37 | sqlite3_stmt* statement; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /SQLite3Component/res/component_manifest.h: -------------------------------------------------------------------------------- 1 | #define COMPONENT_NAME "SQLite3" 2 | #define COMPONENT_DESCRIPTION "SQLite3 WinRT Component" 3 | 4 | #define COMPONENT_VERSION_MAJOR 1 5 | #define COMPONENT_VERSION_MINOR 2 6 | #define COMPONENT_VERSION_BUILD 4 7 | #define COMPONENT_VERSION_REVISION 0 8 | 9 | #define _VERSION_STR(a,b,c,d) #a "." #b "." #c "." #d 10 | #define VERSION_STR(a,b,c,d) _VERSION_STR(a,b,c,d) 11 | 12 | #define COMPONENT_COMPANY_NAME "doo GmbH" 13 | #define COMPONENT_COPYRIGHT "(c)2012,2013 " COMPONENT_COMPANY_NAME 14 | -------------------------------------------------------------------------------- /SQLite3Component/res/component_manifest.rc: -------------------------------------------------------------------------------- 1 | #ifdef APSTUDIO_INVOKED 2 | #error this file cannot be edited in MSDEV. It should not be edited anyway. 3 | #else 4 | 5 | // Include a "component_manifest.h" file the project that contains this bundle_manifest.rc file. 6 | // If you place the "bundle_manifest.h" not in your projects root, you need to specify "Additional Include Directories" for this .rc file. 7 | #include "component_manifest.h" 8 | 9 | #ifndef COMPONENT_NAME 10 | #error You forgot to #define COMPONENT_NAME in your component_manifest.h 11 | #endif 12 | 13 | #ifndef COMPONENT_DESCRIPTION 14 | #error You forgot to #define COMPONENT_DESCRIPTION in your component_manifest.h 15 | #endif 16 | 17 | #ifndef COMPONENT_VERSION_MAJOR 18 | #error You forgot to #define COMPONENT_VERSION_MAJOR in your component_manifest.h 19 | #endif 20 | 21 | #ifndef COMPONENT_VERSION_MINOR 22 | #error You forgot to #define COMPONENT_VERSION_MINOR in your component_manifest.h 23 | #endif 24 | 25 | #ifndef COMPONENT_VERSION_BUILD 26 | #define COMPONENT_VERSION_BUILD 0 27 | #endif 28 | 29 | #ifndef COMPONENT_VERSION_REVISION 30 | #define COMPONENT_VERSION_REVISION 0 31 | #endif 32 | 33 | #ifndef COMPONENT_VERSION_STRING 34 | #define COMPONENT_VERSION_STRING VERSION_STR(COMPONENT_VERSION_MAJOR,COMPONENT_VERSION_MINOR,COMPONENT_VERSION_BUILD,COMPONENT_VERSION_REVISION) 35 | #endif 36 | 37 | #ifndef COMPONENT_VERSION 38 | #define COMPONENT_VERSION COMPONENT_VERSION_MAJOR,COMPONENT_VERSION_MINOR,0,COMPONENT_VERSION_BUILD 39 | #endif 40 | 41 | #ifndef COMPONENT_ORIGINAL_FILENAME 42 | #define COMPONENT_ORIGINAL_FILENAME COMPONENT_NAME ".dll" 43 | #endif 44 | 45 | #include "winres.h" 46 | 47 | #ifdef _WIN32 48 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 49 | #pragma code_page(1252) 50 | #endif //_WIN32 51 | 52 | VS_VERSION_INFO VERSIONINFO 53 | FILEVERSION COMPONENT_VERSION 54 | #ifdef PRODUCT_VERSION 55 | PRODUCTVERSION PRODUCT_VERSION 56 | #endif 57 | FILEFLAGSMASK 0x17L 58 | #ifdef _DEBUG 59 | FILEFLAGS VS_FF_DEBUG 60 | #else 61 | FILEFLAGS 0x0L 62 | #endif 63 | FILEOS VOS_NT_WINDOWS32 64 | FILETYPE VFT_DLL 65 | FILESUBTYPE 0x0L 66 | BEGIN 67 | BLOCK "StringFileInfo" 68 | BEGIN 69 | BLOCK "040904b0" 70 | BEGIN 71 | // If you hit an error here, define COMPONENT_DESCRIPTION in your component_manifest.h 72 | VALUE "FileDescription", COMPONENT_DESCRIPTION 73 | VALUE "FileVersion", COMPONENT_VERSION_STRING 74 | // If you hit an error here, define COMPONENT_NAME in your component_manifest.h 75 | VALUE "InternalName", COMPONENT_NAME 76 | VALUE "OriginalFilename", COMPONENT_ORIGINAL_FILENAME 77 | 78 | VALUE "CompanyName", COMPONENT_COMPANY_NAME 79 | VALUE "LegalCopyright", COMPONENT_COPYRIGHT 80 | #ifdef PRODUCT_NAME 81 | VALUE "ProductName", PRODUCT_NAME 82 | VALUE "ProductVersion", PRODUCT_VERSION_STRING 83 | #endif 84 | VALUE "Internet", "https://doo.net" 85 | #ifdef COMPONENT_AUTHOR 86 | VALUE "Author", COMPONENT_AUTHOR 87 | #endif 88 | END 89 | END 90 | BLOCK "VarFileInfo" 91 | BEGIN 92 | VALUE "Translation", 0x409, 1200 93 | END 94 | END 95 | #endif -------------------------------------------------------------------------------- /SQLite3JS/SQLite3JS.jsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | Debug 10 | ARM 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Debug 18 | x86 19 | 20 | 21 | Release 22 | AnyCPU 23 | 24 | 25 | Release 26 | ARM 27 | 28 | 29 | Release 30 | x64 31 | 32 | 33 | Release 34 | x86 35 | 36 | 37 | 38 | 1a1e8060-a03c-449c-931c-6bceec16e82f 39 | 40 | 41 | 42 | 43 | 44 | Windows 45 | 8.0 46 | en-US 47 | 80A7CD2B5844DCF3B6E40C04CE4327669B0CAC18 48 | SQLite3JS_TemporaryKey.pfx 49 | 50 | 51 | 52 | Designer 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /SQLite3JS/SQLite3JS_TemporaryKey.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/SQLite3JS_TemporaryKey.pfx -------------------------------------------------------------------------------- /SQLite3JS/config.js: -------------------------------------------------------------------------------- 1 | spec.config.jslintPredefines = ["SQLite3JS", "SQLite3"]; 2 | spec.config.junitReport = true; 3 | spec.config.suitesToRun = []; -------------------------------------------------------------------------------- /SQLite3JS/default.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Specs 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /SQLite3JS/examples/blobs.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Blobs 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /SQLite3JS/examples/blobs.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | var dbPath = Windows.Storage.ApplicationData.current.localFolder.path + '\\db.sqlite', 5 | Package = Windows.ApplicationModel.Package; 6 | 7 | // Wait for DOM to be ready 8 | WinJS.Utilities.ready().then(function () { 9 | return SQLite3JS.openAsync(dbPath); 10 | }).then(function (db) { 11 | return db.runAsync('CREATE TABLE IF NOT EXISTS images (id INT PRIMARY KEY, image BLOB)') 12 | .then(function () { 13 | // Get an image to insert into the database as blob 14 | return Package.current.installedLocation.getFileAsync("images\\logo.png"); 15 | }).then(function (file) { 16 | return Windows.Storage.FileIO.readBufferAsync(file); 17 | }).then(function (buffer) { 18 | return db.runAsync('INSERT INTO images (image) VALUES (?)', [buffer]); 19 | }).then(function () { 20 | var div; 21 | return db.eachAsync('SELECT image FROM images', function (row) { 22 | div = document.createElement("img"); 23 | div.src = 'data:image/png;base64,' + row.image; 24 | document.body.appendChild(div); 25 | }); 26 | }).then(function () { 27 | return db.runAsync("DROP TABLE images"); 28 | }).then(function () { 29 | db.close(); 30 | }); 31 | }); 32 | 33 | }()); -------------------------------------------------------------------------------- /SQLite3JS/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/images/logo.png -------------------------------------------------------------------------------- /SQLite3JS/images/smalllogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/images/smalllogo.png -------------------------------------------------------------------------------- /SQLite3JS/images/splashscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/images/splashscreen.png -------------------------------------------------------------------------------- /SQLite3JS/images/storelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/images/storelogo.png -------------------------------------------------------------------------------- /SQLite3JS/images/widelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doo/SQLite3-WinRT/346093d473898f2ec4dcab101d638bd13c4f0a7e/SQLite3JS/images/widelogo.png -------------------------------------------------------------------------------- /SQLite3JS/js/SQLite3.js: -------------------------------------------------------------------------------- 1 | var SQLite3JS = (function () { 2 | "use strict"; 3 | 4 | var SQLite3JS, Database, ItemDataSource, GroupDataSource; 5 | 6 | SQLite3JS = { 7 | /// Set this to true to get some more logging output 8 | debug: false, 9 | logger: { 10 | trace: console.log.bind(console), 11 | warn: console.warn.bind(console), 12 | error: console.error.bind(console), 13 | info: console.info.bind(console) 14 | } 15 | }; 16 | 17 | function PromiseQueue() { 18 | this._items = []; 19 | this._busy = false; 20 | } 21 | 22 | PromiseQueue.prototype.append = function (createPromise) { 23 | var wrappingPromise, 24 | queueItem = { createPromise: createPromise }, 25 | _this = this; 26 | 27 | wrappingPromise = new WinJS.Promise(function (complete, error) { 28 | queueItem.complete = complete; 29 | queueItem.error = error; 30 | }, function () { 31 | if (queueItem.promise) { 32 | queueItem.promise.cancel(); 33 | } else { 34 | queueItem.cancelled = true; 35 | } 36 | 37 | _this._handleNext(); 38 | }); 39 | 40 | this._items.push(queueItem); 41 | if (!this._busy) { 42 | this._handleNext(); 43 | } 44 | 45 | return wrappingPromise; 46 | }; 47 | 48 | PromiseQueue.prototype._handleNext = function () { 49 | var _this = this; 50 | /* shorten call stack */ 51 | this._busy = true; 52 | setImmediate(function () { 53 | if (_this._items.length > 0) { 54 | var nextItem = _this._items[0]; 55 | _this._items = _this._items.slice(1); 56 | _this._handleItem(nextItem); 57 | } else { 58 | _this._busy = false; 59 | } 60 | }); 61 | }; 62 | 63 | PromiseQueue.prototype._handleItem = function (queueItem) { 64 | var _this = this; 65 | 66 | if (!queueItem.cancelled) { 67 | queueItem.promise = queueItem.createPromise(); 68 | queueItem.promise.done(function (result) { 69 | _this._handleNext(); 70 | queueItem.complete(result); 71 | }, function (error) { 72 | _this._handleNext(); 73 | queueItem.error(error); 74 | }); 75 | } else { 76 | this._handleNext(); 77 | } 78 | }; 79 | 80 | function toPropertySet(object) { 81 | var key, propertySet = new Windows.Foundation.Collections.PropertySet(); 82 | 83 | for (key in object) { 84 | if (object.hasOwnProperty(key)) { 85 | propertySet.insert(key, object[key]); 86 | } 87 | } 88 | 89 | return propertySet; 90 | } 91 | 92 | function prepareArgs(args) { 93 | args = args || []; 94 | return (args instanceof Array) ? args : toPropertySet(args); 95 | } 96 | 97 | function formatStatementAndArgs(sql, args) { 98 | var argString = args ? ' ' + args.toString() : ''; 99 | return '"' + sql + '", ' + argString; 100 | } 101 | 102 | function wrapException(exception, detailedMessage, functionName, sql, args) { 103 | var error, message, resultCode, number; 104 | 105 | if (exception.hasOwnProperty('number')) { 106 | // Convert the COM error to an unsigned hex value that we can check in JS like E_FAIL == 0x80004005 107 | number = 0xffffffff + exception.number + 1; 108 | resultCode = number & 0x20000000 ? exception.number & 0xffff : 0; 109 | message = (resultCode > 0 ? resultCode : "0x" + number.toString(16)) + ": "; 110 | if (functionName) { 111 | message += functionName; 112 | 113 | if (sql) { 114 | message += '(' + formatStatementAndArgs(sql, args) + ') '; 115 | } else { 116 | message += " "; 117 | } 118 | } 119 | if (detailedMessage) { 120 | message += detailedMessage; 121 | } 122 | error = new WinJS.ErrorFromName("SQLiteError", message); 123 | error.resultCode = resultCode; 124 | error.number = number; 125 | error.sql = sql; 126 | error.args = args; 127 | error.functionName = functionName; 128 | } else { 129 | error = exception; 130 | } 131 | 132 | return WinJS.Promise.wrapError(error); 133 | } 134 | 135 | function wrapDatabase(connection) { 136 | var that, queue = new PromiseQueue(); 137 | 138 | function callNativeAsync(funcName, sql, args, callback) { 139 | var argString, preparedArgs, fullFuncName; 140 | 141 | return queue.append(function () { 142 | if (SQLite3JS.debug) { 143 | SQLite3JS.logger.trace(funcName + ': ' + formatStatementAndArgs(sql, args)); 144 | } 145 | preparedArgs = prepareArgs(args); 146 | fullFuncName = 147 | preparedArgs instanceof Windows.Foundation.Collections.PropertySet 148 | ? funcName + "Map" 149 | : funcName + "Vector"; 150 | 151 | return connection[fullFuncName](sql, preparedArgs, callback).then(null, function (error) { 152 | return wrapException(error, that.lastError, funcName, sql, args); 153 | }); 154 | }); 155 | } 156 | 157 | that = { 158 | runAsync: function (sql, args) { 159 | return callNativeAsync('runAsync', sql, args).then(function (affectedRowCount) { 160 | return affectedRowCount; 161 | }); 162 | }, 163 | oneAsync: function (sql, args) { 164 | return callNativeAsync('oneAsync', sql, args).then(function (row) { 165 | return row ? JSON.parse(row) : null; 166 | }); 167 | }, 168 | allAsync: function (sql, args) { 169 | return callNativeAsync('allAsync', sql, args).then(function (rows) { 170 | return rows ? JSON.parse(rows) : null; 171 | }); 172 | }, 173 | eachAsync: function (sql, args, callback) { 174 | if (!callback && typeof args === 'function') { 175 | callback = args; 176 | args = undefined; 177 | } 178 | 179 | return callNativeAsync('eachAsync', sql, args, function (row) { 180 | callback(JSON.parse(row)); 181 | }).then(function () { 182 | return that; 183 | }); 184 | }, 185 | mapAsync: function (sql, args, callback) { 186 | if (!callback && typeof args === 'function') { 187 | callback = args; 188 | args = undefined; 189 | } 190 | 191 | var results = []; 192 | 193 | return that.eachAsync(sql, args, function (row) { 194 | results.push(callback(row)); 195 | }).then(function () { 196 | return results; 197 | }); 198 | }, 199 | itemDataSource: function (sql, args, keyColumnName, groupKeyColumnName) { 200 | if (typeof args === 'string') { 201 | groupKeyColumnName = keyColumnName; 202 | keyColumnName = args; 203 | args = undefined; 204 | } 205 | 206 | return new ItemDataSource(that, sql, args, keyColumnName, groupKeyColumnName); 207 | }, 208 | groupDataSource: function (sql, args, keyColumnName, sizeColumnName) { 209 | if (typeof args === 'string') { 210 | sizeColumnName = keyColumnName; 211 | keyColumnName = args; 212 | args = undefined; 213 | } 214 | 215 | return new GroupDataSource(that, sql, args, keyColumnName, sizeColumnName); 216 | }, 217 | close: function () { 218 | connection.close(); 219 | }, 220 | vacuumAsync: function () { 221 | return new WinJS.Promise( function(complete) { 222 | connection.vacuumAsync(); 223 | complete(); 224 | }); 225 | }, 226 | addEventListener: connection.addEventListener.bind(connection), 227 | removeEventListener: connection.removeEventListener.bind(connection) 228 | }; 229 | 230 | Object.defineProperties( 231 | that, 232 | WinJS.Utilities.createEventProperties('update', 'delete', 'insert') 233 | ); 234 | 235 | Object.defineProperties(that, { 236 | "collationLanguage": { 237 | set: function (value) { connection.collationLanguage = value; }, 238 | get: function () { return connection.collationLanguage; }, 239 | enumerable: true 240 | }, 241 | "fireEvents": { 242 | set: function (value) { connection.fireEvents = value; }, 243 | get: function () { return connection.fireEvents; }, 244 | enumerable: true 245 | }, 246 | "lastError": { 247 | get: function () { return connection.lastError; }, 248 | enumerable: true 249 | }, 250 | "autoCommit": { 251 | get: function () { return connection.autoCommit; }, 252 | enumerable: true 253 | }, 254 | "lastInsertRowId": { 255 | get: function () { return connection.lastInsertRowId; }, 256 | enumerable: true 257 | } 258 | }); 259 | 260 | return that; 261 | } 262 | 263 | ItemDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, 264 | function (db, sql, args, keyColumnName, groupKeyColumnName) { 265 | this._dataAdapter = { 266 | setQuery: function (sql, args) { 267 | this._sql = sql; 268 | this._args = args; 269 | }, 270 | getCount: function () { 271 | return db.oneAsync('SELECT COUNT(*) AS cnt FROM (' + this._sql + ')', this._args) 272 | .then(function (row) { return row.cnt; }); 273 | }, 274 | itemsFromIndex: function (requestIndex, countBefore, countAfter) { 275 | var items, 276 | limit = countBefore + 1 + countAfter, 277 | offset = requestIndex - countBefore, 278 | that = this; 279 | 280 | return this.getCount().then(function (totalCount) { 281 | return db.mapAsync( 282 | 'SELECT * FROM (' + that._sql + ') LIMIT ' + limit + ' OFFSET ' + offset, 283 | that._args, 284 | function (row) { 285 | var item = { 286 | key: row[keyColumnName].toString(), 287 | data: row 288 | }; 289 | if (groupKeyColumnName) { 290 | if (!row.hasOwnProperty(groupKeyColumnName) || row[groupKeyColumnName] === null) { 291 | throw "Group key property not found: " + groupKeyColumnName; 292 | } 293 | item.groupKey = row[groupKeyColumnName].toString(); 294 | } 295 | return item; 296 | }).then(function (items) { 297 | return { 298 | items: items, 299 | offset: countBefore, 300 | totalCount: totalCount 301 | }; 302 | }); 303 | }); 304 | }, 305 | setNotificationHandler: function (notificationHandler) { 306 | this._notificationHandler = notificationHandler; 307 | }, 308 | getNotificationHandler: function () { 309 | return this._notificationHandler; 310 | } 311 | }; 312 | 313 | this._dataAdapter.setQuery(sql, args); 314 | this._baseDataSourceConstructor(this._dataAdapter); 315 | }, { 316 | setQuery: function (sql, args) { 317 | this._dataAdapter.setQuery(sql, args); 318 | this.invalidateAll(); 319 | }, 320 | getNotificationHandler: function () { 321 | return this._dataAdapter.getNotificationHandler(); 322 | } 323 | } 324 | ); 325 | 326 | GroupDataSource = WinJS.Class.derive(WinJS.UI.VirtualizedDataSource, 327 | function (db, sql, args, keyColumnName, sizeColumnName) { 328 | var dataAdapter = { 329 | _keyIndexMap: {}, 330 | _ensureGroupsAsync: function () { 331 | if (dataAdapter._groups) { 332 | return WinJS.Promise.wrap(); 333 | } 334 | 335 | var groupIndex = 0, 336 | firstItemIndex = 0; 337 | return db.mapAsync(sql, args, function (row) { 338 | var item = { 339 | key: row[keyColumnName].toString(), 340 | groupSize: row[sizeColumnName], 341 | firstItemIndexHint: firstItemIndex, 342 | data: row 343 | }; 344 | 345 | dataAdapter._keyIndexMap[item.key] = groupIndex; 346 | groupIndex += 1; 347 | firstItemIndex += item.groupSize; 348 | 349 | return item; 350 | }).then(function (groups) { 351 | dataAdapter._groups = groups.filter(function (group) { return group.groupSize > 0; }); 352 | }); 353 | }, 354 | getCount: function () { 355 | return dataAdapter._ensureGroupsAsync().then(function () { 356 | return dataAdapter._groups.length; 357 | }); 358 | }, 359 | itemsFromIndex: function (requestIndex, countBefore, countAfter) { 360 | return dataAdapter._ensureGroupsAsync().then(function () { 361 | return { 362 | items: dataAdapter._groups.slice(), 363 | offset: requestIndex, 364 | absoluteIndex: requestIndex, 365 | totalCount: dataAdapter._groups.length, 366 | atStart: true, 367 | atEnd: true 368 | }; 369 | }); 370 | }, 371 | itemsFromKey: function (key, countBefore, countAfter) { 372 | return dataAdapter._ensureGroupsAsync().then(function () { 373 | return dataAdapter.itemsFromIndex(dataAdapter._keyIndexMap[key], countBefore, countAfter); 374 | }); 375 | }, 376 | setNotificationHandler: function (notificationHandler) { 377 | this._notificationHandler = notificationHandler; 378 | }, 379 | getNotificationHandler: function () { 380 | return this._notificationHandler; 381 | } 382 | }; 383 | this._dataAdapter = dataAdapter; 384 | this._baseDataSourceConstructor(dataAdapter); 385 | }, { 386 | getNotificationHandler: function () { 387 | return this._dataAdapter.getNotificationHandler(); 388 | } 389 | } 390 | ); 391 | 392 | SQLite3JS.openAsync = function (dbPath) { 393 | /// 394 | /// Opens a database from disk or in memory. 395 | /// 396 | /// 397 | /// Path to a file that is located in your apps local/temp/roaming storage or the string ":memory:" 398 | /// to create a database in memory 399 | /// 400 | /// Database object upon completion of the promise 401 | return SQLite3.Database.openAsync(dbPath) 402 | .then(function opened(connection) { 403 | var db = wrapDatabase(connection); 404 | if (SQLite3JS.version) { 405 | return db; 406 | } 407 | return db.oneAsync("SELECT sqlite_version() || ' (' || sqlite_source_id() || ')' as version") 408 | .then(function (result) { 409 | SQLite3JS.logger.info("SQLite3 version: " + (SQLite3JS.version = result.version)); 410 | return db; 411 | }); 412 | }, function onerror(error) { 413 | return wrapException(error, 'Could not open database "' + dbPath + '"', "openAsync"); 414 | }); 415 | }; 416 | 417 | return SQLite3JS; 418 | }()); 419 | -------------------------------------------------------------------------------- /SQLite3JS/js/tests/background.js: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /SQLite3JS/js/tests/jasmineRunner.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | function require(path) { 5 | var element = document.createElement("script"); 6 | element.src = path; 7 | console.info("Require script " + element.src); 8 | document.head.appendChild(element); 9 | } 10 | 11 | NodeList.prototype.forEach = Array.prototype.forEach; 12 | 13 | function isPartOfSuite(suite, name) { 14 | if (!suite) { 15 | return false; 16 | } 17 | if (suite.description === name) { 18 | return true; 19 | } 20 | if (suite.getFullName() === name) { 21 | return true; 22 | } 23 | return isPartOfSuite(suite.parentSuite, name); 24 | } 25 | 26 | function async(testFunc, timeout, message) { 27 | var done, testFuncPromise; 28 | done = false; 29 | if (testFunc.then && typeof testFunc.then === "function") { 30 | testFuncPromise = testFunc; 31 | } else { 32 | testFuncPromise = new WinJS.Promise(function (complete) { 33 | return complete(testFunc()); 34 | }); 35 | } 36 | testFuncPromise.done(function () { 37 | done = true; 38 | }, function (error) { 39 | jasmine.getEnv().currentSpec.fail(error.message); 40 | done = true; 41 | }); 42 | return waitsFor(function () { 43 | return done; 44 | }, message, timeout); 45 | } 46 | 47 | function lintFileAsync(file, predefines) { 48 | var options = { 49 | white: true, 50 | nomen: true, 51 | bitwise: true, 52 | predef: [ 53 | "JSLINT", "window", 'WinJS', 'Windows', 'console', 'document', 'setImmediate' 54 | ].concat(predefines || []) 55 | }; 56 | return Windows.Storage.PathIO.readTextAsync(file).then(function fileRead(fileContent) { 57 | if (!JSLINT(fileContent, options)) { 58 | var error, message = "The file " + file + " contains the following errors:\n"; 59 | message += JSLINT.errors.map(function format(error) { 60 | if (error) { 61 | return error.reason + " at line " + error.line + ", column " + error.character; 62 | } 63 | return "JSLint gave up"; 64 | }).join("\n"); 65 | error = new WinJS.ErrorFromName("JSLintError", message); 66 | error.errors = JSLINT.errors; 67 | error.htmlReport = JSLINT.report(true); 68 | throw error; 69 | } 70 | }); 71 | } 72 | 73 | WinJS.Namespace.define("spec", { 74 | async: async, 75 | lintFileAsync: lintFileAsync, 76 | require: require, 77 | config: {} 78 | }); 79 | 80 | function loadSpecsAsync() { 81 | return Windows.ApplicationModel.Package.current.installedLocation.getFolderAsync("spec").then(function gotFolder(folder) { 82 | var queryOptions = new Windows.Storage.Search.QueryOptions(Windows.Storage.Search.CommonFileQuery.orderByName, [".js"]), 83 | query = folder.createFileQueryWithOptions(queryOptions); 84 | return query.getFilesAsync().then(function (files) { 85 | files.forEach(function (file) { 86 | var element = document.createElement("script"); 87 | element.src = "/spec/" + file.name; 88 | console.info("Loading spec " + element.src); 89 | document.head.appendChild(element); 90 | }); 91 | }); 92 | }); 93 | } 94 | 95 | describe("JSLint", function () { 96 | it("should evaluate all javascript code just fine", function () { 97 | var jsLintPredefines = ["require", "spec", 'jasmine', 'describe', 'xdescribe', 'it', 'xit', 'beforeEach', 'afterEach', 98 | 'expect', 'runs', "waitsFor"].concat(spec.config.jslintPredefines || []), 99 | completePromise = WinJS.Promise.as(); 100 | document.head.querySelectorAll("script:not([data-jslint=false])").forEach(function (scriptElement) { 101 | console.info("JSLinting " + scriptElement.src); 102 | var predefines = (scriptElement.getAttribute("data-jslint-predefines") || "").split(/[ ,]+/); 103 | async(lintFileAsync(scriptElement.src, jsLintPredefines.concat(predefines))); 104 | }); 105 | }); 106 | }); 107 | 108 | document.addEventListener("DOMContentLoaded", function (event) { 109 | WinJS.Application.queueEvent({ type: "run" }); 110 | }); 111 | 112 | WinJS.Application.addEventListener("run", function (event) { 113 | event.setPromise(loadSpecsAsync().then(function specsLoaded() { 114 | var env = jasmine.getEnv(), 115 | htmlReporter, oldSpecFilter; 116 | 117 | htmlReporter = new jasmine.HtmlReporter(); 118 | htmlReporter.logRunningSpecs = true; 119 | env.addReporter(htmlReporter); 120 | 121 | env.specFilter = function (spec) { 122 | return htmlReporter.specFilter(spec); 123 | }; 124 | 125 | if (spec.config.junitReport) { 126 | env.addReporter(new jasmine.JUnitXmlReporter("testResults")); 127 | } 128 | 129 | if (spec.config && spec.config.suitesToRun && spec.config.suitesToRun.length > 0) { 130 | if (spec.config.suitesToRun.length === 1) { 131 | if (spec.config.suitesToRun[0] === "") { 132 | delete spec.config.suitesToRun; 133 | } 134 | } 135 | if (spec.config.suitesToRun && spec.config.suitesToRun.length > 0) { 136 | oldSpecFilter = htmlReporter.specFilter; 137 | htmlReporter.specFilter = function(_spec) { 138 | var specSuiteFilter; 139 | specSuiteFilter = function(_spec) { 140 | return spec.config.suitesToRun.some(isPartOfSuite.bind(this, _spec.suite)); 141 | }; 142 | return oldSpecFilter.call(this, _spec) && specSuiteFilter(_spec); 143 | }; 144 | jasmine.getEnv().specFilter = function(_spec) { 145 | return htmlReporter.specFilter(_spec); 146 | }; 147 | } 148 | } 149 | if (spec.config.quitAfterTests) { 150 | WinJS.Application.addEventListener('jasmine.junitreporter.complete', function() { 151 | return window.close(); 152 | }); 153 | } 154 | jasmine.getEnv().execute(); 155 | })); 156 | }); 157 | 158 | WinJS.Application.start(); 159 | }()); -------------------------------------------------------------------------------- /SQLite3JS/js/tests/string.monkeypatch.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | String.prototype.toUri = function () { 5 | return new Windows.Foundation.Uri(this); 6 | }; 7 | 8 | String.prototype.toAppPackageUri = function () { 9 | return this.toAppPackage().toUri(); 10 | }; 11 | 12 | String.prototype.toAppPackage = function () { 13 | return "ms-appx:///" + this; 14 | }; 15 | 16 | }()); -------------------------------------------------------------------------------- /SQLite3JS/lib/jasmine-1.3.1/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2011 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /SQLite3JS/lib/jasmine-1.3.1/jasmine-html.js: -------------------------------------------------------------------------------- 1 | jasmine.HtmlReporterHelpers = {}; 2 | 3 | jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) { 4 | var el = document.createElement(type); 5 | 6 | for (var i = 2; i < arguments.length; i++) { 7 | var child = arguments[i]; 8 | 9 | if (typeof child === 'string') { 10 | el.appendChild(document.createTextNode(child)); 11 | } else { 12 | if (child) { 13 | el.appendChild(child); 14 | } 15 | } 16 | } 17 | 18 | for (var attr in attrs) { 19 | if (attr == "className") { 20 | el[attr] = attrs[attr]; 21 | } else { 22 | el.setAttribute(attr, attrs[attr]); 23 | } 24 | } 25 | 26 | return el; 27 | }; 28 | 29 | jasmine.HtmlReporterHelpers.getSpecStatus = function(child) { 30 | var results = child.results(); 31 | var status = results.passed() ? 'passed' : 'failed'; 32 | if (results.skipped) { 33 | status = 'skipped'; 34 | } 35 | 36 | return status; 37 | }; 38 | 39 | jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) { 40 | var parentDiv = this.dom.summary; 41 | var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite'; 42 | var parent = child[parentSuite]; 43 | 44 | if (parent) { 45 | if (typeof this.views.suites[parent.id] == 'undefined') { 46 | this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views); 47 | } 48 | parentDiv = this.views.suites[parent.id].element; 49 | } 50 | 51 | parentDiv.appendChild(childElement); 52 | }; 53 | 54 | 55 | jasmine.HtmlReporterHelpers.addHelpers = function(ctor) { 56 | for(var fn in jasmine.HtmlReporterHelpers) { 57 | ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn]; 58 | } 59 | }; 60 | 61 | jasmine.HtmlReporter = function(_doc) { 62 | var self = this; 63 | var doc = _doc || window.document; 64 | 65 | var reporterView; 66 | 67 | var dom = {}; 68 | 69 | // Jasmine Reporter Public Interface 70 | self.logRunningSpecs = false; 71 | 72 | self.reportRunnerStarting = function(runner) { 73 | var specs = runner.specs() || []; 74 | 75 | if (specs.length == 0) { 76 | return; 77 | } 78 | 79 | createReporterDom(runner.env.versionString()); 80 | doc.body.appendChild(dom.reporter); 81 | setExceptionHandling(); 82 | 83 | reporterView = new jasmine.HtmlReporter.ReporterView(dom); 84 | reporterView.addSpecs(specs, self.specFilter); 85 | }; 86 | 87 | self.reportRunnerResults = function(runner) { 88 | reporterView && reporterView.complete(); 89 | }; 90 | 91 | self.reportSuiteResults = function(suite) { 92 | reporterView.suiteComplete(suite); 93 | }; 94 | 95 | self.reportSpecStarting = function(spec) { 96 | if (self.logRunningSpecs) { 97 | self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 98 | } 99 | }; 100 | 101 | self.reportSpecResults = function(spec) { 102 | reporterView.specComplete(spec); 103 | }; 104 | 105 | self.log = function() { 106 | var console = jasmine.getGlobal().console; 107 | if (console && console.log) { 108 | if (console.log.apply) { 109 | console.log.apply(console, arguments); 110 | } else { 111 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 112 | } 113 | } 114 | }; 115 | 116 | self.specFilter = function(spec) { 117 | if (!focusedSpecName()) { 118 | return true; 119 | } 120 | 121 | return spec.getFullName().indexOf(focusedSpecName()) === 0; 122 | }; 123 | 124 | return self; 125 | 126 | function focusedSpecName() { 127 | var specName; 128 | 129 | (function memoizeFocusedSpec() { 130 | if (specName) { 131 | return; 132 | } 133 | 134 | var paramMap = []; 135 | var params = jasmine.HtmlReporter.parameters(doc); 136 | 137 | for (var i = 0; i < params.length; i++) { 138 | var p = params[i].split('='); 139 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 140 | } 141 | 142 | specName = paramMap.spec; 143 | })(); 144 | 145 | return specName; 146 | } 147 | 148 | function createReporterDom(version) { 149 | dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' }, 150 | dom.banner = self.createDom('div', { className: 'banner' }, 151 | self.createDom('span', { className: 'title' }, "Jasmine "), 152 | self.createDom('span', { className: 'version' }, version)), 153 | 154 | dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}), 155 | dom.alert = self.createDom('div', {className: 'alert'}, 156 | self.createDom('span', { className: 'exceptions' }, 157 | self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'), 158 | self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))), 159 | dom.results = self.createDom('div', {className: 'results'}, 160 | dom.summary = self.createDom('div', { className: 'summary' }), 161 | dom.details = self.createDom('div', { id: 'details' })) 162 | ); 163 | } 164 | 165 | function noTryCatch() { 166 | return window.location.search.match(/catch=false/); 167 | } 168 | 169 | function searchWithCatch() { 170 | var params = jasmine.HtmlReporter.parameters(window.document); 171 | var removed = false; 172 | var i = 0; 173 | 174 | while (!removed && i < params.length) { 175 | if (params[i].match(/catch=/)) { 176 | params.splice(i, 1); 177 | removed = true; 178 | } 179 | i++; 180 | } 181 | if (jasmine.CATCH_EXCEPTIONS) { 182 | params.push("catch=false"); 183 | } 184 | 185 | return params.join("&"); 186 | } 187 | 188 | function setExceptionHandling() { 189 | var chxCatch = document.getElementById('no_try_catch'); 190 | 191 | if (noTryCatch()) { 192 | chxCatch.setAttribute('checked', true); 193 | jasmine.CATCH_EXCEPTIONS = false; 194 | } 195 | chxCatch.onclick = function() { 196 | window.location.search = searchWithCatch(); 197 | }; 198 | } 199 | }; 200 | jasmine.HtmlReporter.parameters = function(doc) { 201 | var paramStr = doc.location.search.substring(1); 202 | var params = []; 203 | 204 | if (paramStr.length > 0) { 205 | params = paramStr.split('&'); 206 | } 207 | return params; 208 | } 209 | jasmine.HtmlReporter.sectionLink = function(sectionName) { 210 | var link = '?'; 211 | var params = []; 212 | 213 | if (sectionName) { 214 | params.push('spec=' + encodeURIComponent(sectionName)); 215 | } 216 | if (!jasmine.CATCH_EXCEPTIONS) { 217 | params.push("catch=false"); 218 | } 219 | if (params.length > 0) { 220 | link += params.join("&"); 221 | } 222 | 223 | return link; 224 | }; 225 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter); 226 | jasmine.HtmlReporter.ReporterView = function(dom) { 227 | this.startedAt = new Date(); 228 | this.runningSpecCount = 0; 229 | this.completeSpecCount = 0; 230 | this.passedCount = 0; 231 | this.failedCount = 0; 232 | this.skippedCount = 0; 233 | 234 | this.createResultsMenu = function() { 235 | this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'}, 236 | this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'), 237 | ' | ', 238 | this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing')); 239 | 240 | this.summaryMenuItem.onclick = function() { 241 | dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, ''); 242 | }; 243 | 244 | this.detailsMenuItem.onclick = function() { 245 | showDetails(); 246 | }; 247 | }; 248 | 249 | this.addSpecs = function(specs, specFilter) { 250 | this.totalSpecCount = specs.length; 251 | 252 | this.views = { 253 | specs: {}, 254 | suites: {} 255 | }; 256 | 257 | for (var i = 0; i < specs.length; i++) { 258 | var spec = specs[i]; 259 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views); 260 | if (specFilter(spec)) { 261 | this.runningSpecCount++; 262 | } 263 | } 264 | }; 265 | 266 | this.specComplete = function(spec) { 267 | this.completeSpecCount++; 268 | 269 | if (isUndefined(this.views.specs[spec.id])) { 270 | this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom); 271 | } 272 | 273 | var specView = this.views.specs[spec.id]; 274 | 275 | switch (specView.status()) { 276 | case 'passed': 277 | this.passedCount++; 278 | break; 279 | 280 | case 'failed': 281 | this.failedCount++; 282 | break; 283 | 284 | case 'skipped': 285 | this.skippedCount++; 286 | break; 287 | } 288 | 289 | specView.refresh(); 290 | this.refresh(); 291 | }; 292 | 293 | this.suiteComplete = function(suite) { 294 | var suiteView = this.views.suites[suite.id]; 295 | if (isUndefined(suiteView)) { 296 | return; 297 | } 298 | suiteView.refresh(); 299 | }; 300 | 301 | this.refresh = function() { 302 | 303 | if (isUndefined(this.resultsMenu)) { 304 | this.createResultsMenu(); 305 | } 306 | 307 | // currently running UI 308 | if (isUndefined(this.runningAlert)) { 309 | this.runningAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "runningAlert bar" }); 310 | dom.alert.appendChild(this.runningAlert); 311 | } 312 | this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount); 313 | 314 | // skipped specs UI 315 | if (isUndefined(this.skippedAlert)) { 316 | this.skippedAlert = this.createDom('a', { href: jasmine.HtmlReporter.sectionLink(), className: "skippedAlert bar" }); 317 | } 318 | 319 | this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 320 | 321 | if (this.skippedCount === 1 && isDefined(dom.alert)) { 322 | dom.alert.appendChild(this.skippedAlert); 323 | } 324 | 325 | // passing specs UI 326 | if (isUndefined(this.passedAlert)) { 327 | this.passedAlert = this.createDom('span', { href: jasmine.HtmlReporter.sectionLink(), className: "passingAlert bar" }); 328 | } 329 | this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount); 330 | 331 | // failing specs UI 332 | if (isUndefined(this.failedAlert)) { 333 | this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"}); 334 | } 335 | this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount); 336 | 337 | if (this.failedCount === 1 && isDefined(dom.alert)) { 338 | dom.alert.appendChild(this.failedAlert); 339 | dom.alert.appendChild(this.resultsMenu); 340 | } 341 | 342 | // summary info 343 | this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount); 344 | this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing"; 345 | }; 346 | 347 | this.complete = function() { 348 | dom.alert.removeChild(this.runningAlert); 349 | 350 | this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all"; 351 | 352 | if (this.failedCount === 0) { 353 | dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount))); 354 | } else { 355 | showDetails(); 356 | } 357 | 358 | dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s")); 359 | }; 360 | 361 | return this; 362 | 363 | function showDetails() { 364 | if (dom.reporter.className.search(/showDetails/) === -1) { 365 | dom.reporter.className += " showDetails"; 366 | } 367 | } 368 | 369 | function isUndefined(obj) { 370 | return typeof obj === 'undefined'; 371 | } 372 | 373 | function isDefined(obj) { 374 | return !isUndefined(obj); 375 | } 376 | 377 | function specPluralizedFor(count) { 378 | var str = count + " spec"; 379 | if (count > 1) { 380 | str += "s" 381 | } 382 | return str; 383 | } 384 | 385 | }; 386 | 387 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView); 388 | 389 | 390 | jasmine.HtmlReporter.SpecView = function(spec, dom, views) { 391 | this.spec = spec; 392 | this.dom = dom; 393 | this.views = views; 394 | 395 | this.symbol = this.createDom('li', { className: 'pending' }); 396 | this.dom.symbolSummary.appendChild(this.symbol); 397 | 398 | this.summary = this.createDom('div', { className: 'specSummary' }, 399 | this.createDom('a', { 400 | className: 'description', 401 | href: jasmine.HtmlReporter.sectionLink(this.spec.getFullName()), 402 | title: this.spec.getFullName() 403 | }, this.spec.description) 404 | ); 405 | 406 | this.detail = this.createDom('div', { className: 'specDetail' }, 407 | this.createDom('a', { 408 | className: 'description', 409 | href: '?spec=' + encodeURIComponent(this.spec.getFullName()), 410 | title: this.spec.getFullName() 411 | }, this.spec.getFullName()) 412 | ); 413 | }; 414 | 415 | jasmine.HtmlReporter.SpecView.prototype.status = function() { 416 | return this.getSpecStatus(this.spec); 417 | }; 418 | 419 | jasmine.HtmlReporter.SpecView.prototype.refresh = function() { 420 | this.symbol.className = this.status(); 421 | 422 | switch (this.status()) { 423 | case 'skipped': 424 | break; 425 | 426 | case 'passed': 427 | this.appendSummaryToSuiteDiv(); 428 | break; 429 | 430 | case 'failed': 431 | this.appendSummaryToSuiteDiv(); 432 | this.appendFailureDetail(); 433 | break; 434 | } 435 | }; 436 | 437 | jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() { 438 | this.summary.className += ' ' + this.status(); 439 | this.appendToSummary(this.spec, this.summary); 440 | }; 441 | 442 | jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() { 443 | this.detail.className += ' ' + this.status(); 444 | 445 | var resultItems = this.spec.results().getItems(); 446 | var messagesDiv = this.createDom('div', { className: 'messages' }); 447 | 448 | for (var i = 0; i < resultItems.length; i++) { 449 | var result = resultItems[i]; 450 | 451 | if (result.type == 'log') { 452 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 453 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 454 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 455 | 456 | if (result.trace.stack) { 457 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 458 | } 459 | } 460 | } 461 | 462 | if (messagesDiv.childNodes.length > 0) { 463 | this.detail.appendChild(messagesDiv); 464 | this.dom.details.appendChild(this.detail); 465 | } 466 | }; 467 | 468 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) { 469 | this.suite = suite; 470 | this.dom = dom; 471 | this.views = views; 472 | 473 | this.element = this.createDom('div', { className: 'suite' }, 474 | this.createDom('a', { className: 'description', href: jasmine.HtmlReporter.sectionLink(this.suite.getFullName()) }, this.suite.description) 475 | ); 476 | 477 | this.appendToSummary(this.suite, this.element); 478 | }; 479 | 480 | jasmine.HtmlReporter.SuiteView.prototype.status = function() { 481 | return this.getSpecStatus(this.suite); 482 | }; 483 | 484 | jasmine.HtmlReporter.SuiteView.prototype.refresh = function() { 485 | this.element.className += " " + this.status(); 486 | }; 487 | 488 | jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView); 489 | 490 | /* @deprecated Use jasmine.HtmlReporter instead 491 | */ 492 | jasmine.TrivialReporter = function(doc) { 493 | this.document = doc || document; 494 | this.suiteDivs = {}; 495 | this.logRunningSpecs = false; 496 | }; 497 | 498 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 499 | var el = document.createElement(type); 500 | 501 | for (var i = 2; i < arguments.length; i++) { 502 | var child = arguments[i]; 503 | 504 | if (typeof child === 'string') { 505 | el.appendChild(document.createTextNode(child)); 506 | } else { 507 | if (child) { el.appendChild(child); } 508 | } 509 | } 510 | 511 | for (var attr in attrs) { 512 | if (attr == "className") { 513 | el[attr] = attrs[attr]; 514 | } else { 515 | el.setAttribute(attr, attrs[attr]); 516 | } 517 | } 518 | 519 | return el; 520 | }; 521 | 522 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 523 | var showPassed, showSkipped; 524 | 525 | this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' }, 526 | this.createDom('div', { className: 'banner' }, 527 | this.createDom('div', { className: 'logo' }, 528 | this.createDom('span', { className: 'title' }, "Jasmine"), 529 | this.createDom('span', { className: 'version' }, runner.env.versionString())), 530 | this.createDom('div', { className: 'options' }, 531 | "Show ", 532 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 533 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 534 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 535 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 536 | ) 537 | ), 538 | 539 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 540 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 541 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 542 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 543 | ); 544 | 545 | this.document.body.appendChild(this.outerDiv); 546 | 547 | var suites = runner.suites(); 548 | for (var i = 0; i < suites.length; i++) { 549 | var suite = suites[i]; 550 | var suiteDiv = this.createDom('div', { className: 'suite' }, 551 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 552 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 553 | this.suiteDivs[suite.id] = suiteDiv; 554 | var parentDiv = this.outerDiv; 555 | if (suite.parentSuite) { 556 | parentDiv = this.suiteDivs[suite.parentSuite.id]; 557 | } 558 | parentDiv.appendChild(suiteDiv); 559 | } 560 | 561 | this.startedAt = new Date(); 562 | 563 | var self = this; 564 | showPassed.onclick = function(evt) { 565 | if (showPassed.checked) { 566 | self.outerDiv.className += ' show-passed'; 567 | } else { 568 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 569 | } 570 | }; 571 | 572 | showSkipped.onclick = function(evt) { 573 | if (showSkipped.checked) { 574 | self.outerDiv.className += ' show-skipped'; 575 | } else { 576 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 577 | } 578 | }; 579 | }; 580 | 581 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 582 | var results = runner.results(); 583 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 584 | this.runnerDiv.setAttribute("class", className); 585 | //do it twice for IE 586 | this.runnerDiv.setAttribute("className", className); 587 | var specs = runner.specs(); 588 | var specCount = 0; 589 | for (var i = 0; i < specs.length; i++) { 590 | if (this.specFilter(specs[i])) { 591 | specCount++; 592 | } 593 | } 594 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 595 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 596 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 597 | 598 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 599 | }; 600 | 601 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 602 | var results = suite.results(); 603 | var status = results.passed() ? 'passed' : 'failed'; 604 | if (results.totalCount === 0) { // todo: change this to check results.skipped 605 | status = 'skipped'; 606 | } 607 | this.suiteDivs[suite.id].className += " " + status; 608 | }; 609 | 610 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 611 | if (this.logRunningSpecs) { 612 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 613 | } 614 | }; 615 | 616 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 617 | var results = spec.results(); 618 | var status = results.passed() ? 'passed' : 'failed'; 619 | if (results.skipped) { 620 | status = 'skipped'; 621 | } 622 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 623 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 624 | this.createDom('a', { 625 | className: 'description', 626 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 627 | title: spec.getFullName() 628 | }, spec.description)); 629 | 630 | 631 | var resultItems = results.getItems(); 632 | var messagesDiv = this.createDom('div', { className: 'messages' }); 633 | for (var i = 0; i < resultItems.length; i++) { 634 | var result = resultItems[i]; 635 | 636 | if (result.type == 'log') { 637 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 638 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 639 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 640 | 641 | if (result.trace.stack) { 642 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 643 | } 644 | } 645 | } 646 | 647 | if (messagesDiv.childNodes.length > 0) { 648 | specDiv.appendChild(messagesDiv); 649 | } 650 | 651 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 652 | }; 653 | 654 | jasmine.TrivialReporter.prototype.log = function() { 655 | var console = jasmine.getGlobal().console; 656 | if (console && console.log) { 657 | if (console.log.apply) { 658 | console.log.apply(console, arguments); 659 | } else { 660 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 661 | } 662 | } 663 | }; 664 | 665 | jasmine.TrivialReporter.prototype.getLocation = function() { 666 | return this.document.location; 667 | }; 668 | 669 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 670 | var paramMap = {}; 671 | var params = this.getLocation().search.substring(1).split('&'); 672 | for (var i = 0; i < params.length; i++) { 673 | var p = params[i].split('='); 674 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 675 | } 676 | 677 | if (!paramMap.spec) { 678 | return true; 679 | } 680 | return spec.getFullName().indexOf(paramMap.spec) === 0; 681 | }; 682 | -------------------------------------------------------------------------------- /SQLite3JS/lib/jasmine-1.3.1/jasmine.css: -------------------------------------------------------------------------------- 1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; } 2 | 3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | #HTMLReporter a { text-decoration: none; } 5 | #HTMLReporter a:hover { text-decoration: underline; } 6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; } 7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; } 8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; } 9 | #HTMLReporter .version { color: #aaaaaa; } 10 | #HTMLReporter .banner { margin-top: 14px; } 11 | #HTMLReporter .duration { color: #aaaaaa; float: right; } 12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; } 13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; } 14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; } 15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; } 16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; } 17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; } 18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; } 19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; } 20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; } 21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; } 22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 24 | #HTMLReporter .runningAlert { background-color: #666666; } 25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; } 26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; } 27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; } 28 | #HTMLReporter .passingAlert { background-color: #a6b779; } 29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; } 30 | #HTMLReporter .failingAlert { background-color: #cf867e; } 31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; } 32 | #HTMLReporter .results { margin-top: 14px; } 33 | #HTMLReporter #details { display: none; } 34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; } 35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 38 | #HTMLReporter.showDetails .summary { display: none; } 39 | #HTMLReporter.showDetails #details { display: block; } 40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 41 | #HTMLReporter .summary { margin-top: 14px; } 42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; } 43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; } 44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; } 45 | #HTMLReporter .description + .suite { margin-top: 0; } 46 | #HTMLReporter .suite { margin-top: 14px; } 47 | #HTMLReporter .suite a { color: #333333; } 48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; } 49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; } 50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; } 51 | #HTMLReporter .resultMessage span.result { display: block; } 52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 53 | 54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ } 55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; } 56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; } 57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; } 58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; } 59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; } 60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; } 61 | #TrivialReporter .runner.running { background-color: yellow; } 62 | #TrivialReporter .options { text-align: right; font-size: .8em; } 63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } 64 | #TrivialReporter .suite .suite { margin: 5px; } 65 | #TrivialReporter .suite.passed { background-color: #dfd; } 66 | #TrivialReporter .suite.failed { background-color: #fdd; } 67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; } 68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } 69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; } 70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; } 71 | #TrivialReporter .spec.skipped { background-color: #bbb; } 72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } 73 | #TrivialReporter .passed { background-color: #cfc; display: none; } 74 | #TrivialReporter .failed { background-color: #fbb; } 75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; } 76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; } 77 | #TrivialReporter .resultMessage .mismatch { color: black; } 78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } 79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; } 80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; } 81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; } 82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } 83 | -------------------------------------------------------------------------------- /SQLite3JS/lib/jasmine-reporters/jasmine.junit_reporter.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | if (!jasmine) { 4 | throw new Error("jasmine library does not exist in global namespace!"); 5 | } 6 | 7 | function elapsed(startTime, endTime) { 8 | return (endTime - startTime) / 1000; 9 | } 10 | 11 | function getISODateString(d) { 12 | if (!d) { 13 | return ""; 14 | } 15 | 16 | function pad(n) { return n < 10 ? '0' + n : n; } 17 | 18 | return d.getFullYear() + '-' + 19 | pad(d.getMonth() + 1) + '-' + 20 | pad(d.getDate()) + 'T' + 21 | pad(d.getHours()) + ':' + 22 | pad(d.getMinutes()) + ':' + 23 | pad(d.getSeconds()); 24 | } 25 | 26 | function trim(str) { 27 | return str.replace(/^\s+/, "").replace(/\s+$/, ""); 28 | } 29 | 30 | function escapeInvalidXmlChars(str) { 31 | return str.replace(/\&/g, "&") 32 | .replace(//g, ">") 34 | .replace(/\"/g, """) 35 | .replace(/\'/g, "'"); 36 | } 37 | 38 | if (!jasmine.Suite.prototype.getDuration) { 39 | jasmine.Suite.prototype.getDuration = function () { 40 | var suiteDuration = 0; 41 | this.specs().forEach(function (spec) { 42 | if (!isNaN(spec.duration)) { 43 | suiteDuration += spec.duration; 44 | } 45 | }); 46 | this.suites().forEach(function (suite) { 47 | var innerDuration = suite.getDuration(); 48 | if (!isNaN(innerDuration)) { 49 | suiteDuration += innerDuration; 50 | } 51 | }); 52 | return suiteDuration; 53 | }; 54 | } 55 | /** 56 | * Generates JUnit XML for the given spec run. 57 | * Allows the test results to be used in java based CI 58 | * systems like CruiseControl and Hudson. 59 | * 60 | * @param {string} savePath where to save the files 61 | * @param {boolean} consolidate whether to save nested describes within the 62 | * same file as their parent; default: true 63 | * @param {boolean} useDotNotation whether to separate suite names with 64 | * dots rather than spaces (ie "Class.init" not 65 | * "Class init"); default: true 66 | */ 67 | var JUnitXmlReporter = function (savePath, consolidate, useDotNotation) { 68 | this.savePath = savePath || ''; 69 | this.consolidate = consolidate === jasmine["undefined"] ? true : consolidate; 70 | this.useDotNotation = useDotNotation === jasmine["undefined"] ? true : useDotNotation; 71 | }; 72 | JUnitXmlReporter.finished_at = null; // will be updated after all files have been written 73 | 74 | JUnitXmlReporter.prototype = { 75 | reportSpecStarting: function (spec) { 76 | spec.startTime = new Date(); 77 | 78 | if (!spec.suite.startTime) { 79 | spec.suite.startTime = spec.startTime; 80 | } 81 | }, 82 | 83 | reportSpecResults: function (spec) { 84 | var results = spec.results(), failure = "", failures = 0; 85 | spec.didFail = !results.passed(); 86 | spec.duration = elapsed(spec.startTime, new Date()); 87 | spec.output = ''; 89 | 90 | results.getItems().forEach(function (result) { 91 | if (result.type === 'expect' && result.passed && !result.passed()) { 92 | failures += 1; 93 | failure += (failures + ": " + escapeInvalidXmlChars(result.message) + " "); 94 | } 95 | }); 96 | if (failure) { 97 | spec.output += "" + trim(failure) + ""; 98 | } 99 | spec.output += ""; 100 | }, 101 | 102 | reportSuiteResults: function (suite) { 103 | var results = suite.results(), 104 | specs = suite.specs(), 105 | specOutput = "", 106 | // for JUnit results, let's only include directly failed tests (not nested suites') 107 | failedCount = 0; 108 | 109 | suite.status = results.passed() ? 'Passed.' : 'Failed.'; 110 | if (results.totalCount === 0 || results.skipped) { // todo: change this to check results.skipped 111 | suite.status = 'Skipped.'; 112 | } 113 | 114 | specs.forEach(function (spec) { 115 | failedCount += spec.didFail ? 1 : 0; 116 | specOutput += "\n " + spec.output; 117 | }); 118 | suite.output = '\n'; 121 | suite.output += specOutput; 122 | suite.output += "\n"; 123 | }, 124 | 125 | reportRunnerResults: function (runner) { 126 | var suites = runner.suites(), 127 | winJSPromises = [], 128 | that = this; 129 | suites.forEach(function(suite) { 130 | var fileName = 'TEST-' + that.getFullName(suite, true) + '.xml', 131 | output = ''; 132 | // if we are consolidating, only write out top-level suites 133 | if (that.consolidate && suite.parentSuite) { 134 | output += ""; // shut up jslint 135 | } else if (that.consolidate) { 136 | output += "\n"; 137 | output += that.getNestedOutput(suite); 138 | output += "\n"; 139 | winJSPromises.push(that.writeFile(that.savePath + fileName, output)); 140 | } else { 141 | output += suite.output; 142 | winJSPromises.push(that.writeFile(that.savePath + fileName, output)); 143 | } 144 | }); 145 | if (winJSPromises.length > 0) { 146 | WinJS.Promise.join(winJSPromises).then(function () { 147 | WinJS.Application.queueEvent({ type: 'jasmine.junitreporter.complete' }); 148 | }); 149 | } 150 | // When all done, make it known on JUnitXmlReporter 151 | JUnitXmlReporter.finished_at = (new Date()).getTime(); 152 | }, 153 | 154 | getNestedOutput: function (suite) { 155 | var output = suite.output, 156 | that = this; 157 | suite.suites().forEach(function(_suite) { 158 | output += that.getNestedOutput(_suite); 159 | }); 160 | return output; 161 | }, 162 | 163 | writeFile: function (filename, text) { 164 | // WinJS 165 | var simpleFilename = filename.substr(this.savePath.length), 166 | fileWriteDone = false; 167 | return Windows.Storage.ApplicationData.current.localFolder.createFolderAsync(this.savePath, Windows.Storage.CreationCollisionOption.openIfExists).then(function (folder) { 168 | return folder.createFileAsync(simpleFilename, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (storageFile) { 169 | return Windows.Storage.FileIO.writeTextAsync(storageFile, text); 170 | }); 171 | }); 172 | }, 173 | 174 | getFullName: function (suite, isFilename) { 175 | var fullName, parentSuite; 176 | if (this.useDotNotation) { 177 | fullName = suite.description; 178 | for (parentSuite = suite.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { 179 | fullName = parentSuite.description + '.' + fullName; 180 | } 181 | } 182 | else { 183 | fullName = suite.getFullName(); 184 | } 185 | 186 | // Either remove or escape invalid XML characters 187 | if (isFilename) { 188 | return fullName.replace(/[^\w]/g, ""); 189 | } 190 | return escapeInvalidXmlChars(fullName); 191 | }, 192 | 193 | log: function (str) { 194 | var console = jasmine.getGlobal().console; 195 | 196 | if (console && console.log) { 197 | console.log(str); 198 | } 199 | } 200 | }; 201 | 202 | // export public 203 | jasmine.JUnitXmlReporter = JUnitXmlReporter; 204 | }()); 205 | -------------------------------------------------------------------------------- /SQLite3JS/package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | SQLite3JS 6 | SQLite3JS 7 | doo GmbH 8 | images\storelogo.png 9 | 10 | 11 | 6.2 12 | 6.2 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SQLite3JS/spec/SQLite3Spec.js: -------------------------------------------------------------------------------- 1 | /// 2 | (function () { 3 | "use strict"; 4 | 5 | spec.require("js/SQlite3.js"); 6 | 7 | describe('SQLite3JS', function () { 8 | var db = null; 9 | 10 | beforeEach(function () { 11 | spec.async( 12 | SQLite3JS.openAsync(':memory:').then(function (newDb) { 13 | db = newDb; 14 | return db.runAsync('CREATE TABLE Item (name TEXT, price REAL, dateBought UNSIGNED BIG INT, id INT PRIMARY KEY)').then(function () { 15 | var promises = [ 16 | db.runAsync('INSERT INTO Item (name, price, id) VALUES (?, ?, ?)', ['Apple', 1.2, 1]), 17 | db.runAsync('INSERT INTO Item (name, price, id) VALUES (?, ?, ?)', ['Orange', 2.5, 2]), 18 | db.runAsync('INSERT INTO Item (name, price, id) VALUES (?, ?, ?)', ['Banana', 3, 3]) 19 | ]; 20 | return WinJS.Promise.join(promises); 21 | }); 22 | }) 23 | ); 24 | }); 25 | 26 | afterEach(function () { 27 | spec.async( 28 | db.runAsync('DROP TABLE Item').then(function () { 29 | db.close(); 30 | db = null; 31 | }) 32 | ); 33 | }); 34 | 35 | describe('runAsync()', function () { 36 | it('should allow binding null arguments', function () { 37 | var name = 'Mango'; 38 | 39 | spec.async( 40 | db.runAsync('INSERT INTO Item (name, price, id) VALUES (?, ?, ?)', [name, null, null]) 41 | .then(function () { 42 | return db.oneAsync('SELECT * FROM Item WHERE name = ?', [name]); 43 | }).then(function (row) { 44 | expect(row.name).toEqual(name); 45 | expect(row.price).toEqual(null); 46 | expect(row.id).toEqual(null); 47 | }) 48 | ); 49 | }); 50 | 51 | it('should support binding javascript date arguments', function () { 52 | var name = 'Melon', 53 | dateBought = new Date(); 54 | 55 | spec.async( 56 | db.runAsync('INSERT INTO Item (name, dateBought) VALUES (?, ?)', [name, dateBought]) 57 | .then(function () { 58 | return db.oneAsync('SELECT * FROM Item WHERE dateBought=?', [dateBought]); 59 | }).then(function (row) { 60 | expect(row.name).toEqual(name); 61 | expect(new Date(row.dateBought)).toEqual(dateBought); 62 | }) 63 | ); 64 | }); 65 | 66 | it('should allow binding arguments by name', function () { 67 | spec.async( 68 | db.runAsync( 69 | 'INSERT INTO Item (name, price, id) VALUES (:name, :price, :id)', 70 | { name: 'Papaya', price: 5.2, id: 4 }) 71 | .then(function () { 72 | return db.oneAsync( 73 | 'SELECT COUNT(*) AS cnt FROM Item WHERE price > :limit', 74 | { limit: 5 }); 75 | }).then(function (row) { 76 | expect(row.cnt).toEqual(1); 77 | }) 78 | ); 79 | }); 80 | 81 | it('should return the number of affected rows', function () { 82 | spec.async( 83 | db.runAsync('DELETE FROM Item') 84 | .then(function (affectedRows) { 85 | expect(affectedRows).toEqual(3); 86 | }) 87 | ); 88 | }); 89 | }); 90 | 91 | describe('oneAsync()', function () { 92 | it('should return the correct count', function () { 93 | spec.async( 94 | db.oneAsync('SELECT COUNT(*) AS count FROM Item').then(function (row) { 95 | expect(row.count).toEqual(3); 96 | }) 97 | ); 98 | }); 99 | 100 | it('should return an item by id', function () { 101 | spec.async( 102 | db.oneAsync('SELECT * FROM Item WHERE id = ?', [2]).then(function (row) { 103 | expect(row.name).toEqual('Orange'); 104 | expect(row.price).toEqual(2.5); 105 | expect(row.id).toEqual(2); 106 | }) 107 | ); 108 | }); 109 | 110 | it('should return null for empty queries', function () { 111 | spec.async( 112 | db.oneAsync('SELECT * FROM Item WHERE name = ?', ['BEEF']).then(function (row) { 113 | expect(row).toBeNull(); 114 | }) 115 | ); 116 | }); 117 | 118 | it('should support special characters in strings', function () { 119 | var rowToInsert = { 120 | name: "Foo\nBar'n" 121 | }; 122 | spec.async( 123 | db.runAsync('INSERT INTO Item(name) VALUES(:name)', rowToInsert) 124 | .then(function () { 125 | var id = db.lastInsertRowId; 126 | return db.oneAsync('SELECT * FROM Item WHERE rowId=?', [id]); 127 | }).then(function (result) { 128 | expect(result.name).toEqual("Foo\nBar'n"); 129 | }) 130 | ); 131 | }); 132 | }); 133 | 134 | describe('allAsync()', function () { 135 | it('should return items with names ending on "e"', function () { 136 | spec.async( 137 | db.allAsync( 138 | 'SELECT * FROM Item WHERE name LIKE :pattern ORDER BY id ASC', 139 | { pattern: '%e' }) 140 | .then(function (rows) { 141 | expect(rows.length).toEqual(2); 142 | expect(rows[0].name).toEqual('Apple'); 143 | expect(rows[1].name).toEqual('Orange'); 144 | }) 145 | ); 146 | }); 147 | 148 | it('should return empty array for empty queries', function () { 149 | spec.async( 150 | db.allAsync('SELECT * FROM Item WHERE id < ?', [0]).then(function (rows) { 151 | expect(rows.length).toEqual(0); 152 | }) 153 | ); 154 | }); 155 | 156 | it('should allow cancellation', function () { 157 | var promise, thisSpec = this; 158 | 159 | promise = db.allAsync('SELECT * FROM Item ORDER BY id').then(function () { 160 | thisSpec.fail('Promise did not fail as expected.'); 161 | }, function (error) { 162 | expect(error.message).toEqual('Canceled'); 163 | }); 164 | 165 | promise.cancel(); 166 | 167 | spec.async(promise); 168 | }); 169 | }); 170 | 171 | describe('eachAsync()', function () { 172 | var ids; 173 | 174 | beforeEach(function () { 175 | ids = []; 176 | this.rememberId = function (row) { ids.push(row.id); }; 177 | }); 178 | 179 | it('should call a callback for each row', function () { 180 | spec.async( 181 | db.eachAsync('SELECT * FROM Item ORDER BY id', this.rememberId).then(function () { 182 | expect(ids).toEqual([1, 2, 3]); 183 | }) 184 | ); 185 | }); 186 | 187 | it('should allow binding arguments', function () { 188 | spec.async( 189 | db.eachAsync('SELECT * FROM Item WHERE price > ? ORDER BY id', [2], this.rememberId) 190 | .then(function () { 191 | expect(ids).toEqual([2, 3]); 192 | }) 193 | ); 194 | }); 195 | 196 | it('should allow binding arguments by name', function () { 197 | spec.async( 198 | db.eachAsync( 199 | 'SELECT * FROM Item WHERE price < :max ORDER BY id', 200 | { max: 3 }, 201 | this.rememberId).then(function () { 202 | expect(ids).toEqual([1, 2]); 203 | }) 204 | ); 205 | }); 206 | 207 | xit('should allow cancellation in the callback', function () { 208 | var promise, thisSpec = this; 209 | 210 | function cancel(row) { 211 | promise.cancel(); 212 | } 213 | 214 | promise = db.eachAsync('SELECT * FROM Item ORDER BY id', cancel).then(function () { 215 | thisSpec.fail('Promise did not fail as expected.'); 216 | }, function (error) { 217 | expect(error.message).toEqual('Canceled'); 218 | }); 219 | 220 | spec.async(promise); 221 | }); 222 | }); 223 | 224 | describe('mapAsync()', function () { 225 | it('should map a function over all rows', function () { 226 | spec.async( 227 | db.mapAsync('SELECT * FROM Item ORDER BY id', function (row) { 228 | return row.price > 2 ? 'expensive' : 'cheap'; 229 | }).then(function (rating) { 230 | expect(rating.length).toEqual(3); 231 | expect(rating[0]).toEqual('cheap'); 232 | expect(rating[1]).toEqual('expensive'); 233 | expect(rating[2]).toEqual('expensive'); 234 | }) 235 | ); 236 | }); 237 | }); 238 | 239 | describe('lastInsertRowId', function () { 240 | it('should retrieve the id of the last inserted row', function () { 241 | spec.async( 242 | db.runAsync("INSERT INTO Item (name) VALUES (?)", ['Ananas']).then(function () { 243 | var id = db.lastInsertRowId; 244 | expect(id).toEqual(4); 245 | }) 246 | ); 247 | }); 248 | }); 249 | 250 | describe("Sorting", function () { 251 | beforeEach(function () { 252 | spec.async( 253 | db.runAsync("CREATE TABLE SortTest (name TEXT COLLATE WINLOCALE)").then(function () { 254 | return db.runAsync("INSERT INTO SortTest VALUES (?)", ["Foo20"]); 255 | }).then(function () { 256 | return db.runAsync("INSERT INTO SortTest VALUES (?)", ["Foo"]); 257 | }).then(function () { 258 | return db.runAsync("INSERT INTO SortTest VALUES (?)", ["Foo3"]); 259 | }) 260 | ); 261 | }); 262 | 263 | afterEach(function () { 264 | spec.async( 265 | db.runAsync("DROP TABLE SortTest") 266 | ); 267 | }); 268 | 269 | it("should order numbers according to value", function () { 270 | spec.async( 271 | db.allAsync("SELECT * FROM SortTest ORDER BY name").then(function (rows) { 272 | expect(rows[0].name).toEqual("Foo"); 273 | expect(rows[1].name).toEqual("Foo3"); 274 | expect(rows[2].name).toEqual("Foo20"); 275 | }) 276 | ); 277 | }); 278 | 279 | 280 | }); 281 | describe("Locale-specific Collation", function () { 282 | beforeEach(function () { 283 | spec.async( 284 | db.runAsync("CREATE TABLE CollateTest (name TEXT COLLATE WINLOCALE)").then(function () { 285 | return db.runAsync("INSERT INTO CollateTest VALUES (?)", ["Lj"]); 286 | }).then(function () { 287 | return db.runAsync("INSERT INTO CollateTest VALUES (?)", ["Lz"]); 288 | }).then(function () { 289 | return db.runAsync("INSERT INTO CollateTest VALUES (?)", ["La"]); 290 | }) 291 | ); 292 | }); 293 | 294 | afterEach(function () { 295 | spec.async( 296 | db.runAsync("DROP TABLE CollateTest") 297 | ); 298 | }); 299 | 300 | it('should support english collation', function () { 301 | db.collationLanguage = "en-US"; 302 | spec.async( 303 | db.allAsync("SELECT * FROM CollateTest ORDER BY name").then(function (rows) { 304 | expect(rows[0].name).toEqual("La"); 305 | expect(rows[1].name).toEqual("Lj"); 306 | expect(rows[2].name).toEqual("Lz"); 307 | }) 308 | ); 309 | }); 310 | 311 | it('should support bosnian collation', function () { 312 | db.collationLanguage = "bs-Latn-BA"; 313 | spec.async( 314 | db.allAsync("SELECT * FROM CollateTest ORDER BY name").then(function (rows) { 315 | expect(rows[0].name).toEqual("La"); 316 | expect(rows[1].name).toEqual("Lz"); 317 | expect(rows[2].name).toEqual("Lj"); 318 | }) 319 | ); 320 | }); 321 | }); 322 | 323 | it("should support the REGEXP operator", function () { 324 | spec.async( 325 | db.allAsync("SELECT * FROM Item WHERE name REGEXP '.*a'").then(function (rows) { 326 | expect(rows.length).toEqual(2); 327 | }) 328 | ); 329 | }); 330 | 331 | describe("Win8 app translation", function () { 332 | it("should translate from database queries using default resource", function () { 333 | spec.async( 334 | db.oneAsync("SELECT APPTRANSLATE(?) AS translation", ["testString1"]).then(function (row) { 335 | expect(row.translation).toEqual("Hello World!"); 336 | }) 337 | ); 338 | }); 339 | it("should translate from database queries using specific resource", function () { 340 | spec.async( 341 | db.oneAsync("SELECT APPTRANSLATE(?,?) AS translation", ["secondary", "testString1"]).then(function (row) { 342 | expect(row.translation).toEqual("Goodbye World."); 343 | }) 344 | ); 345 | }); 346 | }); 347 | 348 | describe('Events', function () { 349 | beforeEach(function () { 350 | db.fireEvents = true; 351 | }); 352 | afterEach(function () { 353 | db.fireEvents = false; 354 | }); 355 | function expectEvent(eventName, rowId, callback) { 356 | var calledEventHandler = false; 357 | 358 | runs(function () { 359 | // make sure the event queue is drained of old events 360 | setImmediate(function () { 361 | db.addEventListener(eventName, function listener(event) { 362 | expect(event.tableName).toEqual('Item'); 363 | expect(event.type).toEqual(eventName); 364 | expect(event.rowId).toEqual(rowId); 365 | calledEventHandler = true; 366 | }); 367 | 368 | callback(); 369 | }); 370 | }); 371 | 372 | waitsFor(function () { return calledEventHandler === true; }); 373 | } 374 | 375 | it('should fire oninsert', function () { 376 | expectEvent('insert', 4, function () { 377 | db.runAsync("INSERT INTO Item (name) VALUES (?)", ['Ananas']); 378 | }); 379 | }); 380 | 381 | it('should fire onupdate', function () { 382 | expectEvent('update', 2, function () { 383 | db.runAsync( 384 | "UPDATE Item SET price = :newPrice WHERE name = :name", 385 | { name: 'Orange', newPrice: 0.9 }); 386 | }); 387 | }); 388 | 389 | it('should fire ondelete', function () { 390 | expectEvent('delete', 1, function () { 391 | db.runAsync("DELETE FROM Item WHERE name = ?", ['Apple']); 392 | }); 393 | }); 394 | }); 395 | 396 | describe('Concurrency Handling', function () { 397 | it('should support two concurrent connections', function () { 398 | var tempFolder = Windows.Storage.ApplicationData.current.temporaryFolder, 399 | dbFilename = tempFolder.path + "\\concurrencyTest.sqlite", 400 | db1 = null, db2 = null; 401 | 402 | SQLite3.Database.sharedCache = true; 403 | 404 | spec.async( 405 | SQLite3JS.openAsync(dbFilename) 406 | .then(function (newDb) { 407 | db1 = newDb; 408 | return db1.runAsync( 409 | "CREATE TABLE IF NOT EXISTS TestData (id INTEGER PRIMARY KEY, value TEXT)"); 410 | }).then(function () { 411 | return db1.runAsync("DELETE FROM TestData"); 412 | }).then(function () { 413 | return SQLite3JS.openAsync(dbFilename) 414 | .then(function (newDb) { 415 | db2 = newDb; 416 | var i, db, promise, promises = []; 417 | for (i = 0; i < 50; i += 1) { 418 | db = i % 2 ? db1 : db2; 419 | promise = db.runAsync("INSERT INTO TestData (value) VALUES (?)", ["Value " + i]); 420 | promises.push(promise); 421 | } 422 | return WinJS.Promise.join(promises); 423 | }).then(function () { 424 | return SQLite3JS.openAsync(dbFilename); 425 | }).then(function (db) { 426 | return db.oneAsync("SELECT COUNT(*) as rowCount FROM TestData"); 427 | }).then(function (row) { 428 | expect(row.rowCount).toEqual(50); 429 | }); 430 | }) 431 | ); 432 | }); 433 | }); 434 | 435 | describe('Opening databases', function () { 436 | it('should open file with URI notation', function () { 437 | var thisSpec = this, 438 | path = Windows.Storage.ApplicationData.current.temporaryFolder.path + "\\uritest.db", 439 | uri = new Windows.Foundation.Uri(path); 440 | spec.async( 441 | SQLite3JS.openAsync(uri.rawUri).then(function (db) { 442 | expect(db).not.toBeNull(); 443 | db.close(); 444 | }, function (error) { 445 | thisSpec.fail('The error handler was called.'); 446 | }) 447 | ); 448 | }); 449 | }); 450 | 451 | describe('Error Handling', function () { 452 | it('should throw when creating an invalid database', function () { 453 | var thisSpec = this; 454 | 455 | spec.async( 456 | SQLite3JS.openAsync('invalid path').then(function (db) { 457 | thisSpec.fail('The error handler was not called.'); 458 | }, function (error) { 459 | expect(error.number & 0x0000ffff).toEqual(2); 460 | }) 461 | ); 462 | }); 463 | 464 | it('should throw when executing an invalid statement', function () { 465 | var thisSpec = this; 466 | 467 | spec.async( 468 | db.runAsync('invalid sql').then(function () { 469 | thisSpec.fail('The error handler was not called.'); 470 | }, function (error) { 471 | expect(error.number).toEqual(0x80004005/*E_FAIL*/); 472 | expect(db.lastError).toEqual('near \"invalid\": syntax error'); 473 | }) 474 | ); 475 | }); 476 | 477 | it('should fail on invalid bindings', function () { 478 | var thisSpec = this; 479 | 480 | spec.async( 481 | db.runAsync('SELECT * FROM Item WHERE name=?', [["Array"]]).then(function () { 482 | thisSpec.fail('The error handler was not called.'); 483 | }, function (error) { 484 | expect(error.number & 0x0000ffff).toEqual(1629/*ERROR_DATATYPE_MISMATCH*/); 485 | }) 486 | ); 487 | }); 488 | }); 489 | 490 | describe("Blobs", function () { 491 | var CryptographicBuffer = Windows.Security.Cryptography.CryptographicBuffer; 492 | 493 | beforeEach(function () { 494 | spec.async( 495 | db.runAsync("CREATE TABLE images(title TEXT, img BLOB)") 496 | ); 497 | }); 498 | 499 | afterEach(function () { 500 | spec.async(db.runAsync("DROP TABLE images")); 501 | }); 502 | 503 | it("should not allow other object types than buffers to be inserted", function () { 504 | var thisSpec = this; 505 | spec.async( 506 | Windows.ApplicationModel.Package.current.installedLocation.getFileAsync("images\\logo.png") 507 | .then(function gotFile(file) { 508 | return db.runAsync("INSERT INTO images(title, img) VALUES (?, ?)", ["a title", file]); 509 | }).then(function shouldNotComplete() { 510 | thisSpec.fail('Wooot? The error handler was not called.'); 511 | }, function shouldError(error) { 512 | expect(error.number).toEqual(0x8007065D/*ERROR_DATATYPE_MISMATCH*/); 513 | }) 514 | ); 515 | }); 516 | 517 | it("should allow buffers to be inserted as blobs", function () { 518 | var originalBuffer; 519 | spec.async( 520 | Windows.ApplicationModel.Package.current.installedLocation.getFileAsync("images\\logo.png") 521 | .then(function gotFile(file) { 522 | return Windows.Storage.FileIO.readBufferAsync(file) 523 | .then(function readContent(buffer) { 524 | return (originalBuffer = buffer); 525 | }); 526 | }).then(function readBuffer(buffer) { 527 | return db.runAsync("INSERT INTO images(title, img) VALUES (?, ?)", ["a title", buffer]); 528 | }).then(function inserted(count) { 529 | return db.oneAsync("SELECT img FROM images WHERE title='a title'"); 530 | }).then(function selected(row) { 531 | var div, selectedBuffer = CryptographicBuffer.decodeFromBase64String(row.img); 532 | expect(CryptographicBuffer.compare(originalBuffer, selectedBuffer)).toBeTruthy(); 533 | // For visual confirmation that everything went ok, display the image on the page 534 | div = document.createElement("img"); 535 | div.src = 'data:image/png;base64,' + row.img; 536 | document.body.appendChild(div); 537 | }) 538 | ); 539 | }); 540 | 541 | }); 542 | 543 | describe('Item Data Source', function () { 544 | beforeEach(function () { 545 | this.itemDataSource = db.itemDataSource('SELECT * FROM Item ORDER BY id', 'id'); 546 | }); 547 | 548 | it('should support getCount()', function () { 549 | spec.async( 550 | this.itemDataSource.getCount().then(function (count) { 551 | expect(count).toEqual(3); 552 | }) 553 | ); 554 | }); 555 | 556 | it('should support itemFromIndex()', function () { 557 | spec.async( 558 | this.itemDataSource.itemFromIndex(1).then(function (item) { 559 | expect(item.key).toEqual('2'); 560 | expect(item.data.name).toEqual('Orange'); 561 | }) 562 | ); 563 | }); 564 | }); 565 | 566 | describe('Group Data Source', function () { 567 | beforeEach(function () { 568 | this.groupDataSource = db.groupDataSource( 569 | 'SELECT LENGTH(name) AS key, COUNT(*) AS groupSize FROM Item GROUP BY key', 570 | 'key', 571 | 'groupSize'); 572 | }); 573 | 574 | it('should support getCount()', function () { 575 | spec.async( 576 | this.groupDataSource.getCount().then(function (count) { 577 | expect(count).toEqual(2); 578 | }) 579 | ); 580 | }); 581 | 582 | it('should support itemFromIndex()', function () { 583 | spec.async( 584 | this.groupDataSource.itemFromIndex(1).then(function (item) { 585 | expect(item.key).toEqual('6'); 586 | expect(item.groupSize).toEqual(2); 587 | expect(item.firstItemIndexHint).toEqual(1); 588 | }) 589 | ); 590 | }); 591 | 592 | it('should support itemFromKey()', function () { 593 | spec.async( 594 | this.groupDataSource.itemFromKey('5').then(function (item) { 595 | expect(item.key).toEqual('5'); 596 | expect(item.groupSize).toEqual(1); 597 | expect(item.firstItemIndexHint).toEqual(0); 598 | }) 599 | ); 600 | }); 601 | }); 602 | }); 603 | }()); 604 | -------------------------------------------------------------------------------- /SQLite3JS/strings/en-US/resources.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "testString1" : "Hello World!" 3 | } -------------------------------------------------------------------------------- /SQLite3JS/strings/en-US/secondary.resjson: -------------------------------------------------------------------------------- 1 | { 2 | "testString1" : "Goodbye World." 3 | } --------------------------------------------------------------------------------