Im using expo-sqlite to making calls to the database. the problem is when i make a calls at the application startup. the calls get stuck somehow. never ending, and the application keep waiting.
This is my repository…
import BaseModule from '../baseModule';
import * as SQLite from 'expo-sqlite';
import * as MediaLibrary from 'expo-media-library';
import * as FileSystem from 'expo-file-system';
import * as Permissions from 'expo-permissions';
import {DetaliItemSettings, NovelReaderSettings, ChapterSettings} from '../';
import httpClient from '../http';
import includedParser from '../../includedParser';
import '../../interface/extension'
export type NovelReaderSettingsType = (items: BaseModule) => void;
export type Find = (foundItems: BaseModule[]) => void;
export default class Repository {
static dbIni: Boolean;
static selectedParser?: number
databaseName: string;
constructor() {
this.databaseName = 'NovelManager.db';
}
getParser =async()=> {
const parsers = includedParser();
if (Repository.selectedParser)
return parsers[Repository.selectedParser??0];
var novelReader =
(await this.findOne<NovelReaderSettings>('ApplicationSettings'))
? (await this.findOne<NovelReaderSettings>('ApplicationSettings'))
: (await this.save(NovelReaderSettings.default())) as NovelReaderSettings;
Repository.selectedParser = novelReader?.selectedParserIndex
return parsers[Repository.selectedParser??0];
}
importSettings = async (uri: string) => {
try {
const {status} = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
if (status === 'granted') {
var json = await FileSystem.readAsStringAsync(uri, {encoding: 'utf8'});
if (json) console.log(json);
var item = JSON.parse(json) as {
applicationSettings: any;
items: DetaliItemSettings[];
};
var appSettings = await this.where('ApplicationSettings');
if (item.applicationSettings) {
item.applicationSettings = httpClient.cloneItem(
appSettings.length > 0 ? appSettings[0] : {},
item.applicationSettings,
['id', 'tableName'],
);
await this.save(
item.applicationSettings,
undefined,
'ApplicationSettings',
);
}
if (item.items && item.items.length > 0) {
for (var i = 0; i < item.items.length; i++) {
var a = item.items[i];
var b = await this.where<DetaliItemSettings>('DetaliItems', {
novel: a.novel,
})
var aChapterSettings =
a.chapterSettings ?? ([] as ChapterSettings[]);
var bChaptersSettings =
b && b.length > 0
? ((await this.where<ChapterSettings>('Chapters', {
detaliItem_Id: b[0].id,
})))
: ([] as ChapterSettings[]);
var updatedChapterSettings = [] as ChapterSettings[];
if (b && b.length > 0) {
if (a.chapterIndex) b[0].chapterIndex = a.chapterIndex;
b[0].isFavorit = true;
a = b[0];
}
aChapterSettings.forEach((x) => {
var bCh = bChaptersSettings.find(
(a) => a.chapterUrl === x.chapterUrl,
);
if (bCh)
updatedChapterSettings.push(
httpClient.cloneItem(bCh, x, ['id', 'tableName']),
);
else updatedChapterSettings.push(x);
});
let detaliItemSettings = await this.save<DetaliItemSettings>(
a,
undefined,
'DetaliItems',
);
for (var y = 0; y <= aChapterSettings.length - 1; y++) {
let m = aChapterSettings[y];
m.detaliItem_Id = detaliItemSettings?.id ?? 0;
await this.save(m, undefined, 'Chapters');
}
}
}
return true;
}
} catch (error) {
console.log(error);
}
return false;
};
exportFileToDownloadFolder = async () => {
try {
const {status} = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
if (status === 'granted') {
var favoriteData = await this.where<DetaliItemSettings>('DetaliItems', {
isFavorit: true,
});
for (var i = 0; i < favoriteData.length; i++) {
var item = favoriteData[i];
item.chapterSettings = await this.where<ChapterSettings>('Chapters', {detaliItem_Id: item.id});
item.id = 0;
item.chapterSettings.forEach((x) => {
x.id = 0;
x.detaliItem_Id = 0;
});
}
var result = {
applicationSettings: await this.findOne<NovelReaderSettings>('ApplicationSettings'),
items: favoriteData,
};
let fileUri = FileSystem.documentDirectory + 'NovelManager.db';
await FileSystem.writeAsStringAsync(fileUri, JSON.stringify(result), {
encoding: FileSystem.EncodingType.UTF8,
});
const asset = await MediaLibrary.createAssetAsync(fileUri);
await MediaLibrary.createAlbumAsync('Download', asset, false);
return true;
}
} catch (error) {
console.log(error);
}
return false;
};
dataBasePath = () => {
return FileSystem.documentDirectory + this.databaseName;
};
createConnection = () => {
return SQLite.openDatabase(this.databaseName);
};
allowedKeys = (tableName: string) => {
return new Promise((resolve, reject) => {
this.createConnection().transaction(
(x) =>
x.executeSql(
`PRAGMA table_info(${tableName})`,
undefined,
(trans, data) => {
var keys = [] as string[];
for (var i = 0; i < data.rows.length; i++) {
if (data.rows.item(i).name != 'id')
keys.push(data.rows.item(i).name);
}
resolve(keys);
},
),
(error) => {
reject(error);
},
);
}) as Promise<string[]>;
};
async selectLastRecord<T> (item: BaseModule) {
console.log('Executing SelectLastRecord...');
return (await this.find(item.id <= 0 ? `SELECT * FROM ${item.tableName} ORDER BY id DESC LIMIT 1;` : `SELECT * FROM ${item.tableName} WHERE id=?;`,item.id > 0 ? [item.id] : undefined)).toType<T>().single<T>()
};
delete = async (item: BaseModule, tableName?: string) => {
tableName = item.tableName ?? tableName;
var q = `DELETE FROM ${tableName} WHERE id=?`;
await this.execute(q, [item.id]);
};
public save<T> (
item?: BaseModule,
insertOnly?: Boolean,
tableName?: string,
) {
if (!item)
return undefined;
if (!item.tableName) item.tableName = tableName ?? '';
return new Promise(async (resolve, reject) => {
try {
await this.setUpDataBase();
console.log('Executing Save...');
var items = await this.where(item.tableName, {id: item.id});
var keys = (await this.allowedKeys(item.tableName)).filter((x) =>
Object.keys(item).includes(x),
);
let query = '';
let args = [] as any[];
if (items.length > 0) {
if (insertOnly) return;
query = `UPDATE ${item.tableName} SET `;
keys.forEach((k, i) => {
query += ` ${k}=? ` + (i < keys.length - 1 ? ',' : '');
});
query += ' WHERE id=?';
} else {
query = `INSERT INTO ${item.tableName} (`;
keys.forEach((k, i) => {
query += k + (i < keys.length - 1 ? ',' : '');
});
query += ') values(';
keys.forEach((k, i) => {
query += '?' + (i < keys.length - 1 ? ',' : '');
});
query += ')';
}
keys.forEach((k: string, i) => {
args.push(item[k] ?? null);
});
if (items.length > 0) args.push(item.id);
await this.execute(query, args);
if (item["selectedParserIndex"])
Repository.selectedParser = item["selectedParserIndex"] as number;
resolve((await this.selectLastRecord<T>(item)));
} catch (error) {
console.log(error);
reject(error);
}
}) as Promise<T>;
};
public find = (query: string, args?: any[]) => {
return new Promise((resolve, reject) => {
this.createConnection().transaction(
async (x) => {
await this.setUpDataBase();
console.log('Executing Find..');
x.executeSql(
query,
args,
async (trans, data) => {
console.log('query executed:' + query);
var items = [] as BaseModule[];
for (var i = 0; i < data.rows.length; i++) {
var t = data.rows.item(i);
items.push(t);
}
resolve(items);
},
(_ts, error) => {
console.log('Could not execute query:' + query);
console.log(error);
reject(error);
return false;
},
);
},
(error) => {
console.log(error);
reject(error);
},
);
}) as Promise<BaseModule[]>;
};
async where<T> (tableName: string, query?: any) {
var q = `SELECT * FROM ${tableName} ${query ? 'WHERE ' : ''}`;
var values = [] as any[];
if (query) {
Object.keys(query).forEach((x, i) => {
q += x + '=? ' + (i < Object.keys(query).length - 1 ? 'AND ' : '');
values.push(query[x]);
});
}
return (await this.find(q, values)).map((x) => {
x.tableName = tableName;
return x;
}).toType<T>() ?? [];
};
async findOne<T> (tableName: string, query?: any) {
var items = await this.where<T>(tableName, query);
return items.single<T>();
};
execute = async (query: string, args?: any[]) => {
return new Promise((resolve, reject) => {
this.createConnection().transaction(
(tx) => {
console.log('Execute Query:' + query);
tx.executeSql(
query,
args,
(tx, results) => {
console.log('Statment has been executed....' + query);
resolve(true);
},
(_ts, error) => {
console.log('Could not execute query');
console.log(args);
console.log(error);
reject(error);
return false;
},
);
},
(error) => {
console.log('db executing statement, has been termineted');
console.log(args);
console.log(error);
reject(error);
throw 'db executing statement, has been termineted';
},
);
});
};
public dropTables = async () => {
await this.execute(`DROP TABLE if exists ApplicationSettings`);
await this.execute(`DROP TABLE if exists DetaliItems`);
await this.execute(`DROP TABLE if exists Chapters`);
Repository.dbIni = false;
await this.setUpDataBase();
};
setUpDataBase = async () => {
let applicationSetupQuery = `CREATE TABLE if not exists ApplicationSettings (
id INTEGER NOT NULL UNIQUE,
backGroundColor TEXT NOT NULL,
fontSize INTEGER NOT NULL,
lineHeight INTEGER NOT NULL,
fontFamily TEXT NOT NULL,
marginLeft INTEGER NOT NULL,
marginRight INTEGER NOT NULL,
detaliItem_Id INTEGER,
selectedParserIndex INTEGER,
PRIMARY KEY(id AUTOINCREMENT)
);`;
let detaliItemsQuery = `CREATE TABLE if not exists DetaliItems (
image TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT NOT NULL,
novel TEXT NOT NULL,
parserName TEXT NOT NULL,
chapterIndex INTEGER NOT NULL,
id INTEGER NOT NULL,
isFavorit INTEGER NOT NULL,
PRIMARY KEY(id AUTOINCREMENT)
);`;
let chapterQuery = `CREATE TABLE if not exists Chapters (
id INTEGER NOT NULL UNIQUE,
chapterUrl TEXT NOT NULL,
isViewed INTEGER NOT NULL,
currentProgress NUMERIC NOT NULL,
finished INTEGER NOT NULL,
detaliItem_Id INTEGER NOT NULL,
PRIMARY KEY(id AUTOINCREMENT),
CONSTRAINT "fk_detaliItem_id" FOREIGN KEY(detaliItem_Id) REFERENCES DetaliItems(id)
);`;
if (!Repository.dbIni) {
console.log('dbIni= false, setUpDataBase');
await this.execute(applicationSetupQuery);
await this.execute(detaliItemsQuery);
await this.execute(chapterQuery);
Repository.dbIni = true;
} else {
console.log('dbIni= true, setUpDataBase');
}
};
}
and when i call await new Repository().getParser()
it gets stuck and never end.