Skip to content

Commit 705c74a

Browse files
authored
feat: update dozer library (#128)
* feat: update react sample * feat: update vue sample * feat: update web-analytics demo * docs: update web-analytics guide * feat: update api-auth sample * feat: update api-auth favicon * fix: add deps for stream in api-auth movieList * feat: update usecases lambda * feat: update usecases snowflake-react
1 parent 837403c commit 705c74a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+4074
-794
lines changed

usecases/api-auth/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ cd ..
2222

2323
3. Generate a master token for auth by running the command from the project root directory where `dozer-config.yaml` is located:
2424
```bash
25-
dozer api generate-token
25+
dozer security generate-token
2626
```
2727

2828
4. Copy the `MASTER_TOKEN` generated from the previous step and export the `MASTER_TOKEN` as an environment variable
@@ -33,7 +33,7 @@ export MASTER_TOKEN=your_token_here
3333
5. Start the Dozer app. Dozer will start running, handling the data operations and APIs authorization as defined in your configuration. To do this, simply run the command:
3434

3535
```bash
36-
dozer
36+
dozer run
3737
```
3838

3939
6. Open the new terminal and change the directory to the `server` folder and install required package dependencies:

usecases/api-auth/client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6+
"@dozerjs/dozer": "^0.0.10",
7+
"@dozerjs/dozer-react": "^0.0.8",
68
"@emotion/react": "^11.10.5",
79
"@emotion/styled": "^11.10.5",
8-
"@dozerjs/dozer": "0.0.6",
9-
"@dozerjs/dozer-react": "0.0.4",
1010
"@mui/material": "^5.11.7",
1111
"@testing-library/jest-dom": "^5.16.5",
1212
"@testing-library/react": "^13.4.0",
-359 Bytes
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Loading

usecases/api-auth/client/src/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function App() {
1010
return (
1111
<div className="App">
1212
<header className="App-header">
13-
<img src="https://getdozer.io/img/logo.svg" className="App-logo" alt="logo" />
13+
<img src="/logo.svg" className="App-logo" alt="logo" />
1414
<BrowserRouter>
1515
<Routes>
1616
<Route element={<Login />} path={"/admin"} />
Lines changed: 33 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,23 @@
1-
import {useEffect, useState} from "react";
2-
import {Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";
3-
4-
import {useOnEvent, useQueryCommon} from "@dozerjs/dozer-react";
5-
import {OperationType} from "@dozerjs/dozer/lib/esm/generated/protos/types";
6-
import {useNavigate} from "react-router-dom";
1+
import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
2+
import { DozerProvider, useDozerEvent, useDozerQuery } from "@dozerjs/dozer-react";
3+
import { Navigate } from "react-router-dom";
74

85
function pad(num, size) {
96
num = num.toString();
107
while (num.length < size) num = "0" + num;
118
return num;
129
}
1310

14-
function Dashboard() {
15-
const navigate = useNavigate();
16-
const token = localStorage.getItem('token');
17-
if (!token) {
18-
navigate("/admin");
19-
}
20-
const [values, setValues] = useState([]);
21-
const query = { limit: 500000};
22-
const { records: events } = useQueryCommon("movies_with_bookings", query, token);
23-
24-
useOnEvent('movies_with_bookings', (data, _1, primaryIndexKeys, mapper) => {
25-
setValues(recs => {
26-
if (data.getTyp() === OperationType.UPDATE) {
27-
let oldValue = mapper.mapRecord(data.getOld().getValuesList());
28-
let existingIndex = recs.findIndex(v => primaryIndexKeys.every(k => v[k] === oldValue[k]))
29-
30-
if (existingIndex > -1) {
31-
recs[existingIndex] = mapper.mapRecord(data.getNew().getValuesList());
32-
33-
return [...recs]
34-
}
35-
}
36-
37-
if (data.getTyp() === OperationType.INSERT) {
38-
console.log('insert');
39-
return [...recs, mapper.mapRecord(data.getNew().getValuesList())]
40-
}
41-
42-
if (data.getTyp() === OperationType.DELETE && data.getNew()) {
43-
console.log('delete');
44-
let oldValue = mapper.mapRecord(data.getNew().getValuesList());
45-
let existingIndex = recs.findIndex(v => primaryIndexKeys.every(k => {
46-
return v[k] === oldValue[k]
47-
}))
48-
49-
if (existingIndex > -1) {
50-
recs.splice(existingIndex, 1);
51-
return [...recs]
52-
}
53-
}
54-
55-
return recs;
56-
});
57-
}, token);
58-
11+
function DataTable() {
12+
const query = { limit: 500000 };
13+
const { records, connect } = useDozerQuery("movies_with_bookings", query);
14+
const { stream } = useDozerEvent([{ endpoint: 'movies_with_bookings' }]);
15+
connect(stream);
5916

60-
useEffect(() => {
61-
if(values.length === 0) {
62-
setValues(events);
63-
}
64-
}, [events])
65-
66-
67-
if (values.length === 0) {
17+
if (records.length === 0) {
6818
return null;
6919
}
70-
71-
return <div>
72-
<h3>Admin dashboard</h3>
20+
return (
7321
<TableContainer component={Paper}>
7422
<Table sx={{ minWidth: 650 }} aria-label="simple table">
7523
<TableHead>
@@ -80,20 +28,35 @@ function Dashboard() {
8028
</TableRow>
8129
</TableHead>
8230
<TableBody>
83-
{ values.map(f => (
31+
{records.map(f => (
8432
<TableRow
85-
key={ f.id }
86-
sx={ { '&:last-child td, &:last-child th': { border: 0 } } }
33+
key={f.id}
34+
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
8735
>
88-
<TableCell component="th" scope="row">{ f.id }</TableCell>
89-
<TableCell>{ f.name }</TableCell>
90-
<TableCell align="center">{ f.count }</TableCell>
36+
<TableCell component="th" scope="row">{f.id}</TableCell>
37+
<TableCell>{f.name}</TableCell>
38+
<TableCell align="center">{f.count}</TableCell>
9139
</TableRow>
92-
)) }
40+
))}
9341
</TableBody>
9442
</Table>
9543
</TableContainer>
96-
</div>;
44+
)
45+
}
46+
47+
function Dashboard() {
48+
const token = localStorage.getItem('token');
49+
if (!token) {
50+
return <Navigate to="/admin" />
51+
}
52+
53+
54+
return <DozerProvider value={{
55+
authToken: token,
56+
}}>
57+
<h3>Admin dashboard</h3>
58+
<DataTable />
59+
</DozerProvider>;
9760
}
9861

9962
export default Dashboard;

usecases/api-auth/client/src/components/public/movies.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {useEffect, useState} from "react";
1+
import { useEffect, useState } from "react";
2+
import { DozerProvider } from '@dozerjs/dozer-react';
23
import MoviesList from "./moviesList";
34

45
function Movies() {
@@ -34,7 +35,11 @@ function Movies() {
3435
return null;
3536
}
3637

37-
return <MoviesList token={token} />;
38+
return <DozerProvider value={{
39+
authToken: token,
40+
}}>
41+
<MoviesList token={token} />
42+
</DozerProvider>
3843
}
3944

4045
export default Movies;

usecases/api-auth/client/src/components/public/moviesList.js

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,45 @@
1-
import {useEffect, useState} from "react";
2-
import {ApiClient} from "@dozerjs/dozer";
3-
import {Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow} from "@mui/material";
4-
import {useOnEvent} from "@dozerjs/dozer-react";
5-
import {OperationType} from "@dozerjs/dozer/lib/esm/generated/protos/types";
1+
import { useCallback, useEffect, useState } from "react";
2+
import { useDozerEvent, useDozerQuery } from "@dozerjs/dozer-react";
3+
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
4+
import { OperationType } from "@dozerjs/dozer/lib/esm/generated/protos/types";
5+
import { types_pb } from "@dozerjs/dozer";
6+
import { RecordMapper } from "@dozerjs/dozer/lib/esm/helper";
67

78
function MoviesList({ token }) {
8-
let [movies, setMovies] = useState([]);
99
let [tickets, setTickets] = useState({});
1010
let [user, setUser] = useState({});
1111

12-
useEffect(() => {
13-
if (token) {
14-
let client = new ApiClient("only_movies", {authToken: token});
15-
client.query().then(response => {
16-
setMovies(response[1]);
17-
});
18-
19-
let bookings_client = new ApiClient("user_bookings", {authToken: token});
20-
bookings_client.query().then(response => {
21-
let r = {};
22-
console.log(response);
23-
response[1].forEach(value => {
24-
r[value.movie_id] = value;
25-
})
26-
setTickets(r);
27-
});
28-
29-
let users_client = new ApiClient("users", {authToken: token});
30-
users_client.query().then(response => {
31-
setUser(response[1][0]);
32-
});
33-
}
34-
}, [token]);
12+
const { records: movies } = useDozerQuery("only_movies");
13+
const { records: userBookingsRecords, fields: userBookingsFields } = useDozerQuery("user_bookings");
14+
const { records: usersRecords, fields: usersFields } = useDozerQuery("users");
15+
const { stream } = useDozerEvent([
16+
{
17+
endpoint: 'user_bookings',
18+
eventType: types_pb.EventType.ALL,
19+
},
20+
{
21+
endpoint: 'users',
22+
eventType: types_pb.EventType.ALL,
23+
},
24+
]);
3525

36-
useOnEvent('user_bookings', (data, _1, primaryIndexKeys, mapper) => {
26+
const handleUserBookingsEvent = useCallback((data) => {
27+
if (userBookingsFields.length) {
28+
const mapper = new RecordMapper(userBookingsFields);
3729
setTickets(recs => {
3830
if (data.getTyp() === OperationType.UPDATE) {
39-
let recNew = mapper.mapRecord(data.getNew().getValuesList());
40-
let recOld = mapper.mapRecord(data.getOld().getValuesList());
31+
let recNew = mapper.mapRecord(data.getNew());
32+
let recOld = mapper.mapRecord(data.getOld());
4133

4234
return {
4335
...recs,
44-
[recOld.movie_id]: {...recOld},
45-
[recNew.movie_id]: {...recNew}
36+
[recOld.movie_id]: { ...recOld },
37+
[recNew.movie_id]: { ...recNew }
4638
};
4739
}
4840

4941
if (data.getTyp() === OperationType.INSERT) {
50-
let recNew = mapper.mapRecord(data.getNew().getValuesList());
42+
let recNew = mapper.mapRecord(data.getNew());
5143

5244
return {
5345
[recNew.movie_id]: recNew,
@@ -56,7 +48,7 @@ function MoviesList({ token }) {
5648
}
5749

5850
if (data.getTyp() === OperationType.DELETE && data.getNew()) {
59-
let recOld = mapper.mapRecord(data.getNew().getValuesList());
51+
let recOld = mapper.mapRecord(data.getNew());
6052
return {
6153
[recOld.movie_id]: null,
6254
...recs
@@ -65,23 +57,51 @@ function MoviesList({ token }) {
6557

6658
return recs;
6759
});
68-
},
69-
token)
60+
}
61+
}, [userBookingsFields]);
7062

71-
useOnEvent('users', (data, _1, primaryIndexKeys, mapper) => {
72-
setUser(recs => {
73-
if (data.getTyp() === OperationType.UPDATE || data.getTyp() === OperationType.INSERT) {
74-
return mapper.mapRecord(data.getNew().getValuesList());
75-
}
63+
const handleUsersEvent = useCallback((data) => {
64+
const mapper = new RecordMapper(usersFields);
65+
setUser(recs => {
66+
if (data.getTyp() === OperationType.UPDATE || data.getTyp() === OperationType.INSERT) {
67+
return mapper.mapRecord(data.getNew());
68+
}
7669

77-
if (data.getTyp() === OperationType.DELETE && data.getNew()) {
78-
return null;
79-
}
70+
if (data.getTyp() === OperationType.DELETE && data.getNew()) {
71+
return null;
72+
}
73+
74+
return recs;
75+
});
76+
}, [usersFields]);
77+
78+
useEffect(() => {
79+
const r = {};
80+
userBookingsRecords.forEach(value => {
81+
r[value.movie_id] = value;
82+
})
83+
setTickets(r);
84+
}, [userBookingsRecords])
85+
86+
useEffect(() => {
87+
setUser(usersRecords[0]);
88+
}, [usersRecords])
89+
90+
useEffect(() => {
91+
const cb = (operation) => {
92+
if (operation.getEndpointName() === 'user_bookings') {
93+
handleUserBookingsEvent(operation);
94+
}
95+
if (operation.getEndpointName() === 'users') {
96+
handleUsersEvent(operation);
97+
}
98+
}
99+
stream?.on('data', cb);
100+
return () => {
101+
stream?.removeListener(cb);
102+
}
103+
}, [stream, handleUserBookingsEvent, handleUsersEvent])
80104

81-
return recs;
82-
});
83-
},
84-
token)
85105
const buyTicket = (id) => {
86106
fetch('http://localhost:4000/public/book_movie', {
87107
method: 'POST',
@@ -119,19 +139,19 @@ function MoviesList({ token }) {
119139
</TableRow>
120140
</TableHead>
121141
<TableBody>
122-
{ movies.map(f => (
142+
{movies.map(f => (
123143
<TableRow
124-
key={ f.id }
125-
sx={ { '&:last-child td, &:last-child th': { border: 0 } } }
144+
key={f.id}
145+
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
126146
>
127-
<TableCell component="th" scope="row">{ f.id }</TableCell>
128-
<TableCell>{ f.name }</TableCell>
129-
<TableCell align={"center"}>{ tickets[f.id]?.count ?? 0 }</TableCell>
147+
<TableCell component="th" scope="row">{f.id}</TableCell>
148+
<TableCell>{f.name}</TableCell>
149+
<TableCell align={"center"}>{tickets[f.id]?.count ?? 0}</TableCell>
130150
<TableCell>
131151
<Button onClick={() => buyTicket(f.id)} variant="contained" color="primary">Buy ticket</Button>
132152
</TableCell>
133153
</TableRow>
134-
)) }
154+
))}
135155
</TableBody>
136156
</Table>
137157
</TableContainer>

0 commit comments

Comments
 (0)