Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 212 additions & 0 deletions sqldev/src/main/java/org/utplsql/sqldev/dal/UtplsqlDao.xtend
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,216 @@ class UtplsqlDao {
val nodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Node>(Node), #[objectType])
return nodes
}

/**
* Gets a list of oddgen's nodes as candidates to run utPLSQL tests.
*
* This functions must be called from an oddgen generator only, since the Node is not
* defined in the utPLSQL extension.
*
* @return list of oddgen nodes (complete hierarchy loaded eagerly)
* @throws DataAccessException if there is a problem
*/
def List<Node> runnables() {
var sql = '''
WITH
base AS (
SELECT rownum AS an_id,
o.object_owner,
o.object_type,
o.object_name,
lower(a.name) AS name,
a.text,
a.subobject_name
FROM table(ut3.ut_annotation_manager.get_annotated_objects(user, 'PACKAGE')) o
CROSS JOIN table(o.annotations) a
WHERE lower(a.name) in ('suite','suitepath', 'endcontext','test')
OR lower(a.name) = 'context' AND regexp_like(text, '(\w+)(\.\w+)*')
),
suite AS (
SELECT object_owner, object_type, object_name, text AS suite_description
FROM base
WHERE name = 'suite'
),
suitepath as (
SELECT object_owner, object_type, object_name, text as suitepath
FROM base
WHERE name = 'suitepath'
),
context_base AS (
SELECT an_id,
lead(an_id) over (partition by object_owner, object_type, object_name order by an_id) an_id_end,
object_owner,
object_type,
object_name,
name,
lead(name) over (partition by object_owner, object_type, object_name order by an_id) name_end,
text as context
FROM base
WHERE name IN ('context', 'endcontext')
),
context as (
SELECT an_id, an_id_end, object_owner, object_type, object_name, context
FROM context_base
WHERE name = 'context'
AND name_end = 'endcontext'
),
test AS (
SELECT b.an_id,
b.object_owner,
b.object_type,
b.object_name,
p.suitepath,
c.context,
b.subobject_name,
b.text AS test_description
FROM base b
LEFT JOIN suitepath p
ON p.object_owner = b.object_owner
AND p.object_type = b.object_type
AND p.object_name = b.object_name
LEFT JOIN context c
ON c.object_owner = b.object_owner
AND c.object_type = b.object_type
AND c.object_name = b.object_name
AND b.an_id BETWEEN c.an_id AND c.an_id_end
WHERE name = 'test'
AND (b.object_owner, b.object_type, b.object_name) IN (
select object_owner, object_type, object_name
from suite
)
),
suite_tree AS (
SELECT null AS parent_id,
'SUITE' AS id,
'All Suites' AS name,
'All utPLSQL test suites' AS description,
'PACKAGE_FOLDER_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM dual
UNION ALL
SELECT DISTINCT
'SUITE' AS parent_id,
object_owner || '.' || object_name AS id,
object_name AS name,
null AS description,
'PACKAGE_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM test
UNION ALL
SELECT object_owner || '.' || object_name AS parent_id,
object_owner || '.' || object_name || '.' || subobject_name AS id,
subobject_name AS name,
null AS description,
'PROCEDURE_ICON' AS iconName,
'Yes' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM test
),
suitepath_base AS (
SELECT DISTINCT
suitepath
FROM suitepath
),
gen AS (
SELECT rownum AS pos
FROM xmltable('1 to 100')
),
suitepath_part AS (
SELECT DISTINCT
substr(suitepath, 1, instr(suitepath || '.', '.', 1, g.pos) -1) AS suitepath
FROM suitepath_base b
JOIN gen g
On g.pos <= regexp_count(suitepath, '\w+')
),
suitepath_tree AS (
SELECT NULL AS parent_id,
'SUITEPATH' AS id,
'All Suitepaths' AS name,
'All utPLSQL test suitepathes' AS description,
'FOLDER_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM dual
UNION ALL
SELECT CASE
WHEN regexp_replace(suitepath,'\.?\w+$','') IS NULL THEN
'SUITEPATH'
ELSE
USER || ':' || regexp_replace(suitepath,'\.?\w+$','')
END AS parent_id,
USER || ':' || suitepath AS id,
regexp_substr(suitepath, '\.?(\w+$)', 1, 1, NULL, 1) AS name,
null AS description,
'FOLDER_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM suitepath_part
UNION ALL
SELECT DISTINCT
object_owner || ':' || suitepath AS parent_id,
object_owner || ':' || suitepath || '.' || object_name AS id,
object_name AS name,
null AS description,
'PACKAGE_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM test
WHERE suitepath IS NOT NULL
UNION ALL
SELECT DISTINCT
object_owner || ':' || suitepath || '.' || object_name AS parent_id,
object_owner || ':' || suitepath || '.' || object_name || '.' || context AS id,
context AS name,
null AS description,
'FOLDER_ICON' AS iconName,
'No' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM test
WHERE suitepath IS NOT NULL
AND context IS NOT NULL
UNION ALL
SELECT object_owner || ':' || suitepath || '.' || object_name || CASE WHEN context IS NOT NULL THEN '.' || context END AS parent_id,
object_owner || ':' || suitepath || '.' || object_name || CASE WHEN context IS NOT NULL THEN '.' || context END || '.' || subobject_name AS id,
subobject_name AS name,
null AS description,
'PROCEDURE_ICON' AS iconName,
'Yes' AS leaf,
'Yes' AS generatable,
'Yes' AS multiselectable,
'Yes' AS relevant
FROM test
WHERE suitepath IS NOT NULL
),
tree AS (
SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
FROM suite_tree
UNION ALL
SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
FROM suitepath_tree
)
SELECT parent_id, id, name, description, iconName, leaf, generatable, multiselectable, relevant
FROM tree
'''
val jdbcTemplate = new JdbcTemplate(new SingleConnectionDataSource(conn, true))
val nodes = jdbcTemplate.query(sql, new BeanPropertyRowMapper<Node>(Node))
return nodes
}

}
171 changes: 171 additions & 0 deletions sqldev/src/main/java/org/utplsql/sqldev/oddgen/RunGenerator.xtend
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* 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.oddgen

import java.sql.Connection
import java.util.ArrayList
import java.util.HashMap
import java.util.HashSet
import java.util.LinkedHashMap
import java.util.List
import oracle.ide.config.Preferences
import org.oddgen.sqldev.generators.OddgenGenerator2
import org.oddgen.sqldev.generators.model.Node
import org.utplsql.sqldev.dal.UtplsqlDao
import org.utplsql.sqldev.model.preference.PreferenceModel
import org.utplsql.sqldev.resources.UtplsqlResources

class RunGenerator implements OddgenGenerator2 {

public static val YES = "Yes"
public static val NO = "No"

public static var RESET_PACKAGE = UtplsqlResources.getString("PREF_RESET_PACKAGE_LABEL")
public static var CLEAR_SCREEN = UtplsqlResources.getString("PREF_CLEAR_SCREEN_LABEL")
public static var INDENT_SPACES = UtplsqlResources.getString("PREF_INDENT_SPACES_LABEL")

override isSupported(Connection conn) {
var ret = false
if (conn !== null) {
if (conn.metaData.databaseProductName.startsWith("Oracle")) {
if (conn.metaData.databaseMajorVersion == 11) {
if (conn.metaData.databaseMinorVersion >= 2) {
ret = true
}
} else if (conn.metaData.databaseMajorVersion > 11) {
ret = true
}
}
}
return ret
}

override getName(Connection conn) {
return "Run test"
}

override getDescription(Connection conn) {
return "Runs utPLSQL test packages in the current user."
}

override getFolders(Connection conn) {
val preferences = PreferenceModel.getInstance(Preferences.preferences)
val folders = new ArrayList<String>
for (f : preferences.rootFolderInOddgenView.split(",").filter[!it.empty]) {
folders.add(f.trim)
}
return folders
}

override getHelp(Connection conn) {
return "<p>not yet available</p>"
}

override getNodes(Connection conn, String parentNodeId) {
val preferences = PreferenceModel.getInstance(Preferences.preferences)
val params = new LinkedHashMap<String, String>()
params.put(RESET_PACKAGE, if (preferences.resetPackage) {YES} else {NO})
params.put(CLEAR_SCREEN, if (preferences.clearScreen) {YES} else {NO})
params.put(INDENT_SPACES, String.valueOf(preferences.indentSpaces))
val UtplsqlDao dao = new UtplsqlDao(conn)
val nodes = dao.runnables
for (node : nodes) {
node.params = params
}
return nodes
}

override getLov(Connection conn, LinkedHashMap<String, String> params, List<Node> nodes) {
val lov = new HashMap<String, List<String>>()
lov.put(RESET_PACKAGE, #[YES, NO])
lov.put(CLEAR_SCREEN, #[YES, NO])
lov.put(INDENT_SPACES, #["1", "2", "3", "4", "5", "6", "7", "8"])
return lov
}

override getParamStates(Connection conn, LinkedHashMap<String, String> params, List<Node> nodes) {
return new HashMap<String, Boolean>
}

def private getPath(Node node, Connection conn) {
if (node.id == "SUITE" || node.id == "SUITEPATH") {
return conn.metaData.userName
} else {
return node.id
}
}

def replaceTabsWithSpaces(CharSequence input, int indentSpaces) {
val spaces = String.format("%1$"+indentSpaces+"s", "")
return input.toString.replace("\t", spaces)
}

def dedup(List<Node> nodes) {
val set = new HashSet<String>
for (node : nodes) {
set.add(node.id)
}
val ret = new ArrayList<Node>
for (node : nodes) {
if (!set.contains(node.parentId)) {
ret.add(node)
}
}
return ret
}

override generateProlog(Connection conn, List<Node> nodes) {
val dedupNodes = nodes.dedup
val params = dedupNodes.get(0).params
val ret = '''
«IF params.get(RESET_PACKAGE) == YES»
EXECUTE dbms_session.reset_package;
«ENDIF»
SET SERVEROUTPUT ON SIZE UNLIMITED
«IF params.get(CLEAR_SCREEN) == YES»
CLEAR SCREEN
«ENDIF»
«IF dedupNodes.size == 1»
EXECUTE ut.run('«dedupNodes.get(0).getPath(conn)»');
«ELSE»
BEGIN
ut.run(
ut_varchar2_list(
«FOR node : dedupNodes SEPARATOR ","»
'«node.getPath(conn)»'
«ENDFOR»
)
);
END;
/
«ENDIF»
'''
return ret.replaceTabsWithSpaces(Integer.valueOf(params.get(INDENT_SPACES)))
}

override generateSeparator(Connection conn) {
return ""
}

override generateEpilog(Connection conn, List<Node> nodes) {
return ""
}

override generate(Connection conn, Node node) {
return ""
}

}
Loading