diff --git a/client/src/EditPage.jsx b/client/src/EditPage.jsx index 68f42b75..47275634 100644 --- a/client/src/EditPage.jsx +++ b/client/src/EditPage.jsx @@ -4,85 +4,95 @@ import './App.css'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate } from 'react-router-dom'; import { useState } from 'react'; - -const url = "http://127.0.0.1:3001" +import { apiUrl, fetchPage, postPage, deletePage } from './clientStuff.jsx'; function PageView() { const queryClient = useQueryClient(); const navigate = useNavigate(); const { pagenumber } = useParams(); - const [ text_of_page, setBodyText ] = useState("Not loaded yet"); - const { isPending, error, data } = useQuery({ // fetch the currrent values + const fetchQuery = useQuery({ // fetch the currrent values queryKey: ['page', pagenumber], - queryFn: () => - fetch(`${url}/page/${pagenumber}`, { - method: 'GET', - headers: {'Content-Type': 'application/json'} - }).then((res) => res.json()) - .then((data) => { - setBodyText(data[2]) - return data; - }) + queryFn: () => fetchPage(pagenumber) }) - const mutation = useMutation({ // for changing the value when we're done with it - mutationFn: ({id, title, description}) => { - console.log("trying to update!"); - const body = JSON.stringify({id: id, title: title, description: description}) - console.log(`sending ${body}`) - fetch(`${url}/page/${pagenumber}`, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: body - }).then((res) => { console.log("tried to update!", res.json()) }) - .catch((error) => { console.log("got an error", error.json()) }); - }, + const postMutation = useMutation({ // for changing the value when we're done with it + mutationFn: ({id, title, description}) => postPage({id, title, description}), onSettled: async (data, error, variables) => { // Invalidate and refetch await queryClient.invalidateQueries({ queryKey: ['page', variables.id] }) }, }); - function handleSubmit(e) { - e.preventDefault() - const data = e.target.querySelector('pre').innerHTML - const formData = new FormData(e.target); - mutation.mutate({ + const deleteMutation = useMutation({ // for changing the value when we're done with it + mutationFn: (id) => deletePage(id), + onSettled: async (data, error, variables) => { + // Invalidate and refetch + await queryClient.invalidateQueries({ queryKey: ['pages'] }) + }, + }); + + const ready = !(fetchQuery.error || fetchQuery.isPending); + + let the_id, page_title, page_text, page_html; + if (ready) [the_id, page_title, page_text, page_html] = fetchQuery.data; + if (!page_title) page_title = " "; + if (!page_text) page_text = " "; + + function submitChanges(e) { + const newTitle = document.querySelector('span').innerHTML; + const newText = document.querySelector('pre').innerHTML; + postMutation.mutate({ id: pagenumber, - title: page_title, - description: data, + title: newTitle, + description: newText, }); navigate(`/${pagenumber}`) } - if (isPending) return "Loading..."; - - if (error) return "Uh oh!"; + function submitDelete(e) { + e.preventDefault(); + deleteMutation.mutate(pagenumber); + navigate(`/`); + } - const [the_id, page_title, page_text] = data; return (
-
- logo + logo
-

{the_id}. {page_title}

-
-
-
 setBodyText(e.target.value)} 
-              dangerouslySetInnerHTML={{__html: text_of_page}} />
+            

+ {pagenumber}. + +

- + { ready ? + <> +
+
+              
+ + + + : +
+ { fetchQuery.isPending ? "Loading..." : JSON.stringify(fetchQuery.error) } +
+ }
-
); } diff --git a/client/src/Landing.jsx b/client/src/Landing.jsx index c2b98f0e..b66ea330 100644 --- a/client/src/Landing.jsx +++ b/client/src/Landing.jsx @@ -4,32 +4,22 @@ import './App.css'; import { useNavigate } from 'react-router-dom' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -const url = "http://127.0.0.1:3001" +import { apiUrl, fetchPageList, postNewPage } from './clientStuff.jsx'; function Landing() { const queryClient = useQueryClient(); const navigate = useNavigate(); const { isPending, error, data } = useQuery({ // fetch the currrent values queryKey: ['pages'], - queryFn: () => - fetch(`${url}/pages`, { - method: 'GET', - headers: {'Content-Type': 'application/json'} - }).then((res) => res.json()) + queryFn: fetchPageList }) const makeNewPage = useMutation({ // for changing the value when we're done with it - mutationFn: () => - fetch(`${url}/page/new`, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - }).then((res) => res.json()) - .then((data) => data.id) + mutationFn: () => postNewPage() .catch((error) => { console.log("got an error", error.json()) }), onSettled: async (data, error, variables) => { // Invalidate and navigate to the new page await queryClient.invalidateQueries({ queryKey: ['pages'] }); - console.log(data); navigate(`/${data}/edit`); }, }); @@ -37,13 +27,15 @@ function Landing() { return (
- logo + logo

Welcome to the forest!

+

This is some random stuff I added!

{ isPending ? "Loading..." : (error ? - (
{error}
) : -
    +
    {error}
    + : +
      { data.map((row) =>
    • @@ -51,10 +43,10 @@ function Landing() {
    • ) } -
+ ) } - +
); diff --git a/client/src/PageView.jsx b/client/src/PageView.jsx index 3c90d098..1324fe32 100644 --- a/client/src/PageView.jsx +++ b/client/src/PageView.jsx @@ -4,46 +4,41 @@ import './App.css'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate } from 'react-router-dom'; import { useState } from 'react'; - -const url = "http://localhost:3001" +import { apiUrl, fetchPage, postPage } from './clientStuff.jsx'; function PageView() { - const navigate = useNavigate(); const queryClient = useQueryClient(); + const navigate = useNavigate(); const { pagenumber } = useParams(); - const [ text_of_page, setBodyText ] = useState("Not loaded yet"); const { isPending, error, data } = useQuery({ // fetch the currrent values queryKey: ['page', pagenumber], - queryFn: () => - fetch(`${url}/page/${pagenumber}`, { - method: 'GET', - headers: {'Content-Type': 'application/json'} - }).then((res) => res.json()) - .then((data) => { - //console.log(`got ${data} as a response for ${pagenumber}`); - setBodyText(data[3]); - return data; - }) + queryFn: () => fetchPage(pagenumber) }) - if (isPending) return "Loading..."; + const ready = !(error || isPending); - if (error) return "Uh oh!"; - - const [the_id, page_title, page_text, page_html] = data; + let the_id, page_title, page_text, page_html; + if (data) [the_id, page_title, page_text, page_html] = data; return (
- logo + logo
-

{the_id}. {page_title}

+

{pagenumber}. {ready ? (page_title || " ") : "..."}

-
+ { ready ? +
+ : +
+ { isPending ? "Loading..." : JSON.stringify(error) } +
+ } +
diff --git a/client/src/clientStuff.jsx b/client/src/clientStuff.jsx new file mode 100644 index 00000000..8300c738 --- /dev/null +++ b/client/src/clientStuff.jsx @@ -0,0 +1,43 @@ +export const apiUrl = "http://127.0.0.1:3001" + +const defaults = { + headers: {'Content-Type': 'application/json'} +}; + +export async function postNewPage() { + return fetch(`${apiUrl}/page/new`, { + method: 'POST', + ...defaults + }).then((res) => res.json()) + .then((data) => data.id) +} + +export async function fetchPageList() { + return fetch(`${apiUrl}/pages`, { + method: 'GET', + ...defaults + }).then((res) => res.json()) +} + +export async function fetchPage(id) { + return fetch(`${apiUrl}/page/${id}`, { + method: 'GET', + ...defaults + }).then((res) => res.json()) +} + +export async function postPage({id, title, description}) { + return fetch(`${apiUrl}/page/${id}`, { + method: 'POST', + body: JSON.stringify({id: id, title: title, description: description}), + ...defaults + }) +} + +export async function deletePage(id) { + return fetch(`${apiUrl}/page/${id}`, { + method: 'DELETE', + headers: {'Content-Type': 'application/json'}, + ...defaults + }) +} \ No newline at end of file diff --git a/db/the_big_db.db/dbs/default/data-wal b/db/the_big_db.db/dbs/default/data-wal index 1657ef9d..14717028 100644 Binary files a/db/the_big_db.db/dbs/default/data-wal and b/db/the_big_db.db/dbs/default/data-wal differ diff --git a/db/the_big_db.db/dbs/default/stats.json b/db/the_big_db.db/dbs/default/stats.json index 477713b8..23bd392e 100644 --- a/db/the_big_db.db/dbs/default/stats.json +++ b/db/the_big_db.db/dbs/default/stats.json @@ -1 +1 @@ -{"id":"7de13931-444c-4dd2-a19a-5cd1e70b7f36","rows_written":87,"rows_read":1016,"storage_bytes_used":12288,"write_requests_delegated":0,"current_frame_no":86,"top_query_threshold":3,"top_queries":[{"rows_written":2,"rows_read":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n"},{"rows_written":0,"rows_read":4,"query":"select id from pages"},{"rows_written":0,"rows_read":5,"query":"select id from pages"},{"rows_written":1,"rows_read":4,"query":"\nalter table pages \nadd column html text\n"},{"rows_written":0,"rows_read":6,"query":"\nselect p.id from pages p where not exists (select r.id from renders r where p.id = r.id)\n"},{"rows_written":0,"rows_read":10,"query":"select id from pages"},{"rows_written":0,"rows_read":11,"query":"select id from pages"},{"rows_written":0,"rows_read":12,"query":"select id from pages"},{"rows_written":0,"rows_read":13,"query":"select id from pages"},{"rows_written":0,"rows_read":14,"query":"select id from pages"}],"slowest_query_threshold":0,"slowest_queries":[{"elapsed_ms":0,"query":"select id, title, description from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":2},{"elapsed_ms":1,"query":"\nalter table pages \nadd column html text\n","rows_written":1,"rows_read":4},{"elapsed_ms":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n","rows_written":2,"rows_read":1},{"elapsed_ms":1,"query":"insert into pages (title, description) values (?, ?) returning id","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"select * from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":1,"query":"select count(*) as num_pages from pages","rows_written":0,"rows_read":1},{"elapsed_ms":7,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1}],"embedded_replica_frames_replicated":0,"query_count":665,"query_latency":74555} \ No newline at end of file +{"id":"7de13931-444c-4dd2-a19a-5cd1e70b7f36","rows_written":109,"rows_read":1706,"storage_bytes_used":12288,"write_requests_delegated":0,"current_frame_no":108,"top_query_threshold":3,"top_queries":[{"rows_written":2,"rows_read":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n"},{"rows_written":0,"rows_read":4,"query":"select id from pages"},{"rows_written":0,"rows_read":5,"query":"select id from pages"},{"rows_written":1,"rows_read":4,"query":"\nalter table pages \nadd column html text\n"},{"rows_written":0,"rows_read":6,"query":"\nselect p.id from pages p where not exists (select r.id from renders r where p.id = r.id)\n"},{"rows_written":0,"rows_read":10,"query":"select id from pages"},{"rows_written":0,"rows_read":11,"query":"select id from pages"},{"rows_written":0,"rows_read":12,"query":"select id from pages"},{"rows_written":0,"rows_read":13,"query":"select id from pages"},{"rows_written":0,"rows_read":14,"query":"select id from pages"}],"slowest_query_threshold":0,"slowest_queries":[{"elapsed_ms":0,"query":"select id, title, description from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":2},{"elapsed_ms":1,"query":"\nalter table pages \nadd column html text\n","rows_written":1,"rows_read":4},{"elapsed_ms":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n","rows_written":2,"rows_read":1},{"elapsed_ms":1,"query":"insert into pages (title, description) values (?, ?) returning id","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"select * from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":1,"query":"select count(*) as num_pages from pages","rows_written":0,"rows_read":1},{"elapsed_ms":7,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1}],"embedded_replica_frames_replicated":0,"query_count":877,"query_latency":90259} \ No newline at end of file diff --git a/db/the_big_db.db/dbs/default/wallog b/db/the_big_db.db/dbs/default/wallog index ad4bd94c..3374cd94 100644 Binary files a/db/the_big_db.db/dbs/default/wallog and b/db/the_big_db.db/dbs/default/wallog differ diff --git a/server/server.js b/server/server.js index 93448ef5..9809181e 100644 --- a/server/server.js +++ b/server/server.js @@ -35,26 +35,9 @@ app.get('/pages', (req, res) => { .then((data) => data[0].results.rows) .then((rows) => rows.map(([id]) => id)) .then((ids) => res.json(ids)) - .catch((error) => res.status(404).json({"error": "error"})); + .catch((error) => res.status(500).json({"error": error})); }); -app.get('/page/:id', (req, res) => { - fetch(db_url, { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({ - statements: [{ - q: 'select * from pages where id=?', - params: [req.params.id] - }] - }) - }).then((rsp) => rsp.json()) - .then((data) => data[0].results.rows[0]) - .then((row) => res.json(row)) - .catch((error) => res.status(404).json({"error": error})); -}); - - app.post('/page/new', (req, res) => { fetch(db_url, { method: 'POST', @@ -68,7 +51,25 @@ app.post('/page/new', (req, res) => { }).then((rsp) => rsp.json()) .then((data) => data[0].results.rows[0][0]) .then((row) => res.status(200).json({id: row})) - .catch((error) => res.status(404).json({"error": error})) + .catch((error) => res.status(500).json({"error": error})) +}); + +app.get('/page/:id', (req, res) => { + fetch(db_url, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + statements: [{ + q: 'select * from pages where id=?', + params: [req.params.id] + }] + }) + }).then((rsp) => rsp.json()) + .then((data) => { + if (data[0].results.rows.length == 0) return res.status(404).json({"error": "page not found in db"}); + return data[0].results.rows[0]; + }).then((row) => res.status(200).json(row)) + .catch((error) => res.status(500).json({"error": error})); }); app.post('/page/:id', (req, res) => { @@ -90,5 +91,21 @@ app.post('/page/:id', (req, res) => { }] }) }).then(() => res.status(200).json({})) - .catch((error) => res.status(404).json({"error": error})); + .catch((error) => res.status(500).json({"error": error})); }); + +app.delete('/page/:id', (req, res) => { + console.log(`deleting page #${req.params.id}`); + + fetch(db_url, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + statements: [{ + q: 'delete from pages where id = ?', + params: [Number(req.params.id)] + }] + }) + }).then(() => res.status(200).json({id: req.params.id})) + .catch((error) => res.status(500).json({"error": error})) +})