Создание SQlite/PouchDB с поддержкой React Web App и вопросы?
Моя цель
Создайте веб- приложение React JS, которое может работать в автономном режиме через сервис-работников и может запрашивать файл SQlite без какой-либо серверной части. Я использую ОС Linux.
Эта проблема
Я борюсь с использованием SQlite в веб-приложении React Js. Я использую create-реагировать-приложение и пытаюсь запросить базу данных SQlite.
Начиная с sqlite3
Я не могу установить sqlite3 как пакет npm, так как для него требуется зависимость с именем aws-sdk, и после установки этого пакета он выводит следующее:
/node_modules/sqlite3/node_modules/node-pre-gyp/lib/util/compile.js
Module not found: Can't resolve 'npm' in '/home/user/Documents/snv3/node_modules/sqlite3/node_modules/node-pre-gyp/lib/util'
./node_modules/sqlite3/node_modules/node-pre-gyp/lib/util/nw-pre-gyp/index.html 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
> <!doctype html>
| <html>
| <head>
Затем... я перешел к поиску другой библиотеки, поддерживающей sqlite, например, лучше-sqlite3
Лучше-Sqlite3
Когда лучше-sqlite3 импортируется, это выводится на экране моего браузера:
TypeError: Class is undefined
exports.wrap
node_modules/babel-loader/lib/index.js??ref--6-oneOf-2!/home/user/Documents/projectFolder/node_modules/better-sqlite3/lib/util.js:14
11 | };
12 |
13 | exports.wrap = function (Class, methodName, wrapper) {
> 14 | var originalMethod = Class.prototype[methodName];
15 |
16 | if (typeof originalMethod !== 'function') {
17 | throw new TypeError("Missing method ".concat(methodName));
Я понятия не имею, что это должно означать. В разделе устранения неполадок библиотеки ничего нет, поэтому отладка невозможна.
Kripken's Sql.js
Давайте попробуем что-то встроенное в Javascript и легкий.
О нет, моя куча памяти просто взорвалась, пытаясь скомпилировать ее:
Starting the development server...
<--- Last few GCs --->
tart of marking 2696 ms) (average mu = 0.196, current mu = 0.078) alloca[19981:0x317f660] 30702 ms: Mark-sweep 1387.3 (1425.7) -> 1382.8 (1424.7) MB, 2779.6 / 0.0 ms (+ 0.1 msin 91 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2806 ms) (average mu = 0.104, current mu = 0.010) allocati[19981:0x317f660] 33503 ms: Mark-sweep 1386.7 (1424.7) -> 1385.2 (1425.7) MB, 2780.3 / 0.0 ms (average mu = 0.056, current mu = 0.007) allocation failure scavenge might not succeed
<--- JS stacktrace --->
==== JS stack trace =========================================
0: ExitFrame [pc: 0x30bcb58041bd]
Security context: 0x346742d1e789 <JSObject>
1: get [0x146f266b8549] [/home/user/Documents/projectFolder/node_modules/@babel/traverse/lib/path/index.js:~99] [pc=0x30bcb6347fd5](this=0x2c6f95aa7759 <JSFunction NodePath (sfi =0x3a532511d061)>,/* anonymous */=0xb1cce8a8af9 <Object map = 0x3450d4054639>)
2: /* anonymous */(aka /* anonymous */) [0xb1cce8a8899] [/home/user/Documents/projectFolder/node_modul...
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
1: 0x8b8210 node::Abort() [/usr/local/bin/node]
2: 0x8b825c [/usr/local/bin/node]
3: 0xac1d1e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
4: 0xac1f38 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
5: 0xeb11f2 [/usr/local/bin/node]
6: 0xebd14a v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]
7: 0xebdab4 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
8: 0xec03e5 v8::internal::Heap::AllocateRawWithRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node]
9: 0xe888c4 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [/usr/local/bin/node]
10: 0x112a2ae v8::internal::Runtime_AllocateInNewSpace(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node]
11: 0x30bcb58041bd
Aborted (core dumped)
Ладно, забудьте библиотеки sqlite, давайте попробуем PouchDB!
Текущее решение
PouchDB
Итак, после всего этого беспорядка я отказался от использования библиотек SQlite и попытался сделать что-то, что было в первую очередь автономно: Pouch DB. Я думал, что можно было загрузить файл SQlite в пакет.
Поэтому я задал этот вопрос: как правильно загрузить предварительно собранные базы данных SQlite с PouchDB или без него в приложении React?
Нет, это база данных noSQL, это невозможно...
Затем мне пришлось конвертировать всю базу данных SQlite в файлы.json, все это делалось вручную...
Далее, давайте создадим базу данных и импортируем данные из файлов.json.
Изменить 1:
В моем файле SQlite есть что-то близкое к 5 тыс. Записей в каждой таблице. Таким образом, каждый файл.json, который я конвертировал из таблицы SQlite, имеет 5 тыс. Объектов или документов на ваш выбор. И есть 19 из этих файлов.json, каждый из которых представляет таблицу.
AAAAND... Мне нужно переключаться между файлами (таблицами).json для выполнения запросов, но после преобразования файлов атрибут _rev отсутствует, поэтому каждый раз, когда я загружаю реестры с использованием объемных документов, между таблицами возникают конфликты, потому что им не хватает атрибута _rev.
Это код моей службы БД:
import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';
import {
Example_Table_Name
} from '../../db'
PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);
class DbService {
constructor() {
this._db = new PouchDB('database');
}
static async dbLoad (table) {
const dbInstance = new DbService()._db
try {
const respose = await dbInstance.bulkDocs(TableEnumerator(table))
} catch(e) {
console.error(e)
}
}
static query(query) {
const dbInstance = new DbService()._db
return dbInstance.sql(query)
}
}
export default DbService;
Примеры документов:
Таблица 1:
{ "_id": "table1_010101012",
"Procedure": "XXXXX",
"field4": "",
"field5": "2B",
*insert here some more irrelevant data* }
Таблица 2:
{ "_id": "table2_0555444777",
"Procedure": "YYYYYYYYYYY",
"field4": "",
"field5": "2B",
*insert here some more irrelevant data* }
При первом вызове (dbLoad(Table1)) все документы загружаются, а атрибуты _rev создаются в первой таблице.
Когда я делаю другой вызов (dbLoad(Table2)), используя Table2.json, они конфликтуют, поскольку в новом файле отсутствует атрибут _rev, а когда Pouch создает этот атрибут, они совпадают!
Изменить 2:
Я пытался изменить свой код для этого:
import PDBLoad from 'pouchdb-load';
PouchDB.plugin(PDBLoad);
static async dbLoad (table) {
const db = new PouchDB(table);
try {
db.get('_local/preloaded').then(function (doc) {
}).catch(function (err) {
if (err.name !== 'not_found') {
throw err;
}
// we got a 404, so the local docuent doesn't exist. so let's preload!
return db.load('table_name.json').then(function () {
// create the local document to note that we've preloaded
return db.put({_id: '_local/preloaded'});
});
}).then(function () {
console.log({include_docs: true})
return db.allDocs({include_docs: true});
})
} catch(e) {
console.error(e)
}
}
Файл.json находился в том же каталоге, что и функция загрузки, но он не загружает данные.
Так что я придерживаюсь версии bulkDocs.
Вопросы
Я прошу прощения за очень длинный пост и после всей контекстуализации, возникают вопросы:
- Есть ли возможность настройки библиотек sqlite в среде React Web App?
- И без какого-либо бэкэнда?
- Каков рекомендуемый способ переключения между моими таблицами.json?
- Должен ли я удалить предыдущий сохраненный и загрузить следующий?
- Или загрузить каждую таблицу вручную, а затем выгрузить их, используя pouch-dump-cli?
Я надеюсь, что все хорошо объяснено, и я буду рад прояснить любые ваши вопросы.
Спасибо за ваше время!
Возможный ответ
Итак, я смог решить свою проблему, создав такой код.
import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';
PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);
class DbService {
static async dbLoad (table) {
const db = new PouchDB(table);
try {
await db.bulkDocs(TableEnumerator(table))
} catch(e) {
console.error(e)
}
return db
}
static async query(query, dbReference) {
return dbReference.sql(query)
}
}
export default DbService;
Где оператор switch является именем таблицы и возвращает документацию таблицы для вставки в IndexedDB. Для каждого файла.json я создаю новую базу данных, а затем для выполнения запросов, поскольку я использую React, я сохраняю ссылку на БД в состоянии компонентов.
Я думаю, что не хватает оптимизации, так как каждый раз, когда я переключаюсь между таблицами, я вызываю функцию, которая использует bulkDocs. Может быть, я должен проверить, если таблицы уже вставлены в IndexedDB.
0 ответов
Для будущих читателей, вот как вы можете решить проблему.
- Если у вас есть файл SQLite, перейдите к моему предыдущему заданному вопросу: как правильно загрузить предварительно собранные базы данных SQlite с PouchDB или без в приложении React
Найдите ответ на вопрос и выполните команды sqlite3, соответственно выводя файлы.json.
При вводе команды SELECT, если у вас есть какие-либо столбцы со специальными символами, например, пробел или точки в его имени, используйте оператор квадратных ракеток для имени столбца []:
sqlite3 пример ".output rslt.json" "SELECT '{\" id \ ": \" someTable ' || SUBSTR (\ "000000000 \" || id, LENGTH (\ "000000000 \" || id) - 8, 9) || '\ ", \" anattr \ ": \"' || анатр || '\ ", \" anothe.rattr \ ": \"' || [anoth.erattr] || '\ "},' FROM some_table;";
У меня возникла проблема, некоторые строки таблицы имели двойные кавычки: "Attr": "Lorem ipsum " dolor " ". Это вызывает ошибку синтаксического анализа. Для исправления используйте оператор escape-символа \ перед кавычками: "Lorem ipsum \"dolor\" ". Это должно исправить двойные кавычки.
Вы можете легко использовать регулярное выражение для сопоставления этого вхождения: \ "dolor \", это позволит найти двойные кавычки с желаемым словом внутри. Для быстрой замены напишите \ "dolor \" и замените все вхождения, непосредственно перед тем, как это сделать, проверьте, какие файлы вы модифицируете!!!!
Поскольку никто не проявил ничего по этому поводу, я отвечаю на свой вопрос с моим последним обновлением:
Итак, я смог решить свою проблему, создав такой код.
import PouchDB from 'pouchdb';
import PDBFind from 'pouchdb-find';
import PDBSilverLining from 'pouchdb-silverlining';
import TableEnumerator from '../utils/tableEnumerator';
PouchDB.plugin(PDBFind);
PouchDB.plugin(PDBSilverLining);
class DbService {
static async dbLoad (table) {
const db = new PouchDB(table);
try {
await db.bulkDocs(TableEnumerator(table))
} catch(e) {
console.error(e)
}
return db
}
static async query(query, dbReference) {
return dbReference.sql(query)
}
}
export default DbService;
Где оператор switch является именем таблицы и возвращает документацию таблицы для вставки в IndexedDB. Для каждого файла.json я создаю новую базу данных, а затем для выполнения запросов, поскольку я использую React, я сохраняю ссылку на БД в состоянии компонентов.
Я думаю, что не хватает оптимизации, так как каждый раз, когда я переключаюсь между таблицами, я вызываю функцию, использующую объемные документы. Может быть, я должен проверить, если таблицы уже вставлены в IndexedDB.
Это создает базу данных для каждого файла.json!!! Помните, это не оптимально! Я буду работать над оптимизированным подходом для этого.
Спасибо и спасибо Мартину за вашу помощь!