Skip to content

Commit

Permalink
Part 1 of #5
Browse files Browse the repository at this point in the history
enable/disable "Run utPLSQL test" context menu item in Connections
navigator window
  • Loading branch information
PhilippSalvisberg committed Jan 30, 2018
1 parent f98feec commit e95e0cc
Show file tree
Hide file tree
Showing 9 changed files with 401 additions and 16 deletions.
151 changes: 151 additions & 0 deletions sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Copyright 2018 Philipp Salvisberg <philipp.salvisberg@trivadis.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.utplsql.sqldev.dal

import java.sql.Connection
import java.util.List
import org.springframework.dao.EmptyResultDataAccessException
import org.springframework.jdbc.core.BeanPropertyRowMapper
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.datasource.SingleConnectionDataSource
import org.utplsql.sqldev.model.ut.Annotation

class UtplsqlDao {
public static val UTPLSQL_PACKAGE_NAME = "UT"
private var Connection conn
private var JdbcTemplate jdbcTemplate

new(Connection conn) {
this.conn = conn
this.jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true))
}

/**
* Gets the schema name of the utPLSQL installation.
*
* @return utPLSQL schema or null if no utPLSQL is not installed
* @throws DataAccessException if there is a problem
*/
def String getUtplsqlSchema() {
val sql = '''
SELECT table_owner
FROM all_synonyms
WHERE owner = 'PUBLIC'
AND synonym_name = '«UTPLSQL_PACKAGE_NAME»'
AND table_name = '«UTPLSQL_PACKAGE_NAME»'
'''
try {
val schema = jdbcTemplate.queryForObject(sql, String)
return schema
} catch (EmptyResultDataAccessException e) {
return null
}
}

/**
* Checks if the package ut_annotation_manager is installed.
* This package has been introduced with utPLSQL 3.0.4.
* This version is a prerequisite to identify
* utPLSQL unit test procedures.
*
* @return true if ut_annotation_manager package has been found
* @throws DataAccessException if there is a problem
*/
def boolean isUtAnnotationManagerInstalled() {
if (utplsqlSchema !== null) {
val sql = '''
SELECT count(*)
FROM all_objects
WHERE owner = '«utplsqlSchema»'
AND object_type = 'PACKAGE'
AND object_name = 'UT_ANNOTATION_MANAGER'
'''
val found = jdbcTemplate.queryForObject(sql, Integer)
return found == 1
}
return false
}

/**
* Checks if utPLSQL tests exist
*
* @param owner schema name, mandatory, case-insensitive
* @param objectName name of the package or package body, optional, case-insensitive
* @param subobjectName name of the procedure, optional, case-insensitive
* @return true if at least one test has been found
* @throws DataAccessException if a utPLSQL version less than 3.0.4 is installed or if there are other problems
*/
def boolean containsUtplsqlTest(String owner, String objectName, String subobjectName) {
try {
val sql = '''
SELECT count(
CASE
WHEN a.name = 'test'
AND (upper(a.subobject_name) = upper(?) OR ? IS NULL)
THEN
1
ELSE
NULL
END
)
FROM TABLE(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o
CROSS JOIN TABLE(o.annotations) a
WHERE (o.object_name = upper(?) OR ? IS NULL)
AND a.name IN ('test', 'suite')
HAVING count(
CASE
WHEN a.name = 'suite' THEN
1
ELSE
NULL
END
) > 0
'''
val found = jdbcTemplate.queryForObject(sql, Integer, #[subobjectName, subobjectName, owner, objectName, objectName])
return found > 0
} catch (EmptyResultDataAccessException e) {
return false
}
}

def boolean containsUtplsqlTest(String owner) {
return containsUtplsqlTest(owner, null, null)
}

def boolean containsUtplsqlTest(String owner, String objectType) {
return containsUtplsqlTest(owner, objectType, null)
}

/**
* Gets a list of utPLSQL annotations for a given PL/SQL package specification
*
* @param owner schema name, mandatory, case-insensitive
* @param objectName name of the package or package body, optional, case-insensitive
* @return list of Annotation with name 'suite' or 'test'
* @throws DataAccessException if a utPLSQL version less than 3.0.4 is installed or if there are other problems
*/
def List<Annotation> annotations(String owner, String objectName) {
val sql = '''
SELECT o.object_owner, o.object_type, o.object_name, a.name, a.text, a.subobject_name
FROM TABLE(«utplsqlSchema».ut_annotation_manager.get_annotated_objects(upper(?), 'PACKAGE')) o
CROSS JOIN TABLE(o.annotations) a
WHERE o.object_name = upper(?)
'''
val result = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Annotation>(Annotation), #[owner, objectName])
return result
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,15 @@ class UtplsqlContextMenuListener implements ContextMenuListener {
if (element instanceof DatabaseConnection) {
showMenu = true
} else if (element instanceof ObjectFolder) {
if (element.objectType == "PACKAGE" || element.objectType == "TYPE") {
if (element.objectType == "PACKAGE") {
showMenu = true
}
} else if (element instanceof PlSqlNode) {
if (element.objectType == "PACKAGE" || element.objectType == "PACKAGE BODY" ||
element.objectType == "TYPE" || element.objectType == "TYPE BODY") {
if (element.objectType == "PACKAGE" || element.objectType == "PACKAGE BODY") {
showMenu = true
}
} else if (element instanceof ChildObjectElement) {
if (element.URL.objectType == "PACKAGE" || element.URL.objectType == "TYPE") {
if (element.URL.objectType == "PACKAGE") {
showMenu = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import oracle.dbtools.raptor.navigator.impl.ChildObjectElement
import oracle.dbtools.raptor.navigator.impl.DatabaseSourceNode
import oracle.dbtools.raptor.navigator.impl.ObjectFolder
import oracle.dbtools.raptor.navigator.plsql.PlSqlNode
import oracle.dbtools.raptor.utils.Connections
import oracle.dbtools.worksheet.editor.Worksheet
import oracle.ide.Context
import oracle.ide.Ide
import oracle.ide.controller.Controller
import oracle.ide.controller.IdeAction
import oracle.ide.editor.Editor
import org.utplsql.sqldev.UtplsqlWorksheet
import org.utplsql.sqldev.dal.UtplsqlDao
import org.utplsql.sqldev.model.URLTools
import org.utplsql.sqldev.parser.UtplsqlParser

Expand Down Expand Up @@ -62,7 +64,21 @@ class UtplsqlController implements Controller {
}
} else if (view instanceof DBNavigatorWindow) {
if (context.selection.length == 1) {
action.enabled = true
val element = context.selection.get(0)
val dao = new UtplsqlDao(Connections.instance.getConnection(context.URL.connectionName))
if (dao.utAnnotationManagerInstalled) {
if (element instanceof DatabaseConnection) {
action.enabled = dao.containsUtplsqlTest(element.connection.schema)
} else if (element instanceof ObjectFolder) {
action.enabled = dao.containsUtplsqlTest(element.URL.schema)
} else if (element instanceof PlSqlNode) {
action.enabled = dao.containsUtplsqlTest(element.owner, element.objectName)
} else if (element instanceof ChildObjectElement) {
action.enabled = dao.containsUtplsqlTest(element.URL.schema, element.URL.memberObject, element.shortLabel)
}
} else {
action.enabled = true
}
}
}
return true
Expand Down
29 changes: 29 additions & 0 deletions sqldev/src/main/java/org/utplsql/sqldev/model/ut/Annotation.xtend
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2018 Philipp Salvisberg <philipp.salvisberg@trivadis.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.utplsql.sqldev.model.ut

import org.eclipse.xtend.lib.annotations.Accessors
import org.utplsql.sqldev.model.AbstractModel

@Accessors
class Annotation extends AbstractModel {
String objectOwner
String objectType
String objectName
String name
String text
String subobjectName
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class UtplsqlParser {
}

private def populateObjects() {
val p = Pattern.compile("(?i)(\\s*)(create(\\s+or\\s+replace)?\\s+(package|type)\\s+(body\\s+)?)([^\\s]+)(\\s+)")
val p = Pattern.compile("(?i)(\\s*)(create(\\s+or\\s+replace)?\\s+(package)\\s+(body\\s+)?)([^\\s]+)(\\s+)")
val m = p.matcher(plsqlReduced)
while (m.find) {
val o = new PlsqlObject
Expand All @@ -94,7 +94,7 @@ class UtplsqlParser {
}
}
private def populateUnits() {
val p = Pattern.compile("(?i)(\\s*)(function|procedure)(\\s+)([^\\s\\(;]+)")
val p = Pattern.compile("(?i)(\\s*)(procedure)(\\s+)([^\\s\\(;]+)")
val m = p.matcher(plsqlReduced)
while (m.find) {
val u = new Unit
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2018 Philipp Salvisberg <philipp.salvisberg@trivadis.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.utplsql.sqldev.tests

import java.util.Properties
import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.datasource.SingleConnectionDataSource

abstract class AbstractJdbcTest {
protected static var SingleConnectionDataSource dataSource
protected static var JdbcTemplate jdbcTemplate
protected static var SingleConnectionDataSource sysDataSource
protected static var JdbcTemplate sysJdbcTemplate
// static initializer not supported in Xtend, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=429141
protected static val _staticInitializerForDataSourceAndJdbcTemplate = {
val p = new Properties()
p.load(AbstractJdbcTest.getClass().getResourceAsStream("/test.properties"))
// create dataSource and jdbcTemplate
dataSource = new SingleConnectionDataSource()
dataSource.driverClassName = "oracle.jdbc.OracleDriver"
dataSource.url = '''jdbc:oracle:thin:@«p.getProperty("host")»:«p.getProperty("port")»/«p.getProperty("service")»'''
dataSource.username = p.getProperty("scott_username")
dataSource.password = p.getProperty("scott_password")
jdbcTemplate = new JdbcTemplate(dataSource)
// create dbaDataSource and dbaJdbcTemplate
sysDataSource = new SingleConnectionDataSource()
sysDataSource.driverClassName = "oracle.jdbc.OracleDriver"
sysDataSource.url = '''jdbc:oracle:thin:@«p.getProperty("host")»:«p.getProperty("port")»/«p.getProperty("service")»'''
sysDataSource.username = p.getProperty("sys_username")
sysDataSource.password = p.getProperty("sys_password")
sysJdbcTemplate = new JdbcTemplate(AbstractJdbcTest.sysDataSource)
}
}
Loading

0 comments on commit e95e0cc

Please sign in to comment.