Skip to content

Commit

Permalink
Merge pull request #993 from oskarhane/canary-allow-use-in-multi-stat…
Browse files Browse the repository at this point in the history
…ement

Enable database switching with `:use xx` in multi-statement command
  • Loading branch information
oskarhane authored Nov 25, 2019
2 parents c2c4dd4 + 8b2b8b6 commit c80793d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 33 deletions.
74 changes: 64 additions & 10 deletions e2e_tests/integration/multistatements.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,14 @@ describe('Multi statements', () => {
.title()
.should('include', 'Neo4j Browser')
cy.wait(5000)
cy.get('[data-testid="drawerSettings"]').click()
cy.get('[data-testid="enableMultiStatementMode"]').click()
cy.get('[data-testid="drawerSettings"]').click()
cy.enableMultiStatement()
})
after(() => {
cy.get('[data-testid="drawerSettings"]').click()
cy.get('[data-testid="enableMultiStatementMode"]').click()
cy.get('[data-testid="drawerSettings"]').click()
cy.disableMultiStatement()
})
it('can connect', () => {
const password = Cypress.config('password')
cy.connect(
'neo4j',
password
)
cy.connect('neo4j', password)
})
it('can run multiple statements (non open by default)', () => {
cy.executeCommand(':clear')
Expand Down Expand Up @@ -119,4 +112,65 @@ describe('Multi statements', () => {
.first()
.should('contain', 'ERROR')
})
if (Cypress.config('serverVersion') >= 4.0) {
it('Can use :use command in multi-statements', () => {
cy.executeCommand(':clear')
// Create databases
cy.executeCommand(':use system')
cy.get('[data-testid="frame"]', { timeout: 10000 }).should(
'have.length',
1
)
cy.executeCommand('DROP DATABASE test1')
cy.executeCommand('DROP DATABASE test2')
cy.get('[data-testid="frame"]', { timeout: 10000 }).should(
'have.length',
3
)
cy.executeCommand(':clear')

cy.executeCommand('CREATE DATABASE test1')
cy.get('[data-testid="frame"]', { timeout: 10000 }).should(
'have.length',
1
)
cy.executeCommand('CREATE DATABASE test2')
cy.get('[data-testid="frame"]', { timeout: 10000 }).should(
'have.length',
2
)
cy.executeCommand(':clear')

// Time to try it
const query = ':use test1; CREATE(:Test1); :use test2; CREATE(:Test2);'
cy.executeCommand(query)
cy.get('[data-testid="frame"]', { timeout: 10000 }).should(
'have.length',
1
)
const frame = cy.get('[data-testid="frame"]', { timeout: 10000 }).first()
frame.get('[data-testid="multi-statement-list"]').should('have.length', 1)
frame
.get('[data-testid="multi-statement-list-title"]')
.should('have.length', 4)
frame
.get('[data-testid="multi-statement-list-content"]')
.should('have.length', 0)

// Check sidebar for test1
cy.executeCommand(':use test1')
cy.get('[data-testid="drawerDBMS"]').click()
cy.contains('[data-testid="sidebarMetaItem"]', 'Test1', { timeout: 5000 })
cy.get('[data-testid="drawerDBMS"]').click()

cy.executeCommand(':use test2')
cy.get('[data-testid="drawerDBMS"]').click()
cy.contains('[data-testid="sidebarMetaItem"]', 'Test2', { timeout: 5000 })
cy.get('[data-testid="drawerDBMS"]').click()

cy.executeCommand(':use system')
cy.executeCommand('DROP DATABASE test1')
cy.executeCommand('DROP DATABASE test2')
})
}
})
10 changes: 10 additions & 0 deletions e2e_tests/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,13 @@ Cypress.Commands.add('addUser', (userName, password, role, force) => {
.contains('Add User')
.click()
})
Cypress.Commands.add('enableMultiStatement', () => {
cy.get('[data-testid="drawerSettings"]').click()
cy.get('[data-testid="enableMultiStatementMode"]').check()
cy.get('[data-testid="drawerSettings"]').click()
})
Cypress.Commands.add('disableMultiStatement', () => {
cy.get('[data-testid="drawerSettings"]').click()
cy.get('[data-testid="enableMultiStatementMode"]').uncheck()
cy.get('[data-testid="drawerSettings"]').click()
})
2 changes: 1 addition & 1 deletion src/browser/modules/Sidebar/Sidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function Sidebar (props) {
const AboutDrawer = About
const topNavItemsList = [
{
name: 'DB',
name: 'DBMS',
title: 'Database',
icon: isOpen => (
<DatabaseIcon
Expand Down
21 changes: 10 additions & 11 deletions src/browser/modules/Stream/CypherScriptFrame/Summary.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import ClickToCode from 'browser/modules/ClickToCode/index'
import { getBodyAndStatusBarMessages } from 'browser/modules/Stream/CypherFrame/helpers'
import { errorMessageFormater } from 'browser/modules/Stream/errorMessageFormater'
import {
Expand All @@ -28,6 +27,7 @@ import {
StyledCypherInfoMessage
} from 'browser/modules/Stream/styled'
import { MessageArea, PaddedStatsBar } from './styled'
import { whitelistedMultiCommands } from 'shared/modules/commands/commandsDuck'

const ucFirst = str => str[0].toUpperCase() + str.slice(1)

Expand Down Expand Up @@ -64,8 +64,12 @@ const GenericSummary = ({ status }) => {
<PaddedStatsBar>
<StyledCypherWarningMessage>WARNING</StyledCypherWarningMessage>
<MessageArea>
Only cypher and <code>:param</code> commands will be executed in the
multi statement mode.
Only the commands{' '}
{whitelistedMultiCommands().map((cmd, i) => {
const maybeComma = i > 0 ? ', ' : ''
return [maybeComma, <code key={cmd}>{cmd}</code>]
})}{' '}
and Cypher will be executed in the multi-statement mode.
</MessageArea>
</PaddedStatsBar>
)
Expand Down Expand Up @@ -105,7 +109,7 @@ export const CypherSummary = ({ status, request }) => {
}
}

export const Summary = ({ status }) => {
export const Summary = ({ status, request }) => {
switch (status) {
case 'ignored':
return <GenericSummary status={status} />
Expand All @@ -119,20 +123,15 @@ export const Summary = ({ status }) => {
return (
<PaddedStatsBar>
<StyledCypherSuccessMessage>SUCCESS</StyledCypherSuccessMessage>
<MessageArea>Parameter was successfully set</MessageArea>
<MessageArea>Command was successfully executed</MessageArea>
</PaddedStatsBar>
)
case 'error':
return (
<PaddedStatsBar>
<StyledCypherErrorMessage>ERROR</StyledCypherErrorMessage>
<MessageArea>
Error while setting parameter. Usage:{' '}
<code>:param x => [1, 2, 3]</code>. See{' '}
<ClickToCode code=':help param' execute>
:help param
</ClickToCode>{' '}
for more info.
{(request.result || {}).message || 'Unknown error'}
</MessageArea>
</PaddedStatsBar>
)
Expand Down
3 changes: 2 additions & 1 deletion src/shared/modules/commands/commandsDuck.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export const listDbsCommand = `dbs`

const initialState = {}
export const getErrorMessage = state => state[NAME].errorMessage
export const whitelistedMultiCommands = () => [':param', ':use']

export default function reducer (state = initialState, action) {
if (action.type === APP_START) {
Expand Down Expand Up @@ -174,7 +175,7 @@ export const handleCommandEpic = (action$, store) =>
cmd = cleanCommand(cmd)
const requestId = v4()
const cmdId = v4()
const whitelistedCommands = [`${cmdchar}param`]
const whitelistedCommands = whitelistedMultiCommands()
const isWhitelisted =
whitelistedCommands.filter(wcmd => !!cmd.startsWith(wcmd)).length > 0

Expand Down
30 changes: 20 additions & 10 deletions src/shared/services/commandInterpreterHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ const availableCommands = [
if (!existingDb) {
throw createErrorObject(
NotFoundError,
'Database with that name not found.'
'A database with that name not found.'
)
}
// Everything ok
Expand All @@ -217,15 +217,25 @@ const availableCommands = [
useDb: existingDb.name
})
)
} catch (e) {
put(
frames.add({
useDb: getUseDb(store.getState()),
...action,
type: 'error',
error: e
})
)
if (action.requestId) {
put(updateQueryResult(action.requestId, null, 'success'))
}
return true
} catch (error) {
if (!action.parentId) {
put(
frames.add({
useDb: getUseDb(store.getState()),
...action,
type: 'error',
error
})
)
}
if (action.requestId) {
put(updateQueryResult(action.requestId, error, 'error'))
}
throw error
}
}
},
Expand Down

0 comments on commit c80793d

Please sign in to comment.