From 4d745c4a3af42253eab6d4234e514b7471e93bc5 Mon Sep 17 00:00:00 2001 From: Jakob Stornig Date: Fri, 8 Dec 2023 16:24:21 +0100 Subject: [PATCH] integrated dev --- app/(tabs)/budget/index.tsx | 16 +++++ package-lock.json | 59 +++++++++++++++++ package.json | 6 +- services/database.ts | 127 ++++++++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 services/database.ts diff --git a/app/(tabs)/budget/index.tsx b/app/(tabs)/budget/index.tsx index 88c4d0a..001f94a 100644 --- a/app/(tabs)/budget/index.tsx +++ b/app/(tabs)/budget/index.tsx @@ -1,5 +1,21 @@ +import { useEffect } from 'react'; import { Text } from 'react-native'; +import { executeQuery, initDatabase, addCategory } from '../../../services/database'; export default function Page() { + + useEffect(() => { + initDatabase().then(); + addCategory("Test Category 2", "FFFFFF", "budget").then(); + + executeQuery("SELECT * FROM category").then((res) => { + console.log(res); + });; + + //deleteDatabase(); + }); + + + return Budget Page; } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6e8bf8b..2e67c4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "expo-router": "^2.0.0", "expo-secure-store": "~12.3.1", "expo-splash-screen": "~0.20.5", + "expo-sqlite": "~11.3.3", "expo-status-bar": "~1.6.0", "expo-system-ui": "~2.4.0", "expo-web-browser": "~12.3.2", @@ -25,6 +26,7 @@ "react-native-gesture-handler": "~2.12.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", + "react-native-uuid": "^2.0.1", "react-native-web": "~0.19.6" }, "devDependencies": { @@ -3200,6 +3202,18 @@ "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-13.0.0.tgz", "integrity": "sha512-TI+l71+5aSKnShYclFa14Kum+hQMZ86b95SH6tQUG3qZEmLTarvWpKwqtTwQKqvlJSJrpFiSFu3eCuZokY6zWA==" }, + "node_modules/@expo/websql": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@expo/websql/-/websql-1.0.1.tgz", + "integrity": "sha512-H9/t1V7XXyKC343FJz/LwaVBfDhs6IqhDtSYWpt8LNSQDVjf5NvVJLc5wp+KCpRidZx8+0+YeHJN45HOXmqjFA==", + "dependencies": { + "argsarray": "^0.0.1", + "immediate": "^3.2.2", + "noop-fn": "^1.0.0", + "pouchdb-collections": "^1.0.1", + "tiny-queue": "^0.2.1" + } + }, "node_modules/@expo/xcpretty": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.2.2.tgz", @@ -6836,6 +6850,11 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/argsarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz", + "integrity": "sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg==" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -9028,6 +9047,17 @@ "expo": "*" } }, + "node_modules/expo-sqlite": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-11.3.3.tgz", + "integrity": "sha512-73n+mhwi5mO28oVVrDGYcjy28XeUjNtpXVPtEmc+sr/NQ0hKlkIf2PD3/gKsyNuI8O/twNCZxsAQdM32yHGr8A==", + "dependencies": { + "@expo/websql": "^1.0.1" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-status-bar": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-1.6.0.tgz", @@ -9861,6 +9891,11 @@ "node": ">=14.0.0" } }, + "node_modules/immediate": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz", + "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==" + }, "node_modules/import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", @@ -14505,6 +14540,11 @@ "url": "https://github.com/sponsors/antelle" } }, + "node_modules/noop-fn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/noop-fn/-/noop-fn-1.0.0.tgz", + "integrity": "sha512-pQ8vODlgXt2e7A3mIbFDlizkr46r75V+BJxVAyat8Jl7YmI513gG5cfyRL0FedKraoZ+VAouI1h4/IWpus5pcQ==" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -15170,6 +15210,11 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/pouchdb-collections": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz", + "integrity": "sha512-31db6JRg4+4D5Yzc2nqsRqsA2oOkZS8DpFav3jf/qVNBxusKa2ClkEIZ2bJNpaDbMfWtnuSq59p6Bn+CipPMdg==" + }, "node_modules/prepend-http": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", @@ -15676,6 +15721,15 @@ "react-native": "*" } }, + "node_modules/react-native-uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-native-uuid/-/react-native-uuid-2.0.1.tgz", + "integrity": "sha512-cptnoIbL53GTCrWlb/+jrDC6tvb7ypIyzbXNJcpR3Vab0mkeaaVd5qnB3f0whXYzS+SMoSQLcUUB0gEWqkPC0g==", + "engines": { + "node": ">=10.0.0", + "npm": ">=6.0.0" + } + }, "node_modules/react-native-web": { "version": "0.19.9", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.9.tgz", @@ -16896,6 +16950,11 @@ "xtend": "~4.0.1" } }, + "node_modules/tiny-queue": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tiny-queue/-/tiny-queue-0.2.1.tgz", + "integrity": "sha512-EijGsv7kzd9I9g0ByCl6h42BWNGUZrlCSejfrb3AKeHC33SGbASu1VDf5O3rRiiUOhAC9CHdZxFPbZu0HmR70A==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/package.json b/package.json index 914e2df..8fff007 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,9 @@ "expo-font": "~11.4.0", "expo-linking": "~5.0.2", "expo-router": "^2.0.0", + "expo-secure-store": "~12.3.1", "expo-splash-screen": "~0.20.5", + "expo-sqlite": "~11.3.3", "expo-status-bar": "~1.6.0", "expo-system-ui": "~2.4.0", "expo-web-browser": "~12.3.2", @@ -34,8 +36,8 @@ "react-native-gesture-handler": "~2.12.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", - "react-native-web": "~0.19.6", - "expo-secure-store": "~12.3.1" + "react-native-uuid": "^2.0.1", + "react-native-web": "~0.19.6" }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/services/database.ts b/services/database.ts new file mode 100644 index 0000000..dbe3336 --- /dev/null +++ b/services/database.ts @@ -0,0 +1,127 @@ +//created by thschleicher + +import * as SQLite from "expo-sqlite"; +import uuid from "react-native-uuid"; + +import { Query } from "expo-sqlite"; + +const db = SQLite.openDatabase("interactive_systeme.db"); + +export const initDatabase = async () => { + try { + await db.transactionAsync(async (tx: SQLite.SQLTransactionAsync) => { + await tx.executeSqlAsync( + "CREATE TABLE IF NOT EXISTS category (guid VARCHAR(36) PRIMARY KEY, name TEXT, color TEXT, type TEXT);" + ); + await tx.executeSqlAsync( + "CREATE TABLE IF NOT EXISTS expense (guid VARCHAR(36) PRIMARY KEY, name TEXT, category_guid VARCHAR(36), datetime DATETIME, amount DOUBLE, FOREIGN KEY (category_guid) REFERENCES category(guid));" + ); + console.log("Successfully initialized Tables!"); + }); + } catch (error) { + + console.log("Error initializing the Tables!"); + throw (error); + } +}; + +export const addCategory = async (name: string, color: string, type: string) => { + + //needs user input validation for type and color (should be validated by this function) + + const UUID = uuid.v4(); + + try { + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync("INSERT INTO category (guid, name, color, type) VALUES (?, ?, ?, ?);", + [UUID.toString(), name, color, type] + ); + }); + console.log("Category added successfully!"); + } catch (error) { + console.log("Error adding category: ", error); + throw error; + } +} + +export const addExpense = async (name: string, category_guid: string,datetime: string, amount: number) => { + + //needs user input validation for type and color (should be validated by this function) + + const expenseUUID = uuid.v4(); + + try { + await db.transactionAsync(async (tx) => { + await tx.executeSqlAsync("INSERT INTO expense (guid, name, category_guid, datetime, amount) VALUES (?, ?, ?, ?, ?);", [expenseUUID.toString(), name, category_guid, datetime, amount] + ); + }); + console.log("Expense added successfully!"); + } catch (error) { + console.log("Error adding expense: ", error); + throw error; + } +}; + +export const deleteCategory = async (guid: string) => { + try { + await db.transactionAsync(async (tx: SQLite.SQLTransactionAsync) => { + await tx.executeSqlAsync("DELETE FROM category WHERE guid = ?;", [guid]); + }); + } catch(error) { + console.log("Error deleting category: ", error); + throw error; + } +} + +export const deleteExpense = async (guid: string) => { + try { + await db.transactionAsync(async (tx: SQLite.SQLTransactionAsync) => { + await tx.executeSqlAsync("DELETE FROM expense WHERE guid = ?;", [guid]); + }); + } catch(error) { + console.log("Error deleting expense: ", error); + throw error; + } +} + +export const executeQuery = async (query: string) => { + const sqliteQuary: Query[] = [{sql: query, args: []}]; + const result = await runQuery(sqliteQuary); + + if("rows" in result[0]) { + return result[0]["rows"]; + } + + console.error("Query could not be executed!"); +}; + +export const deleteDatabase = () => { + closeDatabase().then(() => { + try { + db.deleteAsync() + } catch (error) { + console.log("Error deleting the Database: ", error); + throw error; + } + + }); + console.log("Database Deleted!") +} + +const runQuery = async (query: Query[]) => { + try { + return await db.execAsync(query, true); + } catch (error) { + console.log("Error running Quary: ", error); + throw(error); + } +}; + +const closeDatabase = async () => { + try { + db.closeAsync(); + } catch (error) { + console.log("Error, cant close database: ", error); + throw error; + } +}