extract some queries from the app pages

This commit is contained in:
Shoofle 2024-09-19 15:43:50 -04:00
parent d5ef81007d
commit 6ce4def6e5
8 changed files with 171 additions and 114 deletions

View File

@ -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...";
function submitDelete(e) {
e.preventDefault();
deleteMutation.mutate(pagenumber);
navigate(`/`);
}
if (error) return "Uh oh!";
const [the_id, page_title, page_text] = data;
return (
<div className="App">
<form onSubmit={handleSubmit}>
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<a href="/"><img src={logo} className="App-logo" alt="logo" /></a>
<div className="Page-title">
<h3>{the_id}. {page_title}</h3>
<h3>
{pagenumber}.
<span
contentEditable="true"
dangerouslySetInnerHTML={{__html: ready ? page_title : "..." }} />
</h3>
</div>
<div className="Page-contents">
<pre
contentEditable="true"
onChange={(e) => setBodyText(e.target.value)}
dangerouslySetInnerHTML={{__html: text_of_page}} />
</div>
<button
type="submit"
disabled={mutation.isPending}>
{mutation.isPending ? "Updating..." : "Update"}
</button>
{ ready ?
<>
<div className="Page-contents">
<pre
contentEditable="true"
dangerouslySetInnerHTML={{__html: page_text}} />
</div>
<button
disabled={postMutation.isPending}
onClick={submitChanges}>
{postMutation.isPending ? "Updating..." : "Update"}
</button>
<button
disabled={deleteMutation.isPending}
onClick={submitDelete}>
{deleteMutation.isPending ? "Deleting..." : "Delete this page (no backsies)"}
</button>
</>
:
<div className="Page-contents">
{ fetchQuery.isPending ? "Loading..." : JSON.stringify(fetchQuery.error) }
</div>
}
</header>
</form>
</div>
);
}

View File

@ -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 (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<a href="/"><img src={logo} className="App-logo" alt="logo" /></a>
<h3>Welcome to the forest!</h3>
<h4>This is some random stuff I added!</h4>
{ isPending ?
"Loading..." :
(error ?
(<pre>{error}</pre>) :
<ol>
<pre>{error}</pre>
:
<ul>
{
data.map((row) =>
<li>
@ -51,10 +43,10 @@ function Landing() {
</li>
)
}
</ol>
</ul>
)
}
<button onClick={makeNewPage.mutate} >Make new page!</button>
<button onClick={makeNewPage.mutate} >Dig!</button>
</header>
</div>
);

View File

@ -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 (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<a href="/"><img src={logo} className="App-logo" alt="logo" /></a>
<div className="Page-title">
<h3>{the_id}. {page_title}</h3>
<h3>{pagenumber}. {ready ? (page_title || " ") : "..."}</h3>
</div>
<div
className="Page-contents"
dangerouslySetInnerHTML={{ __html: text_of_page }}
/>
{ ready ?
<div
className="Page-contents"
dangerouslySetInnerHTML={{ __html: (page_html || " ") }}
/>
:
<div className="Page-contents">
{ isPending ? "Loading..." : JSON.stringify(error) }
</div>
}
<button type="submit" onClick={() => navigate(`/${pagenumber}/edit`)}>Edit this page!</button>
</header>
</div>

View File

@ -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
})
}

View File

@ -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}
{"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}

Binary file not shown.

View File

@ -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}))
})