Skip to content

Commit 4cd9f8c

Browse files
committed
financial app work
1 parent 19fe750 commit 4cd9f8c

File tree

3 files changed

+188
-31
lines changed

3 files changed

+188
-31
lines changed

financial/react-frontend/src/pages/ATM.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ let mut tx = pool.begin().await?;
273273
sqlx::query!("UPDATE accounts SET balance = balance + $1 WHERE id = $2", amount, account_id)
274274
.execute(&mut tx)
275275
.await?;
276-
tx.commit().await?;`
276+
tx.commit().await?;`,
277+
"Ruby on Rails": `# Ruby on Rails (ActiveRecord)
278+
account = Account.find(account_id)
279+
account.balance += amount
280+
account.save!`
277281
};
278282

279283
// Set Java as default if nothing is selected
@@ -436,6 +440,16 @@ tx.commit().await?;`
436440
/>
437441
Rust
438442
</RadioLabel>
443+
<RadioLabel>
444+
<input
445+
type="radio"
446+
name="language"
447+
value="Ruby on Rails"
448+
checked={selectedLanguage === 'Ruby on Rails'}
449+
onChange={handleChange}
450+
/>
451+
Ruby on Rails
452+
</RadioLabel>
439453

440454
<Button type="submit">Submit</Button>
441455
</Form>

financial/react-frontend/src/pages/Graph.js

Lines changed: 136 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,53 @@ const ToggleButton = styled.button`
9090
}
9191
`;
9292

93+
const TwoColumnContainer = styled.div`
94+
display: flex;
95+
gap: 32px;
96+
width: 100%;
97+
@media (max-width: 900px) {
98+
flex-direction: column;
99+
gap: 0;
100+
}
101+
`;
102+
103+
const LeftColumn = styled.div`
104+
flex: 2;
105+
min-width: 320px;
106+
`;
107+
108+
const RightColumn = styled.div`
109+
flex: 1;
110+
min-width: 320px;
111+
background: ${bankerPanel};
112+
border: 1px solid ${bankerAccent};
113+
border-radius: 8px;
114+
padding: 20px;
115+
color: ${bankerText};
116+
font-family: 'Fira Mono', 'Consolas', 'Menlo', monospace;
117+
font-size: 0.98rem;
118+
white-space: pre-wrap;
119+
overflow-x: auto;
120+
margin-left: 16px;
121+
`;
122+
123+
const CodeTitle = styled.div`
124+
font-weight: bold;
125+
color: ${bankerAccent};
126+
margin-bottom: 12px;
127+
`;
128+
129+
const PanelSection = styled.div`
130+
margin-bottom: 32px;
131+
padding-bottom: 16px;
132+
border-bottom: 1px solid ${bankerAccent};
133+
&:last-child {
134+
border-bottom: none;
135+
margin-bottom: 0;
136+
padding-bottom: 0;
137+
}
138+
`;
139+
93140
const Graph = () => {
94141
const [cy, setCy] = useState(null);
95142
const [isCollapsed, setIsCollapsed] = useState(true);
@@ -194,6 +241,61 @@ const Graph = () => {
194241
}
195242
}
196243

244+
const staticCreateSnippet = `
245+
CREATE PROPERTY GRAPH "bank_graph"
246+
VERTEX TABLES (
247+
"FINANCIAL"."ACCOUNTS"
248+
KEY ( "ACCOUNT_ID" )
249+
PROPERTIES ( "ACCOUNT_BALANCE", "ACCOUNT_ID", "ACCOUNT_NAME", "ACCOUNT_OPENED_DATE", "ACCOUNT_OTHER_DETAILS", "ACCOUNT_TYPE", "CUSTOMER_ID" )
250+
)
251+
EDGE TABLES (
252+
"FINANCIAL"."TRANSFERS" KEY ( "TXN_ID" )
253+
SOURCE KEY ( "SRC_ACCT_ID" ) REFERENCES "ACCOUNTS"( "ACCOUNT_ID" )
254+
DESTINATION KEY ( "DST_ACCT_ID" ) REFERENCES "ACCOUNTS"( "ACCOUNT_ID" )
255+
PROPERTIES ( "AMOUNT", "DESCRIPTION", "DST_ACCT_ID", "SRC_ACCT_ID", "TXN_ID" )
256+
)
257+
`;
258+
259+
const staticCytoscapeSnippet = `
260+
function plotTransferEdge(cy, tx, index) {
261+
cy.add({
262+
data: {
263+
id: \`txn$\{tx.TXN_ID || \`$\{tx.src}_\${tx.dst}_\${index}\`}\`,
264+
source: String(tx.SRC_ACCT_ID || tx.src),
265+
target: String(tx.DST_ACCT_ID || tx.dst),
266+
label: tx.DESCRIPTION || tx.description || ''
267+
}
268+
});
269+
}
270+
`;
271+
272+
const staticPGXPythonSQLEtcSnippet = `
273+
%custom-algorithm-pgx
274+
// Write your GraphAlgorithm code here
275+
276+
%pgql-pgx
277+
/* Query and visualize 100 elements (nodes and edges) of BANK_GRAPH */
278+
SELECT * FROM match (s)-[t]->(d) on bank_graphLIMIT 100
279+
280+
%java-pgx
281+
PgxGraph graph = session.readGraphWithProperties(dataSourceName, 'graphName')
282+
283+
%sparql-rdf
284+
SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 15
285+
286+
%pgql-rdbms
287+
SELECT n,e,m FROM MATCH (n) -[e]-> (m) ON GRAPH_NAME
288+
289+
%sql
290+
SELECT * FROM TABLE_NAME
291+
292+
%python-pgx
293+
GRAPH_NAME="BANK_GRAPH"
294+
graph = session.get_graph(GRAPH_NAME)
295+
296+
%conda
297+
`;
298+
197299
return (
198300
<PageContainer>
199301
<h2>Process: Detect Money Laundering</h2>
@@ -272,16 +374,40 @@ const Graph = () => {
272374
)}
273375
</SidePanel>
274376

275-
{/* Cytoscape Graph */}
276-
<GraphContainer id="cy"></GraphContainer>
277-
278-
{/* Generate Transactions Button */}
279-
<GenerateButton onClick={() => generateCircularTransfersAndGraph(cy)}>
280-
Generate transactions to see corresponding graph
281-
</GenerateButton>
282-
<DangerButton onClick={clearAllTransfers}>
283-
Clear all transfer history
284-
</DangerButton>
377+
<TwoColumnContainer>
378+
<LeftColumn>
379+
{/* Cytoscape Graph */}
380+
<GraphContainer id="cy"></GraphContainer>
381+
382+
{/* Generate/Clear Buttons */}
383+
<GenerateButton onClick={() => generateCircularTransfersAndGraph(cy)}>
384+
Generate transactions to see corresponding graph
385+
</GenerateButton>
386+
<DangerButton onClick={clearAllTransfers}>
387+
Clear all transfer history
388+
</DangerButton>
389+
</LeftColumn>
390+
<RightColumn>
391+
<PanelSection>
392+
<CodeTitle>Create the graph...</CodeTitle>
393+
<code>
394+
{staticCreateSnippet}
395+
</code>
396+
</PanelSection>
397+
<PanelSection>
398+
<CodeTitle>Use Cytoscape to visualize and analyze the graph...</CodeTitle>
399+
<code>
400+
{staticCytoscapeSnippet}
401+
</code>
402+
</PanelSection>
403+
<PanelSection>
404+
<CodeTitle>Use PGX, Python, SQL, etc. to conduct graph operations, visualize, etc...</CodeTitle>
405+
<code>
406+
{staticPGXPythonSQLEtcSnippet}
407+
</code>
408+
</PanelSection>
409+
</RightColumn>
410+
</TwoColumnContainer>
285411
</PageContainer>
286412
);
287413
};

financial/react-frontend/src/pages/Transactions.js

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -262,26 +262,43 @@ const Transactions = () => {
262262
};
263263

264264
const codeSnippets = {
265-
lockFree: `// Lock-free Reservations (Oracle MicroTx)
266-
// No locks held, high concurrency, safe for hotspots
267-
POST /transfer
268-
{
269-
"fromAccount": "A123",
270-
"toAccount": "B456",
271-
"amount": 100,
272-
"useLockFreeReservations": true
273-
}
274-
// The database ensures atomicity and consistency using lock-free algorithms.`,
275-
standard: `// Standard Saga Transaction (Oracle MicroTx)
276-
// Traditional locking, safe for most workloads
277-
POST /transfer
278-
{
279-
"fromAccount": "A123",
280-
"toAccount": "B456",
281-
"amount": 100,
282-
"useLockFreeReservations": false
283-
}
284-
// The database uses standard locking for consistency.`
265+
lockFree: `// Auto-compensating distributed transactions reduces code by 80% and insures transactional integrity
266+
267+
public ResponseEntity<?> deposit //...
268+
microTxLockFreeReservation.join(connection);
269+
270+
//...
271+
272+
public ResponseEntity<?> compensate //...
273+
microTxLockFreeReservation.rollback(connection);
274+
`,
275+
standard: `
276+
// Traditional compensation logic, complicated and error-prone, requires book-keeping and extensive error handling
277+
278+
public ResponseEntity<?> deposit //...
279+
Account account = AccountTransferDAO.instance().getAccountForAccountId(accountId);
280+
AccountTransferDAO.instance().saveJournal(new Journal(DEPOSIT, accountId, 0, lraId,
281+
AccountTransferDAO.getStatusString(ParticipantStatus.Active)));
282+
AccountTransferDAO.instance().saveJournal(new Journal(DEPOSIT, accountId, depositAmount, lraId,
283+
AccountTransferDAO.getStatusString(ParticipantStatus.Active)));
284+
285+
//...
286+
287+
public ResponseEntity<?> compensate //...
288+
Journal journal = AccountTransferDAO.instance().getJournalForLRAid(lraId, WITHDRAW);
289+
String lraState = journal.getLraState();
290+
journal.setLraState(AccountTransferDAO.getStatusString(ParticipantStatus.Compensating));
291+
AccountTransferDAO.instance().saveJournal(journal);
292+
Account account = AccountTransferDAO.instance().getAccountForAccountId(journal.getAccountId());
293+
if (account != null) {
294+
account.setAccountBalance(account.getAccountBalance() + journal.getJournalAmount());
295+
AccountTransferDAO.instance().saveAccount(account);
296+
} else {
297+
journal.setLraState(AccountTransferDAO.getStatusString(ParticipantStatus.FailedToCompensate));
298+
}
299+
journal.setLraState(AccountTransferDAO.getStatusString(ParticipantStatus.Compensated));
300+
AccountTransferDAO.instance().saveJournal(journal);
301+
`
285302
};
286303

287304
const selectedSnippet = formData.useLockFreeReservations ? codeSnippets.lockFree : codeSnippets.standard;

0 commit comments

Comments
 (0)