diff --git a/app/panels/query_editor/common.js b/app/panels/query_editor/common.js
index c198bb2..eb125f9 100644
--- a/app/panels/query_editor/common.js
+++ b/app/panels/query_editor/common.js
@@ -23,8 +23,20 @@ const NODE_TYPE = {
ATTRIBUTE: "attribute"
};
+//Типы сущностей
+const ENTITY_TYPE = {
+ VIEW: "VIEW",
+ TABLE: "TABLE"
+};
+
+//Иконки типов сущностей
+const ENTITY_TYPE_ICON = {
+ [ENTITY_TYPE.VIEW]: "table_view",
+ [ENTITY_TYPE.TABLE]: "table_rows"
+};
+
//----------------
//Интерфейс модуля
//----------------
-export { DATA_TYPE, DATA_TYPE_ICON, NODE_TYPE };
+export { DATA_TYPE, DATA_TYPE_ICON, NODE_TYPE, ENTITY_TYPE, ENTITY_TYPE_ICON };
diff --git a/app/panels/query_editor/components/entity/entity.css b/app/panels/query_editor/components/entity/entity.css
deleted file mode 100644
index 1f64803..0000000
--- a/app/panels/query_editor/components/entity/entity.css
+++ /dev/null
@@ -1,33 +0,0 @@
-.entity__wrapper {
- width: 100%;
- height: 100%;
- border: 1px solid var(--border-color-dark);
- border-radius: 6px;
- box-shadow: var(--shadow-entity);
- overflow: hidden;
- background-color: white;
-}
-
-.entity__wrapper[data-selected="true"] {
- outline: 1px solid var(--outline-color);
- border-color: var(--outline-color);
-}
-
-.entity__title {
- width: 100%;
- height: 50px;
- align-content: center;
- border-bottom: 1px solid var(--border-color);
- font-weight: 900;
- text-align: center;
- background-color: var(--entity-title-bg);
- cursor: move;
-}
-
-.entity__name {
- width: 100%;
- align-content: center;
- text-align: center;
- font-size: 0.8rem;
- color: gray;
-}
diff --git a/app/panels/query_editor/components/entity/entity.js b/app/panels/query_editor/components/entity/entity.js
index b2503f5..6ccd2dc 100644
--- a/app/panels/query_editor/components/entity/entity.js
+++ b/app/panels/query_editor/components/entity/entity.js
@@ -9,47 +9,136 @@
import React from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
-import "./entity.css"; //Стили компомнента
+import { Box, Stack, ListItem, Icon, ListItemButton, Typography } from "@mui/material"; //Компоненты UI
+import { ENTITY_TYPE, ENTITY_TYPE_ICON } from "../../common"; //Общие ресурсы и константы редактора запросов
import { ATTRIBUTE_SHAPE } from "../attribute/attribute"; //Описание атрибута сущности
//---------
//Константы
//---------
+//Варианты представления сущности
+const ENTITY_VARIANT = {
+ LIST_ITEM: "LIST_ITEM",
+ DIAGRAM: "DIAGRAM"
+};
+
+//Иконки
+const ICONS = { ...ENTITY_TYPE_ICON, DEFAULT: "border_clear" };
+
//Структура данных о сущности запроса
const ENTITY_SHAPE = PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
+ type: PropTypes.oneOf(Object.values(ENTITY_TYPE)).isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
attrs: PropTypes.arrayOf(ATTRIBUTE_SHAPE).isRequired
});
+//Структура данных о сущности запроса (краткая)
+const ENTITY_BRIEF_SHAPE = PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ type: PropTypes.oneOf(Object.values(ENTITY_TYPE)).isRequired
+});
+
+//Стили
+const STYLES = {
+ CONTAINER: selected => ({
+ width: "100%",
+ height: "100%",
+ border: "1px solid var(--border-color-dark)",
+ borderRadius: "6px",
+ boxShadow: "var(--shadow-entity)",
+ overflow: "hidden",
+ backgroundColor: "white",
+ cursor: "move",
+ ...(selected
+ ? {
+ outline: "1px solid var(--outline-color)",
+ borderColor: "var(--outline-color)"
+ }
+ : {})
+ }),
+ CONTENT_STACK: variant => ({
+ width: "100%",
+ backgroundColor: "var(--entity-title-bg)",
+ ...(variant === ENTITY_VARIANT.DIAGRAM ? { height: "50px" } : {})
+ }),
+ CAPTIONS_TYPOGRAPHY: variant => ({ ...(variant === ENTITY_VARIANT.DIAGRAM ? { maxWidth: "100px", overflow: "hidden" } : {}) })
+};
+
//-----------
//Тело модуля
//-----------
//Сущность запроса
-const Entity = ({ data, selected = false }) => {
- return (
-
-
-
{data.title}
-
{data.name}
-
-
+const Entity = ({ data, variant = ENTITY_VARIANT.DIAGRAM, selected = false, onClick = null }) => {
+ //Иконка
+ const icon = ICONS[data.type] || ICONS.DEFAULT;
+
+ //Всплывающая подсказка
+ const iconTitle = data.type === ENTITY_TYPE.VIEW ? "Представление" : "Таблица";
+
+ //Содержимое самой сущности
+ const entContent = (
+
+
+ {icon}
+
+
+
+ {data.title}
+
+
+ {data.name}
+
+
+
);
+
+ //Формирование представления
+ return variant == ENTITY_VARIANT.LIST_ITEM ? (
+
+ onClick && onClick(data)} dense>
+ {entContent}
+
+
+ ) : variant == ENTITY_VARIANT.DIAGRAM ? (
+ {entContent}
+ ) : null;
};
//Контроль свойств компонента - Сущность запроса
Entity.propTypes = {
- data: ENTITY_SHAPE.isRequired,
- selected: PropTypes.bool
+ data: PropTypes.oneOfType([ENTITY_SHAPE, ENTITY_BRIEF_SHAPE]).isRequired,
+ variant: PropTypes.string,
+ selected: PropTypes.bool,
+ onClick: PropTypes.func
};
//----------------
//Интерфейс модуля
//----------------
-export { Entity, ENTITY_SHAPE };
+export { Entity, ENTITY_VARIANT, ENTITY_SHAPE, ENTITY_BRIEF_SHAPE };
diff --git a/app/panels/query_editor/components/inspector_query_ents/entity_add_dialog.js b/app/panels/query_editor/components/inspector_query_ents/entity_add_dialog.js
index b67a589..54b05c4 100644
--- a/app/panels/query_editor/components/inspector_query_ents/entity_add_dialog.js
+++ b/app/panels/query_editor/components/inspector_query_ents/entity_add_dialog.js
@@ -7,33 +7,103 @@
//Подключение библиотек
//---------------------
-import React from "react"; //Классы React
+import React, { useState } from "react"; //Классы React
import PropTypes from "prop-types"; //Контроль свойств компонента
-import { P8PDialog } from "../../../../components/p8p_dialog"; //Типовой диалог
+import { Box, TextField, InputAdornment, Icon, IconButton } from "@mui/material"; //Интерфейсные элементы MUI
+import { P8PDialog, P8P_DIALOG_WIDTH } from "../../../../components/p8p_dialog"; //Типовой диалог
+import { P8PComponentInlineMessage } from "../../../../components/editors/p8p_component_inline_message"; //Типовое встраиваемое сообщение
import { TITLES } from "../../../../../app.text"; //Общие текстовые ресурсы приложения
+import { EntsList } from "./ents_list"; //Список сущостей
+import { useEntities, useDebounce } from "./hooks"; //Хуки для работы с сущностями
+
+//---------
+//Константы
+//---------
+
+//Максимальная длина поисковой фразы для начала поиска (символов)
+const FILTER_MIN_LENGTH = 3;
+
+//Таймаут ожидания ввода поисковой фразы до начала поиска на сервере (мс)
+const FILTER_TIMEOUT = 1000;
+
+//Стили
+const STYLES = {
+ LIST_CONTAINER: { width: "100%", height: "500px" }
+};
//-----------
//Тело модуля
//-----------
//Диалог добавления сущности запроса
-const EntityAddDialog = ({ onOk, onCancel }) => {
- //Нажатие на кнопку "Ok"
- const handleOk = values => onOk && onOk({ ...values });
+const EntityAddDialog = ({ onSelect, onClose }) => {
+ //Собственное состояние - фильтр сущностей
+ const [filter, setFilter] = useState("");
- //Нажатие на кнопку "Отмена"
- const handleCancel = () => onCancel && onCancel();
+ //Значение для отложенного поиска
+ const debouncedFilter = useDebounce(filter, FILTER_TIMEOUT);
+
+ //Доступные сущности
+ const [ents] = useEntities(debouncedFilter, FILTER_MIN_LENGTH);
+
+ //При выборе сущности в списке
+ const handleSelect = ent => onSelect && onSelect({ ...ent });
+
+ //Нажатие на кнопку "Закыть"
+ const handleClose = () => onClose && onClose();
+
+ //При изменении значения фильтра
+ const handleFilterChange = e => setFilter(e.target.value);
+
+ //При очистке фильтра
+ const handleFilterClear = () => setFilter("");
//Генерация содержимого
return (
-
+
+
+ search
+
+ ),
+ endAdornment: (
+
+
+ clear
+
+
+ )
+ }}
+ />
+
+ {ents && }
+ {!ents && (
+ FILTER_MIN_LENGTH
+ ? "Измените значение фильтра для повторного поиска"
+ : `Начните ввод в строку поиска (не менее ${FILTER_MIN_LENGTH} символов)`
+ }
+ />
+ )}
+
+
);
};
//Контроль свойств - Диалог добавления сущности запроса
EntityAddDialog.propTypes = {
- onOk: PropTypes.func,
- onCancel: PropTypes.func
+ onSelect: PropTypes.func,
+ onClose: PropTypes.func
};
//----------------
diff --git a/app/panels/query_editor/components/inspector_query_ents/ents_list.js b/app/panels/query_editor/components/inspector_query_ents/ents_list.js
new file mode 100644
index 0000000..24dbe9d
--- /dev/null
+++ b/app/panels/query_editor/components/inspector_query_ents/ents_list.js
@@ -0,0 +1,52 @@
+/*
+ Парус 8 - Панели мониторинга - Редактор запросов
+ Компонент: Список сущностей
+*/
+
+//---------------------
+//Подключение библиотек
+//---------------------
+
+import React from "react"; //Классы React
+import PropTypes from "prop-types"; //Контроль свойств компонента
+import { List } from "@mui/material"; //Интерфейсные компоненты MUI
+import { APP_STYLES } from "../../../../../app.styles"; //Общие стили приложения
+import { Entity, ENTITY_VARIANT, ENTITY_BRIEF_SHAPE } from "../entity/entity"; //Сущности
+
+//---------
+//Константы
+//---------
+
+//Стили
+const STYLES = {
+ LIST: { height: "100%", width: "100%", bgcolor: "background.paper", overflowY: "auto", ...APP_STYLES.SCROLL }
+};
+
+//-----------
+//Тело модуля
+//-----------
+
+//Список сущностей
+const EntsList = ({ ents = [], onSelect = null } = {}) => {
+ //При нажатии на элемент списка
+ const handleItemClick = ent => onSelect && onSelect(ent);
+
+ //Формирование представления
+ return (
+
+ {ents && ents.map((ent, i) => )}
+
+ );
+};
+
+//Контроль свойств компонента - Список сущностей
+EntsList.propTypes = {
+ ents: PropTypes.arrayOf(ENTITY_BRIEF_SHAPE),
+ onSelect: PropTypes.func
+};
+
+//----------------
+//Интерфейс модуля
+//----------------
+
+export { EntsList };
diff --git a/app/panels/query_editor/components/inspector_query_ents/hooks.js b/app/panels/query_editor/components/inspector_query_ents/hooks.js
index 3a8f03d..58d8a17 100644
--- a/app/panels/query_editor/components/inspector_query_ents/hooks.js
+++ b/app/panels/query_editor/components/inspector_query_ents/hooks.js
@@ -7,7 +7,7 @@
//Подключение библиотек
//---------------------
-import { useContext, useCallback, useEffect, useState } from "react"; //Классы React
+import { useRef, useContext, useCallback, useEffect, useState } from "react"; //Классы React
import { BackEndСtx } from "../../../../context/backend"; //Контекст взаимодействия с сервером
import { object2Base64XML } from "../../../../core/utils"; //Вспомогательные функции
@@ -15,6 +15,69 @@ import { object2Base64XML } from "../../../../core/utils"; //Вспомогат
//Тело модуля
//-----------
+//Работа с сущностями системы
+const useEntities = (filter, minFilterLen) => {
+ //Контроллер для прерывания запросов
+ const abortController = useRef(null);
+
+ //Собственное состояние - флаг загрузки
+ const [isLoading, setLoading] = useState(false);
+
+ //Собственное состояние - флаг необходимости обновления
+ const [refresh, setRefresh] = useState(true);
+
+ //Собственное состояние - данные
+ const [data, setData] = useState(null);
+
+ //Подключение к контексту взаимодействия с сервером
+ const { executeStored } = useContext(BackEndСtx);
+
+ //Обновление данных
+ const doRefresh = () => setRefresh(true);
+
+ //При необходимости получить/обновить данные
+ useEffect(() => {
+ //Загрузка данных с сервера
+ const loadData = async () => {
+ try {
+ setLoading(true);
+ abortController.current?.abort?.();
+ abortController.current = new AbortController();
+ const data = await executeStored({
+ stored: "PKG_P8PANELS_QE.ENTITY_LIST",
+ args: { SSEARCH: filter },
+ respArg: "COUT",
+ isArray: name => ["XENT"].includes(name),
+ attributeValueProcessor: (name, val) => (["name", "title"].includes(name) ? undefined : val),
+ loader: false,
+ signal: abortController.current.signal
+ });
+ setData(data?.XENTS?.XENT || null);
+ } finally {
+ setRefresh(false);
+ setLoading(false);
+ }
+ };
+ //Если надо обновить
+ if (refresh) {
+ //Если фильтр задан и он нас удовлетворяет - получим данные
+ if (filter && String(filter).length >= minFilterLen) loadData();
+ //Нет фильтра - нет данных
+ else {
+ setData(null);
+ }
+ }
+ //Сбрасываем запрос при смене зависимостей или отмонтировании
+ return () => abortController.current?.abort?.();
+ }, [refresh, filter, minFilterLen, executeStored]);
+
+ //При изменении входных свойств - поднимаем флаг обновления
+ useEffect(() => setRefresh(true), [filter, minFilterLen]);
+
+ //Возвращаем интерфейс хука
+ return [data, doRefresh, isLoading];
+};
+
//Работа с сущностями запроса
const useQueryEntities = query => {
//Подключение к контексту взаимодействия с сервером
@@ -114,8 +177,27 @@ const useEntityAttrs = (query, entity) => {
return [data, setAttrs, doRefresh, isLoading];
};
+//Отложенное значение
+const useDebounce = (value, delay) => {
+ //Собственное состояние
+ const [debouncedValue, setDebouncedValue] = useState(value);
+
+ //При изменении интервала или значения
+ useEffect(() => {
+ //Взводим таймер
+ const handler = setTimeout(() => {
+ setDebouncedValue(value);
+ }, delay);
+ //Сбрасываем таймер при отмонтировании или изменении зависимостей
+ return () => clearTimeout(handler);
+ }, [value, delay]);
+
+ //Возвращаем отложенное значение
+ return debouncedValue;
+};
+
//----------------
//Интерфейс модуля
//----------------
-export { useQueryEntities, useEntityAttrs };
+export { useEntities, useQueryEntities, useEntityAttrs, useDebounce };
diff --git a/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js b/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js
index 0e0cea4..ec8d23f 100644
--- a/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js
+++ b/app/panels/query_editor/components/inspector_query_ents/inspector_query_ents.js
@@ -54,12 +54,12 @@ const InspectorQueryEntities = ({ query, entity, onOptionsChanged }) => {
}
});
- //Закрытие диалога добавления сущности по "Отмена"
- const handleEntityAddDialogCancel = () => setOpenEntityAddDialog(false);
+ //Закрытие диалога добавления сущности по "Закрыть"
+ const handleEntityAddDialogClose = () => setOpenEntityAddDialog(false);
- //Закрытие диалога добавления сущности по "ОК"
- const handleEntityAddDialogOk = async values => {
- await addEnt(values.name, "VIEW");
+ //Закрытие диалога добавления сущности по выбору сущности из списка
+ const handleEntityAddDialogSelect = async ent => {
+ await addEnt(ent.name, ent.type);
setOpenEntityAddDialog(false);
notifyOptionsChanged();
};
@@ -76,7 +76,7 @@ const InspectorQueryEntities = ({ query, entity, onOptionsChanged }) => {
//Формирование представления
return (
<>
- {openEntityAddDialog && }
+ {openEntityAddDialog && }
{openEntityAttrsDialog && (
)}
diff --git a/db/PKG_P8PANELS_QE.pck b/db/PKG_P8PANELS_QE.pck
index f05edf2..d4a0fc3 100644
--- a/db/PKG_P8PANELS_QE.pck
+++ b/db/PKG_P8PANELS_QE.pck
@@ -1,5 +1,12 @@
create or replace package PKG_P8PANELS_QE as
+ /* Получение списка доступных сущностей */
+ procedure ENTITY_LIST
+ (
+ SSEARCH in varchar2, -- Поисковый запрос
+ COUT out clob -- Сериализованный список доступных сущностей
+ );
+
/* Получение данных о запросе */
procedure QUERY
(
@@ -142,6 +149,24 @@ end PKG_P8PANELS_QE;
/
create or replace package body PKG_P8PANELS_QE as
+ /* Константы - Минимальная длина поисковой фразы для сущностей */
+ NENT_MIN_SEARCH_LEN constant PKG_STD.TNUMBER := 3; -- Количество символов
+
+ /* Получение списка доступных сущностей */
+ procedure ENTITY_LIST
+ (
+ SSEARCH in varchar2, -- Поисковый запрос
+ COUT out clob -- Сериализованный список доступных сущностей
+ )
+ is
+ begin
+ /* Если фильтр задан и он нас утраивает */
+ if ((SSEARCH is not null) and (LENGTH(SSEARCH) >= NENT_MIN_SEARCH_LEN)) then
+ /* Получим список доступных сущностей */
+ COUT := PKG_P8PANELS_QE_BASE.ENTITY_LIST(SSEARCH => SSEARCH, NBRIEF => 1, NINCLUDE_ATTRS => 0);
+ end if;
+ end ENTITY_LIST;
+
/* Получение описания запроса */
procedure QUERY
(
diff --git a/db/PKG_P8PANELS_QE_BASE.pck b/db/PKG_P8PANELS_QE_BASE.pck
index 7f2535c..514784e 100644
--- a/db/PKG_P8PANELS_QE_BASE.pck
+++ b/db/PKG_P8PANELS_QE_BASE.pck
@@ -62,6 +62,12 @@ create or replace package PKG_P8PANELS_QE_BASE as
/* Типы данных - Коллекция отношений */
type TRLS is table of TRL;
+ /* Получение заголовка представления из метаданных */
+ function DMSCLVIEWS_TITLE_GET
+ (
+ SVIEW_NAME in varchar2 -- Имя представления
+ ) return varchar2; -- Заголовок представления из метаданных
+
/* Десериализация коллекции атрибутов сущности (из BASE64) */
function TATTRS_FROM_XML_BASE64
(
@@ -117,7 +123,8 @@ create or replace package PKG_P8PANELS_QE_BASE as
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
- STYPE in varchar2 -- Тип (см. константы SENT_TYPE_*)
+ STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
+ NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
);
/* Удаление сущности из коллекции */
@@ -158,6 +165,14 @@ create or replace package PKG_P8PANELS_QE_BASE as
SATTR_ID in varchar2 -- Идентификатор атрибута
);
+ /* Формирование списка доступных сущностей */
+ function ENTITY_LIST
+ (
+ SSEARCH in varchar2, -- Поисковый запрос
+ NBRIEF in number, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
+ NINCLUDE_ATTRS in number -- Флаг включения в ответ атрибутов сущности (0 - нет, 1 - да)
+ ) return clob; -- Список сущностей
+
/* Считывание записи запроса */
function QUERY_GET
(
@@ -852,7 +867,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
return null;
end TATTRS_INDEX_BY_NAME;
- /* Формирование списка атрибутов сущности по типу и наименованию */
+ /* Формирование списка атрибутов сущности */
function TATTRS_MAKE
(
RENT in TENT, -- Родительская сущность
@@ -1055,7 +1070,8 @@ create or replace package body PKG_P8PANELS_QE_BASE as
(
SNAME in varchar2, -- Имя
STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
- NNUMB in number -- Номер сущности
+ NNUMB in number, -- Номер сущности
+ NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
) return TENT -- Описание сущности
is
RENT TENT; -- Буфер для результата
@@ -1080,7 +1096,11 @@ create or replace package body PKG_P8PANELS_QE_BASE as
RENT.STITLE := DMSCLVIEWS_TITLE_GET(SVIEW_NAME => RENT.SNAME);
RENT.STYPE := SENT_TYPE_VIEW;
/* Формируем набор атрибутов */
- RENT.RATTRS := TATTRS_MAKE(RENT => RENT, NCOUNT => 10);
+ if (NINIT_ATTRS = 1) then
+ RENT.RATTRS := TATTRS_MAKE(RENT => RENT, NCOUNT => 10);
+ else
+ RENT.RATTRS := TATTRS();
+ end if;
end if;
/* Если сущность это таблица */
if (STYPE = SENT_TYPE_TABLE) then
@@ -1094,21 +1114,27 @@ create or replace package body PKG_P8PANELS_QE_BASE as
/* Сериализация сущности */
procedure TENT_TO_XML
(
- RENT in TENT -- Сущность
+ RENT in TENT, -- Сущность
+ NBRIEF in number := 0, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
+ NINCLUDE_ATTRS in number := 1 -- Флаг включения атрибутов в описание (0 - нет, 1 - да)
)
is
begin
/* Открываем описание сущности */
PKG_XFAST.DOWN_NODE(SNAME => STAG_ENT);
/* Cущность */
- PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RENT.SID);
+ if (NBRIEF = 0) then
+ PKG_XFAST.ATTR(SNAME => SATTR_ID, SVALUE => RENT.SID);
+ PKG_XFAST.ATTR(SNAME => SATTR_X, NVALUE => RENT.NX);
+ PKG_XFAST.ATTR(SNAME => SATTR_Y, NVALUE => RENT.NY);
+ end if;
PKG_XFAST.ATTR(SNAME => SATTR_NAME, SVALUE => RENT.SNAME);
PKG_XFAST.ATTR(SNAME => SATTR_TITLE, SVALUE => RENT.STITLE);
PKG_XFAST.ATTR(SNAME => SATTR_TYPE, SVALUE => RENT.STYPE);
- PKG_XFAST.ATTR(SNAME => SATTR_X, NVALUE => RENT.NX);
- PKG_XFAST.ATTR(SNAME => SATTR_Y, NVALUE => RENT.NY);
/* Атрибуты */
- TATTRS_TO_XML(RATTRS => RENT.RATTRS);
+ if (NINCLUDE_ATTRS = 1) then
+ TATTRS_TO_XML(RATTRS => RENT.RATTRS);
+ end if;
/* Закрываем описание сущности */
PKG_XFAST.UP();
end TENT_TO_XML;
@@ -1209,7 +1235,8 @@ create or replace package body PKG_P8PANELS_QE_BASE as
(
RENTS in out nocopy TENTS, -- Изменяемая коллекция
SNAME in varchar2, -- Имя
- STYPE in varchar2 -- Тип (см. константы SENT_TYPE_*)
+ STYPE in varchar2, -- Тип (см. константы SENT_TYPE_*)
+ NINIT_ATTRS in number := 1 -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
)
is
RENT TENT; -- Добавляемая сущность
@@ -1219,7 +1246,10 @@ create or replace package body PKG_P8PANELS_QE_BASE as
RENTS := TENTS();
end if;
/* Формируем пописание сущности */
- RENT := TENT_MAKE(SNAME => SNAME, STYPE => STYPE, NNUMB => TENTS_NEXT_NUMB(RENTS => RENTS, SNAME => SNAME));
+ RENT := TENT_MAKE(SNAME => SNAME,
+ STYPE => STYPE,
+ NNUMB => TENTS_NEXT_NUMB(RENTS => RENTS, SNAME => SNAME),
+ NINIT_ATTRS => NINIT_ATTRS);
/* Добавляем её в коллекцию */
RENTS.EXTEND();
RENTS(RENTS.LAST) := RENT;
@@ -1260,10 +1290,45 @@ create or replace package body PKG_P8PANELS_QE_BASE as
end if;
end TENTS_POSITION_SET;
+ /* Формирование списка сущностей */
+ function TENTS_MAKE
+ (
+ SSEARCH in varchar2, -- Поисковый запрос
+ NINIT_ATTRS in number -- Флаг инициализации атрибутов сущности (0 - нет, 1 - да)
+ ) return TENTS -- Коллекция сущностей
+ is
+ RRES TENTS; -- Буфер для результата
+ SSEARCH_ PKG_STD.TSTRING; -- Строка поиска, предобразованная для применения в запросе
+ begin
+ /* Инициализируем результат */
+ RRES := TENTS();
+ /* Формируем список представлений */
+ PKG_OBJECT_DESC.SNAP_VIEWS(NACCESS_TYPE => 1);
+ /* Подготовим поисковую фразу */
+ if (SSEARCH is not null) then
+ SSEARCH_ := '%' || LOWER(replace(SSEARCH, ' ', '%')) || '%';
+ else
+ SSEARCH_ := null;
+ end if;
+ /* Обходим полученный список */
+ for C in (select T.VIEW_NAME
+ from SNAP_VIEWS T
+ where ((SSEARCH_ is null) or ((SSEARCH_ is not null) and ((LOWER(T.VIEW_NAME) like SSEARCH_) or (LOWER(DMSCLVIEWS_TITLE_GET(T.VIEW_NAME)) like
+ SSEARCH_)))))
+ loop
+ /* Добавляем представления в коллекцию */
+ TENTS_ADD(RENTS => RRES, SNAME => C.VIEW_NAME, STYPE => SENT_TYPE_VIEW, NINIT_ATTRS => NINIT_ATTRS);
+ end loop;
+ /* Вернём полученный список */
+ return RRES;
+ end TENTS_MAKE;
+
/* Сериализация коллекции сущностей */
procedure TENTS_TO_XML
(
- RENTS in TENTS -- Коллекция сущностей
+ RENTS in TENTS, -- Коллекция сущностей
+ NBRIEF in number := 0, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
+ NINCLUDE_ATTRS in number := 1 -- Флаг включения атрибутов в описание (0 - нет, 1 - да)
)
is
begin
@@ -1275,7 +1340,7 @@ create or replace package body PKG_P8PANELS_QE_BASE as
loop
begin
/* Добавляем описание сущности */
- TENT_TO_XML(RENT => RENTS(I));
+ TENT_TO_XML(RENT => RENTS(I), NBRIEF => NBRIEF, NINCLUDE_ATTRS => NINCLUDE_ATTRS);
exception
when NO_DATA_FOUND then
null;
@@ -1620,6 +1685,41 @@ create or replace package body PKG_P8PANELS_QE_BASE as
return RRES;
end TRLS_FROM_XML;
+ /* Формирование списка доступных сущностей */
+ function ENTITY_LIST
+ (
+ SSEARCH in varchar2, -- Поисковый запрос
+ NBRIEF in number, -- Флаг формирования описания сущности в кратком формате (0 - нет, 1 - да)
+ NINCLUDE_ATTRS in number -- Флаг включения в ответ атрибутов сущности (0 - нет, 1 - да)
+ ) return clob -- Список сущностей
+ is
+ CRES clob; -- Буфер для сериализации
+ begin
+ /* Начинаем формирование XML */
+ PKG_XFAST.PROLOGUE(ITYPE => PKG_XFAST.CONTENT_, BALINE => true, BINDENT => true);
+ /* Открываем корень */
+ PKG_XFAST.DOWN_NODE(SNAME => STAG_DATA);
+ /* Строим и сериализуем список доступных сущностей */
+ TENTS_TO_XML(RENTS => TENTS_MAKE(SSEARCH => SSEARCH, NINIT_ATTRS => NINCLUDE_ATTRS),
+ NBRIEF => NBRIEF,
+ NINCLUDE_ATTRS => NINCLUDE_ATTRS);
+ /* Закрываем корень */
+ PKG_XFAST.UP();
+ /* Сериализуем */
+ CRES := PKG_XFAST.SERIALIZE_TO_CLOB();
+ /* Завершаем формирование XML */
+ PKG_XFAST.EPILOGUE();
+ /* Возвращаем результат */
+ return CRES;
+ exception
+ when others then
+ /* Завершаем формирование XML */
+ PKG_XFAST.EPILOGUE();
+ /* Вернем ошибку */
+ PKG_STATE.DIAGNOSTICS_STACKED();
+ P_EXCEPTION(0, PKG_STATE.SQL_ERRM());
+ end ENTITY_LIST;
+
/* Считывание записи запроса */
function QUERY_GET
(