Skip to content

Commit

Permalink
Merge pull request #70 from open-source-labs/development
Browse files Browse the repository at this point in the history
Merge Dev with Master
  • Loading branch information
jwagner988 authored Mar 9, 2022
2 parents 59b7dee + a24fb62 commit 11efe6d
Show file tree
Hide file tree
Showing 32 changed files with 896 additions and 25,555 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@
"ignorePackages",
{ "js": "never", "jsx": "never", "ts": "never", "tsx": "never" }
],
// "import/no-extraneous-dependencies": ["error", { "devDependencies": true }], **trying to resolve the electron issue
"jsx-a11y/label-has-associated-control": "off",
// prevent wrong warning with typescript overloads
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error"],
"no-dupe-class-members": "off",
"no-dupe-class-members": "off",
"@typescript-eslint/no-dupe-class-members": ["error"],
"lines-between-class-members": "off",
"@typescript-eslint/lines-between-class-members": [
Expand All @@ -52,5 +53,6 @@
"react/jsx-props-no-spreading": "off",
"camelcase": "off"
},
// "settings": "import/core-modules: [ electron ]", **trying to resolve the electron issue
"root": true
}
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

To get started on contributing to this project:

1. Download and install [Postgres.app](https://postgresapp.com/) and start it before opening up SeeQR
1. Download and install [Postgres.app](https://postgresapp.com/)(Mac)/[PGAdmin](https://www.pgadmin.org/download)(Windows) and start it before opening up SeeQR
2. Ensure that psql is available in the `$PATH`
3. Ensure that a 'postgres' role exists
4. Download the latest version of [SeeQR](https://github.com/open-source-labs/seeqr/releases/latest)
Expand Down Expand Up @@ -85,7 +85,7 @@ To get started on contributing to this project:
- Create/Edit Database <i>(currently in beta)</i>

- Users can create a new database from scratch by clicking the `Create New Database` button at the bottom of the sidebar
- Once a the database is given a name, htiting the `Initialize Database` button will create new database on the users PostgreSQL instance
- Once a the database is given a name, hitting the `Initialize Database` button will create new database on the users PostgreSQL instance
- Users can then input SQL commands and click `Update Database` to create and drop tables in the database
- Users have the option to alter any existing databases as well by selecting the database on the sidebar and running any SQL commands they would like.
- The `Export` button will write a .sql file on the user's desktop of the selected database
Expand All @@ -99,13 +99,24 @@ To get started on contributing to this project:

- In the 'QUERIES' view, the main panel is where the query input text field is located, utilizing CodeMirror. The paint button in the top right corner of the panel auto-formats the inputted query
- Users can select the database to use in the 'Database' dropdown above the main panel
- Users also have the option to execute a labelled or unlabelled query — simply provide a label in the 'Label' field above the main panel to identify the query in later comparisons against other queries
- Users also have the option to execute a labelled/grouped or unlabelled/ungrouped query — simply provide a label/group in the 'Label'/'Group' field above the main panel to identify the query in later comparisons against other queries
- Please note that only labelled queries will be saved in the current session for future references
- To execute the query, simply select the 'RUN QUERY' button at the bottom of the panel or press 'Ctrl-Enter' on the keyboard

<br />
<div align="center">
<img src="./assets/readmeImages/gifs/Query_Execution.gif" width=800/>
</div>

- Save/Load Queries

- In the 'QUERIES' view, the file upload icon will open a file explorer window to select a .JSON to import query data from
- The file icon to the right of the upload icon will designate the file path to save query data to if you press the save button on the queries
- To save individual query data press the save icon on the individual queries in the dropdowns

<br />
<div align="center">
<img src="./assets/readmeImages/gifs/query.gif" width=800/>
<img src="./assets/readmeImages/gifs/Save_Load_Queries.gif" width=800/>
</div>

- Data
Expand All @@ -121,21 +132,22 @@ To get started on contributing to this project:
- Clicking on a node will display additional details regarding that action as well
- To execute a new query, simply select the '+' button in the sidebar. To go back to a previously saved query, just select it in the sidebar


<br />
<div align="center">
<img src="./assets/readmeImages/gifs/execution_plan.gif" width=800/>
<img src="./assets/readmeImages/gifs/Query_Exec_Plan.gif" width=800/>
</div>

- Compare

- Click on the 'bar graph' icon at the top of the sidebar to get to the 'Compare Queries' view
- The comparison table is flexible to the user’s preferences as the user selects which queries to compare side by side
- Simply check or uncheck the box next to each saved query to add or remove the query from the graph
- Graph will be organized along the x-axis by label, and colored by schema
- Graph will be organized along the x-axis by group, and colored by schema
- Aside from the visualized performance comparison of the selected queries, a table will display information about each selected query, including its total run time and performance relative to other queries with the same label, with the most performant query highlighted

<div align="center">
<img src="./assets/readmeImages/gifs/compare_view.gif" width=800/>
<img src="./assets/readmeImages/gifs/Comparing_Queries.gif" width=800/>
</div>

## Application Architecture and Logic
Expand All @@ -152,7 +164,7 @@ We've released SeeQR because it's a useful tool to help optimize SQL databases.

## Core Team

[Allison Le](https://github.com/allisonle1) | [Brandon Lee](https://github.com/BrandonW-Lee) | [Casey Escovedo](https://github.com/caseyescovedo) | [Casey Walker](https://github.com/cwalker3011) | [Catherine Chiu](https://github.com/catherinechiu) | [Chris Akinrinade](https://github.com/chrisakinrinade) | [Cindy Chau](https://github.com/cindychau) | [Claudio Santos](https://github.com/Claudiohbsantos) | [Faraz Akhtar](https://github.com/faraza22) | [Frank Norton](https://github.com/FrankNorton32) | [Harrison Nam](https://github.com/harrynam07) | [James Kolotouros](https://github.com/dkolotouros) | [Jennifer Courtner](https://github.com/jcourtner) | [Justin Dury-Agri](https://github.com/justinD-A) | [Katie Klochan](https://github.com/kklochan) | [Mercer Stronck](https://github.com/mercerstronck) | [Muhammad Trad](https://github.com/muhammadtrad) | [Richard Guo](https://github.com/richardguoo) | [Richard Lam](https://github.com/rlam108) | [Sam Frakes](https://github.com/frakes413) | [Serena Kuo](https://github.com/serenackuo) | [Timothy Sin](https://github.com/timothysin)
[Allison Le](https://github.com/allisonle1) | [Brandon Lee](https://github.com/BrandonW-Lee) | [Casey Escovedo](https://github.com/caseyescovedo) | [Casey Walker](https://github.com/cwalker3011) | [Catherine Chiu](https://github.com/catherinechiu) | [Chris Akinrinade](https://github.com/chrisakinrinade) | [Cindy Chau](https://github.com/cindychau) | [Claudio Santos](https://github.com/Claudiohbsantos) | [Eric Han](https://github.com/ericJH92) | [Faraz Akhtar](https://github.com/faraza22) | [Frank Norton](https://github.com/FrankNorton32) | [Harrison Nam](https://github.com/harrynam07) | [James Kolotouros](https://github.com/dkolotouros) | [Jennifer Courtner](https://github.com/jcourtner) | [John Wagner](https://github.com/jwagner988) | [Justin Dury-Agri](https://github.com/justinD-A) | [Justin Hicks](https://github.com/JuiceBawks) | [Katie Klochan](https://github.com/kklochan) | [May Wirapa Boonyasurat](https://github.com/mimiwrp) | [Mercer Stronck](https://github.com/mercerstronck) | [Muhammad Trad](https://github.com/muhammadtrad) | [Richard Guo](https://github.com/richardguoo) | [Richard Lam](https://github.com/rlam108) | [Sam Frakes](https://github.com/frakes413) | [Serena Kuo](https://github.com/serenackuo) | [Timothy Sin](https://github.com/timothysin) | [Vincent Trang](https://github.com/vincentt114)


## License
Expand Down
43 changes: 34 additions & 9 deletions __tests__/frontend/lib/queries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
window.require = ((str: string) => str) as any
import * as queries from '../../../frontend/lib/queries';
import type { QueryData } from '../../../frontend/types';
import type { QueryData, ExplainJson } from '../../../frontend/types';

const first: Partial<QueryData> = {
label: 'firstQuery',
db: 'firstDb',
group: 'group1',
sqlString: 'select * from tests',
executionPlan: {
Plan: {
'Node Type': 'Seq Scan',
'Relation Name': 'users',
Alias: 'users',
'Startup Cost': 0,
'Total Cost': 0,
'Plan Rows': 0,
'Plan Width': 0,
'Actual Startup Time': 0,
'Actual Total Time': 0,
'Actual Rows': 0,
'Actual Loops': 0,
},
'Planning Time': 1,
'Execution Time': 1,
},
};

const second: Partial<QueryData> = {
Expand All @@ -15,15 +34,16 @@ const second: Partial<QueryData> = {

describe('key generation', () => {
it('should create key from label and db given as params', () => {
expect(queries.keyFromData('LABEL', 'DB')).toEqual('label:LABEL db:DB');
expect(queries.keyFromData('LABEL', 'DB', 'GROUP')).toEqual('label:LABEL db:DB group:GROUP');
});

it('should create key from query object', () => {
const query = {
label: 'query1',
db: 'db1',
group: 'group1'
};
expect(queries.key(query as QueryData)).toEqual('label:query1 db:db1');
expect(queries.key(query as QueryData)).toEqual('label:query1 db:db1 group:group1');
});
});

Expand Down Expand Up @@ -137,23 +157,28 @@ describe('setCompare', () => {

it('should not mutate original collection', () => {
expect(Object.keys(collection).length).toBe(0);
const newCollection = queries.setCompare({}, first as QueryData, true);
const newCollection = queries.setCompare({}, {}, first as QueryData, true);
expect(Object.keys(collection).length).toBe(0);
expect(newCollection).not.toBe(collection);
});

it('should add query to new collection if given true for isCompared', () => {
expect(Object.keys(collection).length).toBe(0);
const newCollection = queries.setCompare({}, first as QueryData, true);
const newCollection = queries.setCompare({}, {}, first as QueryData, true);
expect(Object.keys(newCollection).length).toBe(1);
expect(newCollection[queries.key(first as QueryData)]).toEqual(first);
});

it('should remove query from new collection if given false for isCompared', () => {
it('should set execution time to 0 if given false for isCompared', () => {
let qs:any = { [`${queries.key(first as QueryData)}`]: first };
expect(Object.keys(collection).length).toBe(0);
const newCollection = queries.setCompare({}, first as QueryData, true);
const newCollection = queries.setCompare({}, qs, first as QueryData, true);
expect(Object.keys(newCollection).length).toBe(1);
const clearedCollection = queries.setCompare({}, first as QueryData, false);
expect(Object.keys(clearedCollection).length).toBe(0);
expect(newCollection[queries.key(first as QueryData)].executionPlan['Planning Time']).toBe(1);
expect(newCollection[queries.key(first as QueryData)].executionPlan['Execution Time']).toBe(1);
const newSetCollection = queries.setCompare(newCollection, qs, first as QueryData, false);
expect(Object.keys(newSetCollection).length).toBe(1);
expect(newSetCollection[queries.key(first as QueryData)].executionPlan['Planning Time']).toBe(0);
expect(newSetCollection[queries.key(first as QueryData)].executionPlan['Execution Time']).toBe(0);
});
});
Binary file added assets/readmeImages/gifs/Comparing_Queries.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Generate_Dummy_Data.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Import_DB_&_Copy_DB.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Manual_Create_DB.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Query_Exec_Plan.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Query_Execution.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/readmeImages/gifs/Save_Load_Queries.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/readmeImages/gifs/compare_view.gif
Binary file not shown.
Binary file removed assets/readmeImages/gifs/execution_plan.gif
Binary file not shown.
Binary file removed assets/readmeImages/gifs/query.gif
Binary file not shown.
2 changes: 1 addition & 1 deletion backend/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import { FamilyRestroomRounded } from '@mui/icons-material';
import { app, BrowserWindow, Menu } from 'electron';

const dev: boolean = process.env.NODE_ENV === 'development';
Expand Down Expand Up @@ -71,7 +72,6 @@ if (dev) {
installExtension(REACT_DEVELOPER_TOOLS);
});
}

// Invoke createWindow to create browser windows after Electron has been initialized.
app.on('ready', createWindow);

Expand Down
1 change: 0 additions & 1 deletion backend/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const { Pool } = require('pg');
// Note: User must have a 'postgres' role set-up prior to initializing this connection. https://www.postgresql.org/docs/13/database-roles.html
const PG_URI: string = 'postgres://postgres:postgres@localhost:5432';
let pool = new Pool({ connectionString: PG_URI });
// console.log('Connected to: ', PG_URI);


// *********************************************************** HELPER FUNCTIONS ************************************************* //
Expand Down
6 changes: 5 additions & 1 deletion frontend/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ const App = () => {

const [selectedDb, setSelectedDb] = useState<AppState['selectedDb']>('');
const [sidebarIsHidden, setSidebarHidden] = useState(false);
const [newFilePath, setFilePath] = useState<AppState['newFilePath']>('');

/**
* Hook to create new Query from data
*/
const createNewQuery: CreateNewQuery = (query: QueryData) => {
// Only save query to saved queries if it contains all minimum information
if (query.label && query.db && query.sqlString) {
if (query.label && query.db && query.sqlString && query.group) {
const newQueries = createQuery(queries, query);
setQueries(newQueries);
}
Expand Down Expand Up @@ -115,6 +116,8 @@ const App = () => {
setWorkingQuery,
setSidebarHidden,
sidebarIsHidden,
setFilePath,
newFilePath
}}
/>
<Main $fullwidth={sidebarIsHidden}>
Expand All @@ -130,6 +133,7 @@ const App = () => {
setSelectedDb={setSelectedDb}
createNewQuery={createNewQuery}
show={shownView === 'queryView'}
queries={queries}
/>
<QuickStartView show={shownView === 'quickStartView'} />
<NewSchemaView
Expand Down
15 changes: 13 additions & 2 deletions frontend/components/sidebar/QueryEntry.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';

import styled from 'styled-components';
import {
IconButton,
ListItemSecondaryAction,
Checkbox,
Tooltip,
Button
} from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import {
Expand All @@ -13,13 +15,13 @@ import {
textColor,
} from '../../style-variables';
import { QueryData } from '../../types';
import SaveIcon from '@material-ui/icons/Save';

const QueryText = styled(StyledListItemText)`
& .MuiListItemText-secondary {
color: ${textColor};
}
`;

const CompareCheck = styled(Checkbox)`
color: ${textColor};
`;
Expand All @@ -31,6 +33,7 @@ interface QueryEntryProps {
setComparison: (evt: React.ChangeEvent<HTMLInputElement>) => void;
isCompared: boolean;
deleteThisQuery: () => void;
saveThisQuery: () => void;
}

const QueryEntry = ({
Expand All @@ -40,13 +43,19 @@ const QueryEntry = ({
setComparison,
isCompared,
deleteThisQuery,
saveThisQuery,
}: QueryEntryProps) => (
<SidebarListItem button $customSelected={isSelected} onClick={select}>
<QueryText primary={query.label} secondary={query.db} />
<QueryText primary={`${query.label} - ${query.db}`} />
<ListItemSecondaryAction>
<Tooltip title="View in Comparison">
<CompareCheck onChange={setComparison} checked={isCompared} />
</Tooltip>
<Tooltip title="Save Query">
<IconButton onClick={saveThisQuery}>
<SaveIcon fontSize='default' />
</IconButton>
</Tooltip>
<Tooltip title="Forget Query">
<IconButton edge="end" onClick={deleteThisQuery}>
<CloseIcon />
Expand All @@ -56,4 +65,6 @@ const QueryEntry = ({
</SidebarListItem>
);



export default QueryEntry;
Loading

0 comments on commit 11efe6d

Please sign in to comment.