1
0
mirror of https://github.com/1C-Company/v8-code-style.git synced 2024-11-28 09:33:06 +02:00

#822 Отбор виртуальных таблиц в параметрах (#838)

This commit is contained in:
Dmitriy Marmyshev 2021-10-13 21:09:31 +03:00 committed by GitHub
parent 85ad9ae05d
commit f55976e338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1360 additions and 48 deletions

View File

@ -61,6 +61,7 @@
- Строковый литерал должен содержать CamelCase
- Соединение с подзапросом
- Использование конструкции "ДЛЯ ИЗМЕНЕНИЯ"
- Отбор виртуальной таблицы должен быть в параметрах
#### Права ролей

View File

@ -6,7 +6,8 @@ Bundle-Version: 0.1.0.qualifier
Bundle-Activator: com.e1c.v8codestyle.internal.ql.CorePlugin
Bundle-Vendor: %providerName
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.18.0,4.0.0)",
org.eclipse.emf.ecore;bundle-version="[2.22.0,3.0.0)"
org.eclipse.emf.ecore;bundle-version="[2.22.0,3.0.0)",
org.eclipse.xtext;bundle-version="[2.24.0,3.0.0)"
Bundle-RequiredExecutionEnvironment: JavaSE-11
Automatic-Module-Name: com.e1c.v8codestyle.ql
Bundle-ActivationPolicy: lazy
@ -14,8 +15,11 @@ Bundle-Localization: plugin
Import-Package: com._1c.g5.v8.bm.core;version="[7.0.0,8.0.0)",
com._1c.g5.v8.dt.common;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.core.platform;version="[10.4.0,11.0.0)",
com._1c.g5.v8.dt.mcore;version="[6.0.0,7.0.0)",
com._1c.g5.v8.dt.metadata.dbview;version="4.0.0",
com._1c.g5.v8.dt.metadata.mdclass;version="[8.0.0,9.0.0)",
com._1c.g5.v8.dt.ql.model;version="[4.0.0,5.0.0)",
com._1c.g5.v8.dt.ql.typesystem;version="5.0.0",
com._1c.g5.wiring;version="[2.2.0,3.0.0)",
com._1c.g5.wiring.binder;version="[1.1.0,2.0.0)",
com.e1c.g5.v8.dt.check;version="[1.0.0,2.0.0)",

View File

@ -0,0 +1,38 @@
# Virtual table filters should be in parameters
If you use virtual tables in queries, pass all conditions related to this virtual table to the table parameters. We do not recommended that you access virtual tables using conditions of WHERE clause, and other.
Such query returns a correct result but it is more difficult for DBMS to select an optimum method to execute that query. In some cases, it can cause DBMS optimizer errors and considerably slow down the query execution.
## Noncompliant Code Example
For example, the following query uses the WHERE section to select data from a virtual table:
```bsl
Query.Text= "SELECT
| Products
|FROM
| AccumulationRegister.Stock.Balance()
|WHERE
| Warehouse = &Warehouse";
```
Upon executing this query, all records of a virtual table are selected. Then only those that meet the specified condition are sampled.
## Compliant Solution
We recommend that you restrict the number of records to be selected at a very early stage of query processing. To do so, pass conditions to virtual table parameters.
```bsl
Query.Text= "SELECT
| Products
|FROM
| AccumulationRegister.Stock.Balance(, Warehouse = &Warehouse)";
```
## See
- [Accessing virtual table](https://support.1ci.com/hc/en-us/articles/360011121039-Accessing-virtual-table)
- [Using filters in queries with virtual tables](https://1c-dn.com/library/using_filters_in_queries_with_virtual_tables/)
- [Virtual table parameters](https://1c-dn.com/library/tutorials/practical_developer_guide_virtual_table_parameters3/)

View File

@ -0,0 +1,39 @@
# Отбор виртуальной таблицы должен быть в параметрах
При использовании виртуальных таблиц в запросах, следует передавать в параметры таблиц все условия, относящиеся к данной виртуальной таблице. Не рекомендуется обращаться к виртуальным таблицам при помощи условий в секции ГДЕ и т.п.
Такой запрос будет возвращать правильный (с точки зрения функциональности) результат, но СУБД будет намного сложнее выбрать оптимальный план для его выполнения. В некоторых случаях это может привести к ошибкам оптимизатора СУБД и значительному замедлению работы запроса.
## Неправильно
Например, следующий запрос использует секцию ГДЕ запроса для выборки из виртуальной таблицы:
```bsl
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки()
|ГДЕ
| Склад = &Склад";
```
Возможно, что в результате выполнения этого запроса сначала будут выбраны все записи виртуальной таблицы, а затем из них будет отобрана часть, соответствующая заданному условию.
## Правильно
Рекомендуется ограничивать количество выбираемых записей на самом раннем этапе обработки запроса. Для этого следует передать условия в параметры виртуальной таблицы.
```bsl
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад)";
```
## См.
- [Обращения к виртуальным таблицам](https://its.1c.ru/db/v8std#content:657:hdoc)

View File

@ -42,6 +42,10 @@
category="com.e1c.v8codestyle.ql"
class="com.e1c.v8codestyle.internal.ql.ExecutableExtensionFactory:com.e1c.v8codestyle.ql.check.UsingForUpdateCheck">
</check>
<check
category="com.e1c.v8codestyle.ql"
class="com.e1c.v8codestyle.internal.ql.ExecutableExtensionFactory:com.e1c.v8codestyle.ql.check.VirtualTableFiltersCheck">
</check>
</extension>
</plugin>

View File

@ -131,7 +131,7 @@ public class CorePlugin
*
* @return Guice injector for this plugin, never <code>null</code>
*/
/* package */ Injector getInjector()
public Injector getInjector()
{
Injector localInstance = injector;
if (localInstance == null)

View File

@ -44,6 +44,9 @@ final class Messages
public static String TempTableHasIndex_title;
public static String UsingForUpdateCheck_description;
public static String UsingForUpdateCheck_title;
public static String VirtualTableFiltersCheck_description;
public static String VirtualTableFiltersCheck_Filter__0_for_virtual_table__1__should_be_in_parameters;
public static String VirtualTableFiltersCheck_title;
static
{
// initialize resource bundle

View File

@ -0,0 +1,165 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.ql.check;
import static com._1c.g5.v8.dt.ql.model.QlPackage.Literals.MULTI_PART_COMMON_EXPRESSION__SOURCE_TABLE;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.IResourceServiceProvider;
import com._1c.g5.v8.dt.metadata.dbview.DbViewElement;
import com._1c.g5.v8.dt.metadata.dbview.DbViewSelectDef;
import com._1c.g5.v8.dt.metadata.mdclass.RegisterDimension;
import com._1c.g5.v8.dt.ql.model.AbstractQuerySchemaTable;
import com._1c.g5.v8.dt.ql.model.CommonExpression;
import com._1c.g5.v8.dt.ql.model.MultiPartCommonExpression;
import com._1c.g5.v8.dt.ql.model.QuerySchemaExpression;
import com._1c.g5.v8.dt.ql.model.QuerySchemaOperator;
import com._1c.g5.v8.dt.ql.model.QuerySchemaTable;
import com._1c.g5.v8.dt.ql.typesystem.IDynamicDbViewFieldComputer;
import com.e1c.g5.v8.dt.check.CheckComplexity;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
import com.e1c.g5.v8.dt.check.settings.IssueType;
import com.e1c.g5.v8.dt.ql.check.QlBasicDelegateCheck;
import com.e1c.v8codestyle.internal.ql.CorePlugin;
/**
* Checks that all dimensions of virtual table placed in parameters instead of filter.
*
* @author Dmitriy Marmyshev
*/
public class VirtualTableFiltersCheck
extends QlBasicDelegateCheck
{
private static final String CHECK_ID = "ql-virtual-table-filters"; //$NON-NLS-1$
private final IDynamicDbViewFieldComputer dynamicDbViewFieldComputer;
public VirtualTableFiltersCheck()
{
super();
IResourceServiceProvider rsp =
IResourceServiceProvider.Registry.INSTANCE.getResourceServiceProvider(URI.createURI("*.qldcs")); //$NON-NLS-1$
this.dynamicDbViewFieldComputer = rsp.get(IDynamicDbViewFieldComputer.class);
}
@Override
public String getCheckId()
{
return CHECK_ID;
}
@Override
protected void configureCheck(CheckConfigurer builder)
{
builder.title(Messages.VirtualTableFiltersCheck_title)
.description(Messages.VirtualTableFiltersCheck_description)
.complexity(CheckComplexity.NORMAL)
.severity(IssueSeverity.MAJOR)
.issueType(IssueType.PERFORMANCE)
.delegate(QuerySchemaTable.class);
}
@Override
protected void checkQlObject(EObject object, QueryOwner owner, IQlResultAcceptor resultAceptor,
ICheckParameters parameters, IProgressMonitor monitor)
{
QuerySchemaTable sourceTable = (QuerySchemaTable)object;
if (!isVirtualTableWithParameters(sourceTable.getTable()))
{
return;
}
QuerySchemaOperator operator = EcoreUtil2.getContainerOfType(sourceTable, QuerySchemaOperator.class);
if (monitor.isCanceled() || operator == null || operator.getFilters() == null)
{
return;
}
QuerySchemaExpression filters = operator.getFilters();
String alias = sourceTable.getAlias();
alias = alias + "."; //$NON-NLS-1$
List<MultiPartCommonExpression> filterItems = new ArrayList<>();
for (TreeIterator<EObject> iterator = filters.eAllContents(); iterator.hasNext();)
{
EObject filter = iterator.next();
if (monitor.isCanceled())
{
return;
}
if (filter instanceof MultiPartCommonExpression
&& ((MultiPartCommonExpression)filter).getFullContent().startsWith(alias)
&& isDimension((MultiPartCommonExpression)filter))
{
filterItems.add((MultiPartCommonExpression)filter);
}
}
for (MultiPartCommonExpression item : filterItems)
{
String message = MessageFormat.format(
Messages.VirtualTableFiltersCheck_Filter__0_for_virtual_table__1__should_be_in_parameters,
item.getFullContent(), sourceTable.getAlias());
resultAceptor.addIssue(message, item, MULTI_PART_COMMON_EXPRESSION__SOURCE_TABLE);
}
}
private boolean isVirtualTableWithParameters(AbstractQuerySchemaTable table)
{
try
{
DbViewElement dbView = dynamicDbViewFieldComputer.computeDbView(table);
if (dbView instanceof DbViewSelectDef)
{
DbViewSelectDef virtualTable = (DbViewSelectDef)dbView;
return !virtualTable.getParams().isEmpty();
}
}
catch (Exception e)
{
// Log in case model is damaged
CorePlugin.logError(e);
}
return false;
}
private boolean isDimension(CommonExpression object)
{
try
{
DbViewElement dbView = dynamicDbViewFieldComputer.computeDbView(object);
return dbView.getMdObject() instanceof RegisterDimension;
}
catch (Exception e)
{
// Log in case model is damaged
CorePlugin.logError(e);
}
return false;
}
}

View File

@ -1,3 +1,4 @@
#Generated by ResourceBundle Editor (http://essiembre.github.io/eclipse-rbe/)
###############################################################################
# Copyright (C) 2021, 1C-Soft LLC and others.
#
@ -10,22 +11,47 @@
# Contributors:
# 1C-Soft LLC - initial API and implementation
###############################################################################
CamelCaseStringLiteral_description=Query string literal contains non CamelCase content
CamelCaseStringLiteral_Regular_expression_to_skip_literal_content=Regular expression to skip literal content
CamelCaseStringLiteral_String_literal_contains_non_CamelCase_symbols__0=String literal contains non CamelCase symbols: "{0}"
CamelCaseStringLiteral_title=Query string literal contains non CamelCase content
CastToMaxNumber_description=Query cast to max number
CastToMaxNumber_Maximum_cast_number_length=Maximum cast number length
CastToMaxNumber_Maximum_cast_number_precision_or_N_to_skip_check=Maximum cast number precision, or -1 to skip check
CastToMaxNumber_Query_cast_to_number_with_lenth__0__and_max_allowed__1=Query cast to number with lenth {0} and max allowed {1}
CastToMaxNumber_Query_cast_to_number_with_precision__0__and_max_allowed__1=Query cast to number with precision {0} and max allowed {1}
CastToMaxNumber_title=Query cast to max number
JoinToSubQuery_description=Query join with sub query
JoinToSubQuery_Query_join_to_sub_query_not_allowed=Query join to sub query not allowed
JoinToSubQuery_title=Query join with sub query
TempTableHasIndex_description=Temporary table should have indexes
TempTableHasIndex_Exclude_table_name_pattern=Exclude table name pattern
TempTableHasIndex_New_temporary_table_should_have_indexes=New temporary table should have indexes
TempTableHasIndex_title=Temporary table should have indexes
UsingForUpdateCheck_description=Check if query contains "FOR UPDATE"
UsingForUpdateCheck_title=Using "FOR UPDATE" clause
CamelCaseStringLiteral_Regular_expression_to_skip_literal_content = Regular expression to skip literal content
CamelCaseStringLiteral_String_literal_contains_non_CamelCase_symbols__0 = String literal contains non CamelCase symbols: "{0}"
CamelCaseStringLiteral_description = Query string literal contains non CamelCase content
CamelCaseStringLiteral_title = Query string literal contains non CamelCase content
CastToMaxNumber_Maximum_cast_number_length = Maximum cast number length
CastToMaxNumber_Maximum_cast_number_precision_or_N_to_skip_check = Maximum cast number precision, or -1 to skip check
CastToMaxNumber_Query_cast_to_number_with_lenth__0__and_max_allowed__1 = Query cast to number with lenth {0} and max allowed {1}
CastToMaxNumber_Query_cast_to_number_with_precision__0__and_max_allowed__1 = Query cast to number with precision {0} and max allowed {1}
CastToMaxNumber_description = Query cast to max number
CastToMaxNumber_title = Query cast to max number
JoinToSubQuery_Query_join_to_sub_query_not_allowed = Query join to sub query not allowed
JoinToSubQuery_description = Query join with sub query
JoinToSubQuery_title = Query join with sub query
TempTableHasIndex_Exclude_table_name_pattern = Exclude table name pattern
TempTableHasIndex_New_temporary_table_should_have_indexes = New temporary table should have indexes
TempTableHasIndex_description = Temporary table should have indexes
TempTableHasIndex_title = Temporary table should have indexes
UsingForUpdateCheck_description = Check if query contains "FOR UPDATE"
UsingForUpdateCheck_title = Using "FOR UPDATE" clause
VirtualTableFiltersCheck_Filter__0_for_virtual_table__1__should_be_in_parameters = Filter {0} for virtual table {1} should be in parameters
VirtualTableFiltersCheck_description = Virtual table filters should be in parameters
VirtualTableFiltersCheck_title = Virtual table filters should be in parameters

View File

@ -50,3 +50,9 @@ TempTableHasIndex_title = Временная таблица должна сод
UsingForUpdateCheck_description = Проверка наличия конструкции "ДЛЯ ИЗМЕНЕНИЯ" в запросе
UsingForUpdateCheck_title = Использование конструкции "ДЛЯ ИЗМЕНЕНИЯ"
VirtualTableFiltersCheck_Filter__0_for_virtual_table__1__should_be_in_parameters = Отбор {0} для виртуальной таблицы {1} должен быть в параметрах
VirtualTableFiltersCheck_description = Отбор виртуальной таблицы должен быть в параметрах
VirtualTableFiltersCheck_title = Отбор виртуальной таблицы должен быть в параметрах

View File

@ -0,0 +1,11 @@
SELECT
StocksBalanceAndTurnovers.Product,
StocksBalanceAndTurnovers.Warehouse,
StocksBalanceAndTurnovers.QuntityExpense,
StocksBalanceAndTurnovers.AmountExpense,
StocksBalanceAndTurnovers.AmountTurnover
FROM
AccumulationRegister.Stocks.BalanceAndTurnovers(,,,, Warehouse <> ""
AND Product.ProductType = VALUE(Enum.ProductType.Service)) AS StocksBalanceAndTurnovers
WHERE
StocksBalanceAndTurnovers.AmountTurnover > 100

View File

@ -0,0 +1,12 @@
SELECT
StocksBalanceAndTurnovers.Product,
StocksBalanceAndTurnovers.Warehouse,
StocksBalanceAndTurnovers.QuntityExpense,
StocksBalanceAndTurnovers.AmountExpense,
StocksBalanceAndTurnovers.AmountTurnover
FROM
AccumulationRegister.Stocks.BalanceAndTurnovers AS StocksBalanceAndTurnovers
WHERE
StocksBalanceAndTurnovers.Warehouse <> ""
AND StocksBalanceAndTurnovers.Product.ProductType = VALUE(Enum.ProductType.Service)
AND StocksBalanceAndTurnovers.AmountTurnover > 100

View File

@ -0,0 +1,331 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.ql.check.itests;
import static org.junit.Assert.assertNotNull;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EObject;
import org.junit.Before;
import org.junit.Ignore;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import com._1c.g5.v8.dt.core.platform.IDtProject;
import com._1c.g5.v8.dt.dcs.util.DcsUtil;
import com._1c.g5.v8.dt.ql.model.QuerySchema;
import com.e1c.g5.v8.dt.check.ICheck;
import com.e1c.g5.v8.dt.check.ICheckDefinition;
import com.e1c.g5.v8.dt.check.ICheckParameters;
import com.e1c.g5.v8.dt.check.IDelegateApplicabilityFilter;
import com.e1c.g5.v8.dt.check.settings.CheckUid;
import com.e1c.g5.v8.dt.check.settings.ICheckParameterSettings;
import com.e1c.g5.v8.dt.check.settings.ICheckSettings;
import com.e1c.g5.v8.dt.ql.check.QlBasicDelegateCheck;
import com.e1c.g5.v8.dt.ql.check.QlBasicDelegateCheck.QueryOwner;
import com.e1c.g5.v8.dt.testing.check.CheckTestBase;
import com.e1c.v8codestyle.internal.ql.CorePlugin;
import com.e1c.v8codestyle.ql.check.itests.TestingQlResultAcceptor.QueryMarker;
/**
* The abstract query schema test base.
* Allows to load and validate query schema model from bundle resource file.
*
* @author Dmitriy Marmyshev
*/
@Ignore
public class AbstractQueryTestBase
extends CheckTestBase
{
private static final String PROJECT_NAME = "QlEmptyProject";
protected static final String FOLDER_RESOURCE = "/resources/";
private IDtProject dtProject;
private Class<? extends ICheck> checkClass;
private ICheck check;
private ICheckDefinition definition;
private TestingCheckResultAcceptor resultAcceptor;
private TestingQlResultAcceptor qlResultAcceptor;
/**
* Instantiates a new abstract query test base.
*
* @param checkClass the check class
*/
protected AbstractQueryTestBase(Class<? extends ICheck> checkClass)
{
super();
this.checkClass = checkClass;
}
@Override
protected boolean enableCleanUp()
{
return false;
}
/**
* Gets the DT project instance.
*
* @return the project, cannot return {@code null}.
*/
protected IDtProject getProject()
{
return dtProject;
}
/**
* Sets the up of the abstract check. It is forbidden for clients to override this method.
*
* @throws Exception the exception
*/
@Before
public void setUp() throws Exception
{
IProject project = testingWorkspace.getProject(getTestConfigurationName());
if (!project.exists() || !project.isAccessible())
{
testingWorkspace.cleanUpWorkspace();
dtProject = openProjectAndWaitForValidationFinish(getTestConfigurationName());
}
dtProject = dtProjectManager.getDtProject(project);
setCheckEnable(true);
resultAcceptor = new TestingCheckResultAcceptor();
qlResultAcceptor = new TestingQlResultAcceptor();
QlBasicDelegateCheck.setResultAcceptor((o, f) -> qlResultAcceptor);
}
/**
* Sets the check enable or disable.
*
* @param enable the new check enable
*/
private void setCheckEnable(boolean enable) throws Exception
{
IProject project = getProject().getWorkspaceProject();
CheckUid cuid = new CheckUid(getCheckId(), CorePlugin.PLUGIN_ID);
ICheckSettings settings = checkRepository.getSettings(cuid, project);
if (settings.isEnabled() != enable)
{
settings.setEnabled(enable);
checkRepository.applyChanges(Collections.singleton(settings), project);
waitForDD(getProject());
}
}
/**
* Gets the test configuration name, the project name.
*
* @return the test configuration name, cannot return {@code null}.
*/
protected String getTestConfigurationName()
{
return PROJECT_NAME;
}
/**
* Gets the check instance created in BSL bundle.
*
* @return the check instance, cannot return {@code null}.
*/
private ICheck getCheckInstance() throws Exception
{
if (check == null)
{
check = CorePlugin.getDefault().getInjector().getInstance(checkClass);
definition = createCheckDefinition();
assertNotNull(definition);
check.configureContextCollector(definition);
}
return check;
}
/**
* Gets the check id gets from the check instance.
*
* @return the check id, cannot return {@code null}.
*/
private String getCheckId() throws Exception
{
return getCheckInstance().getCheckId();
}
/**
* Load query from bundle resource and validate it.
*
* @param resourcePath the resource path, cannot be {@code null}.
* @return the query schema, cannot return {@code null}.
* @throws Exception the exception if cannot load query model
*/
protected QuerySchema loadQueryAndValidate(String resourcePath) throws Exception
{
String queryText =
new String(getClass().getResourceAsStream(resourcePath).readAllBytes(), StandardCharsets.UTF_8);
QuerySchema querySchema = DcsUtil.getQuerySchema(queryText, getProject());
assertNotNull(querySchema);
validateQuery(querySchema);
return querySchema;
}
/**
* Validate query and collect the errors.
*
* @param querySchema the query schema, cannot be {@code null}.
* @throws Exception the exception
*
* @see #getQueryMarkers() to get error markers
*/
private void validateQuery(QuerySchema querySchema) throws Exception
{
QlBasicDelegateCheck.setOwner(new QueryOwner(querySchema, null));
ICheckParameters checkParametes = getCheckParameters();
ICheck validator = getCheckInstance();
if (!(validator instanceof QlBasicDelegateCheck))
{
throw new IllegalStateException("Check should be QlBasicDelegateCheck class, but was: " + validator);
}
IDelegateApplicabilityFilter filter = getDelegateFilter();
assertNotNull(filter);
IProgressMonitor monitor = new NullProgressMonitor();
for (TreeIterator<EObject> iterator = querySchema.eAllContents(); iterator.hasNext();)
{
EObject child = iterator.next();
if (filter.isApplicable(child))
{
validator.check(child, resultAcceptor, checkParametes, monitor);
}
}
}
/**
* Gets the query markers: error message, the QL object, it's feature and position in text.
*
* @return the query markers, cannot return {@code null}.
*/
protected List<QueryMarker> getQueryMarkers()
{
return qlResultAcceptor.getMarkers();
}
private ICheckDefinition createCheckDefinition() throws Exception
{
String fullCalss = "com.e1c.g5.v8.dt.internal.check.derived.CheckDefinition";
Bundle current = FrameworkUtil.getBundle(getClass());
for (Bundle bundle : current.getBundleContext().getBundles())
{
if ("com.e1c.g5.v8.dt.check".equals(bundle.getSymbolicName()))
{
Class<?> clazz = bundle.loadClass(fullCalss);
Constructor<?> c = clazz.getConstructor();
return (ICheckDefinition)c.newInstance();
}
}
return null;
}
private IDelegateApplicabilityFilter getDelegateFilter() throws Exception
{
if (definition == null)
{
getCheckInstance();
}
Method method = definition.getClass().getMethod("getDelegateApplicabilityFilter");
IDelegateApplicabilityFilter filter = (IDelegateApplicabilityFilter)method.invoke(definition);
method = definition.getClass().getMethod("getSupportedDelegateTypes");
@SuppressWarnings("unchecked")
Set<Class<?>> delegateClasses = (Set<Class<?>>)method.invoke(definition);
return object -> {
if (filter != null && !filter.isApplicable(filter))
{
return false;
}
for (Class<?> delegate : delegateClasses)
{
if (delegate.isInstance(object))
{
return true;
}
}
return false;
};
}
private ICheckParameters getCheckParameters() throws Exception
{
IProject project = getProject().getWorkspaceProject();
CheckUid cuid = new CheckUid(getCheckId(), CorePlugin.PLUGIN_ID);
ICheckSettings settings = checkRepository.getSettings(cuid, project);
Map<String, Object> values = settings.getParameters()
.entrySet()
.stream()
.collect(Collectors.toMap(Entry::getKey, e -> getParameterObject(e.getValue())));
return new TestingCheckParameters(values);
}
private Object getParameterObject(ICheckParameterSettings parameter)
{
Class<?> type = parameter.getType();
String value = parameter.getValue();
if (type == Integer.class)
{
return Integer.valueOf(value);
}
else if (type == Boolean.class)
{
return Boolean.valueOf(value);
}
else if (type == Double.class)
{
return Double.valueOf(value);
}
else if (type == Long.class)
{
return Long.valueOf(value);
}
return value;
}
}

View File

@ -92,15 +92,13 @@ public class TempTableHasIndexTest
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertTrue(qlResultAcceptor.featuredMessages.isEmpty());
assertTrue(qlResultAcceptor.getMarkers().isEmpty());
selectQuery = querySchema.getQueries().get(0);
assertTrue(selectQuery instanceof QuerySchemaSelectQuery);
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertFalse(qlResultAcceptor.featuredMessages.isEmpty());
assertFalse(qlResultAcceptor.getMarkers().isEmpty());
}
@ -123,15 +121,13 @@ public class TempTableHasIndexTest
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertTrue(qlResultAcceptor.featuredMessages.isEmpty());
assertTrue(qlResultAcceptor.getMarkers().isEmpty());
selectQuery = querySchema.getQueries().get(0);
assertTrue(selectQuery instanceof QuerySchemaSelectQuery);
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertFalse(qlResultAcceptor.featuredMessages.isEmpty());
assertFalse(qlResultAcceptor.getMarkers().isEmpty());
}
@ -153,15 +149,13 @@ public class TempTableHasIndexTest
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertTrue(qlResultAcceptor.featuredMessages.isEmpty());
assertTrue(qlResultAcceptor.getMarkers().isEmpty());
selectQuery = querySchema.getQueries().get(0);
assertTrue(selectQuery instanceof QuerySchemaSelectQuery);
check.check(selectQuery, resultAcceptor, emptyParameters, new NullProgressMonitor());
assertTrue(qlResultAcceptor.messages.isEmpty());
assertTrue(qlResultAcceptor.featuredMessages.isEmpty());
assertTrue(qlResultAcceptor.getMarkers().isEmpty());
}
}

View File

@ -10,9 +10,6 @@
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
/**
*
*/
package com.e1c.v8codestyle.ql.check.itests;
import java.util.ArrayList;
@ -20,52 +17,182 @@ import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.xtext.util.Triple;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.nodemodel.INode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import com.e1c.g5.v8.dt.ql.check.QlBasicDelegateCheck.IQlResultAcceptor;
/**
* @author Dmitriy Marmyshev
* Testing result acceptor implementation for QL check tests.
*
* @author Dmitriy Marmyshev
*/
class TestingQlResultAcceptor
implements IQlResultAcceptor
{
final List<String> messages = new ArrayList<>();
final List<Triple<String, EObject, EStructuralFeature>> featuredMessages = new ArrayList<>();
private final List<QueryMarker> markers = new ArrayList<>();
@Override
public void addIssue(String message)
{
messages.add(message);
markers.add(new QueryMarker(message));
}
@Override
public void addIssue(String message, EObject target, EStructuralFeature feature)
{
featuredMessages.add(Tuples.create(message, target, feature));
markers.add(new QueryMarker(message, target, feature));
}
@Override
public void addIssue(String message, EObject target, EStructuralFeature manyFeature, int index)
{
featuredMessages.add(Tuples.create(message, target, manyFeature));
markers.add(new QueryMarker(message, target, manyFeature, index));
}
@Override
public void addIssue(String message, int length)
{
messages.add(message);
markers.add(new QueryMarker(message));
}
@Override
public void addIssue(String message, int lineNumber, int offset, int length)
{
messages.add(message);
markers.add(new QueryMarker(message, lineNumber, offset, length));
}
public List<QueryMarker> getMarkers()
{
return markers;
}
public final class QueryMarker
{
private final String message;
private final int lineNumber;
private final int offset;
private final int length;
private final EObject target;
private final EStructuralFeature feature;
private final int index;
private QueryMarker(String message)
{
this.message = message;
this.lineNumber = -1;
this.offset = -1;
this.length = -1;
this.target = null;
this.feature = null;
this.index = -1;
}
private QueryMarker(String message, int lineNumber, int offset, int length)
{
this.message = message;
this.lineNumber = lineNumber;
this.offset = offset;
this.length = length;
this.target = null;
this.feature = null;
this.index = -1;
}
private QueryMarker(String message, EObject target)
{
this(message, target, null, -1);
}
private QueryMarker(String message, EObject target, EStructuralFeature feature)
{
this(message, target, feature, -1);
}
private QueryMarker(String message, EObject target, EStructuralFeature manyFeature, int index)
{
this.message = message;
this.target = target;
this.feature = manyFeature;
this.index = index;
INode node = null;
if (feature == null)
{
node = NodeModelUtils.findActualNodeFor(target);
}
else
{
List<INode> nodes = NodeModelUtils.findNodesForFeature(target, manyFeature);
if (!nodes.isEmpty() && index > -1 && index < nodes.size())
{
node = nodes.get(index);
}
else if (!nodes.isEmpty())
{
node = nodes.get(0);
}
}
if (node == null)
{
this.lineNumber = -1;
this.offset = -1;
this.length = -1;
}
else
{
this.lineNumber = NodeModelUtils.getLineAndColumn(node.getRootNode(), node.getOffset()).getLine();
this.offset = node.getOffset();
this.length = node.getLength();
}
}
public String getMessage()
{
return message;
}
public EObject getTarget()
{
return target;
}
public EStructuralFeature getFeature()
{
return feature;
}
public int getFeatureIndex()
{
return index;
}
public int getLineNumber()
{
return lineNumber;
}
public int getOffset()
{
return offset;
}
public int getLength()
{
return length;
}
}
}

View File

@ -0,0 +1,80 @@
/*******************************************************************************
* Copyright (C) 2021, 1C-Soft LLC and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* 1C-Soft LLC - initial API and implementation
*******************************************************************************/
package com.e1c.v8codestyle.ql.check.itests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import org.junit.Test;
import com.e1c.v8codestyle.ql.check.VirtualTableFiltersCheck;
import com.e1c.v8codestyle.ql.check.itests.TestingQlResultAcceptor.QueryMarker;
/**
* The test for {@link VirtualTableFiltersCheck} check
*
* @author Dmitriy Marmyshev
*/
public class VirtualTableFiltersCheckTest
extends AbstractQueryTestBase
{
private static final String PROJECT_NAME = "QlFullDemo";
public VirtualTableFiltersCheckTest()
{
super(VirtualTableFiltersCheck.class);
}
@Override
protected String getTestConfigurationName()
{
return PROJECT_NAME;
}
/**
* Test virtual table dimension in filters that is non-compliant query.
*
* @throws Exception the exception
*/
@Test
public void testVirtualTableDimensionInFilters() throws Exception
{
loadQueryAndValidate(FOLDER_RESOURCE + "ql-virtual-table-filters.ql");
List<QueryMarker> markers = getQueryMarkers();
assertEquals(2, markers.size());
QueryMarker marker = markers.get(0);
assertNotNull(marker.getTarget());
assertEquals(10, marker.getLineNumber());
marker = markers.get(1);
assertNotNull(marker.getTarget());
assertEquals(11, marker.getLineNumber());
}
/**
* Test virtual table dimension in parameters of the virtual table that is compliant query.
*
* @throws Exception the exception
*/
@Test
public void testVirtualTableDimensionInParameters() throws Exception
{
loadQueryAndValidate(FOLDER_RESOURCE + "ql-virtual-table-filters-compliant.ql");
List<QueryMarker> markers = getQueryMarkers();
assertTrue(markers.isEmpty());
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>QlFullDemo</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
<nature>com._1c.g5.v8.dt.core.V8ConfigurationNature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,2 @@
Manifest-Version: 1.0
Runtime-Version: 8.3.19

View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:AccumulationRegister xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:core="http://g5.1c.ru/v8/dt/mcore" xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="8f428475-637e-423b-ae04-52eedff7eb9a">
<producedTypes>
<selectionType typeId="7e13f4c8-f316-4376-864e-8a0a3d953769" valueTypeId="611ed5fd-2d14-4160-9682-fdf7d9471553"/>
<listType typeId="76d38f77-982d-40ee-81c1-69aed5bfa58f" valueTypeId="707d1294-2326-47b0-b858-e32e35dda216"/>
<managerType typeId="4bbaafc7-8bb6-4118-9fd5-a760c2f688a1" valueTypeId="ba11fe68-c788-4c86-a593-99ac793b7f56"/>
<recordSetType typeId="94f661ba-7e8c-4707-a41e-c3fca54bee00" valueTypeId="d803afa6-0d37-4208-8a01-a9bf2bafd28a"/>
<recordKeyType typeId="f8e59b4b-75b9-42db-9c0b-44bba3a979ef" valueTypeId="d593aa9e-f11f-4bb5-b888-05d131a8ba7c"/>
<recordType typeId="ca01113c-68f8-4321-8849-8d087d15bbac" valueTypeId="524150e9-af3e-4a1c-b566-aec26daf5320"/>
</producedTypes>
<name>Stocks</name>
<synonym>
<key>en</key>
<value>Stocks</value>
</synonym>
<useStandardCommands>true</useStandardCommands>
<dataLockControlMode>Managed</dataLockControlMode>
<enableTotalsSplitting>true</enableTotalsSplitting>
<resources uuid="c53b3494-a3cf-4686-8a7c-aa3aad6f1fef">
<name>Quntity</name>
<synonym>
<key>en</key>
<value>Quntity</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
</resources>
<resources uuid="aadc477f-eea9-4396-aaf8-5c0158948c72">
<name>Amount</name>
<synonym>
<key>en</key>
<value>Amount</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
</resources>
<dimensions uuid="bced3a0d-b507-45fd-92ab-4b110b5e7a32">
<name>Product</name>
<synonym>
<key>en</key>
<value>Product</value>
</synonym>
<type>
<types>CatalogRef.Products</types>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<useInTotals>true</useInTotals>
</dimensions>
<dimensions uuid="ad6c0d9f-9780-4e2d-991e-18a2e0300f68">
<name>Warehouse</name>
<synonym>
<key>en</key>
<value>Warehouse</value>
</synonym>
<type>
<types>String</types>
<stringQualifiers>
<length>25</length>
</stringQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<useInTotals>true</useInTotals>
</dimensions>
</mdclass:AccumulationRegister>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:core="http://g5.1c.ru/v8/dt/mcore" xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="b2fd044d-0eda-4dd8-87b1-5f5aa4021f80">
<producedTypes>
<objectType typeId="3d509ce2-91e7-4823-b288-387bac361060" valueTypeId="3f1031dd-bc5d-4b71-ac95-8441fe4b068d"/>
<refType typeId="0bc77064-20a1-4809-9163-0e941e59ccc5" valueTypeId="cd33e306-c24b-4890-883e-34d9c70a0300"/>
<selectionType typeId="88e82cdf-ac72-4241-b044-37a0e2e1c6c2" valueTypeId="04ebe965-49ee-4c06-949d-377fda54c361"/>
<listType typeId="a2a2fed0-ad90-42ed-af36-44e703c27e15" valueTypeId="1d63a0db-b1be-4839-af9b-ed56dccde130"/>
<managerType typeId="bb86848a-592f-4800-a6b5-e5941ab399a4" valueTypeId="80ff8d6a-94cf-466e-b313-0fd64f29b673"/>
</producedTypes>
<name>Products</name>
<synonym>
<key>en</key>
<value>Products</value>
</synonym>
<useStandardCommands>true</useStandardCommands>
<inputByString>Catalog.Products.StandardAttribute.Code</inputByString>
<inputByString>Catalog.Products.StandardAttribute.Description</inputByString>
<fullTextSearchOnInputByString>DontUse</fullTextSearchOnInputByString>
<createOnInput>Use</createOnInput>
<dataLockControlMode>Managed</dataLockControlMode>
<fullTextSearch>Use</fullTextSearch>
<levelCount>2</levelCount>
<foldersOnTop>true</foldersOnTop>
<codeLength>9</codeLength>
<descriptionLength>25</descriptionLength>
<codeType>String</codeType>
<codeAllowedLength>Variable</codeAllowedLength>
<checkUnique>true</checkUnique>
<autonumbering>true</autonumbering>
<defaultPresentation>AsDescription</defaultPresentation>
<editType>InDialog</editType>
<choiceMode>BothWays</choiceMode>
<attributes uuid="28d343c5-9385-4947-aabd-c9710318ecbb">
<name>SKU</name>
<synonym>
<key>en</key>
<value>SKU</value>
</synonym>
<type>
<types>String</types>
<stringQualifiers>
<length>50</length>
</stringQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fillValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<dataHistory>Use</dataHistory>
</attributes>
<attributes uuid="87de5891-0663-4737-a964-858bd4178415">
<name>ProductType</name>
<synonym>
<key>en</key>
<value>Product type</value>
</synonym>
<type>
<types>EnumRef.ProductType</types>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fillValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<dataHistory>Use</dataHistory>
</attributes>
</mdclass:Catalog>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Configuration xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="ac82a1aa-c235-4d82-981c-83db8b46b6f9">
<name>QlFullDemo</name>
<synonym>
<key>en</key>
<value>Ql full demo</value>
</synonym>
<containedObjects classId="9cd510cd-abfc-11d4-9434-004095e12fc7" objectId="b75ea52a-1270-4d00-8641-acb1dc8b1e18"/>
<containedObjects classId="9fcd25a0-4822-11d4-9414-008048da11f9" objectId="9b9184ee-1561-44f6-986f-bbad7bc65ad8"/>
<containedObjects classId="e3687481-0a87-462c-a166-9f34594f9bba" objectId="19f7afda-bd9d-4b6f-9918-460f079fa1d4"/>
<containedObjects classId="9de14907-ec23-4a07-96f0-85521cb6b53b" objectId="067e5fcc-671f-486e-9d09-61e71adc3a3e"/>
<containedObjects classId="51f2d5d8-ea4d-4064-8892-82951750031e" objectId="cff42135-668a-4e11-bb98-e38d991a9e07"/>
<containedObjects classId="e68182ea-4237-4383-967f-90c1e3370bc7" objectId="1ac9fa8e-26eb-47e2-8777-f81f8195fa28"/>
<containedObjects classId="fb282519-d103-4dd3-bc12-cb271d631dfc" objectId="fb199fe5-11d5-4af6-9e9b-084365badb8c"/>
<configurationExtensionCompatibilityMode>8.3.19</configurationExtensionCompatibilityMode>
<defaultRunMode>ManagedApplication</defaultRunMode>
<usePurposes>PersonalComputer</usePurposes>
<usedMobileApplicationFunctionalities>
<functionality>
<use>true</use>
</functionality>
<functionality>
<functionality>OSBackup</functionality>
<use>true</use>
</functionality>
</usedMobileApplicationFunctionalities>
<defaultLanguage>Language.English</defaultLanguage>
<dataLockControlMode>Managed</dataLockControlMode>
<objectAutonumerationMode>NotAutoFree</objectAutonumerationMode>
<modalityUseMode>DontUse</modalityUseMode>
<synchronousPlatformExtensionAndAddInCallUseMode>DontUse</synchronousPlatformExtensionAndAddInCallUseMode>
<compatibilityMode>8.3.19</compatibilityMode>
<languages uuid="7c2a7750-bb5c-4731-9bd9-b60909828556">
<name>English</name>
<synonym>
<key>en</key>
<value>English</value>
</synonym>
<languageCode>en</languageCode>
</languages>
<catalogs>Catalog.Products</catalogs>
<documents>Document.ProductArraival</documents>
<enums>Enum.ProductType</enums>
<reports>Report.QueryTestReport</reports>
<informationRegisters>InformationRegister.Prices</informationRegisters>
<accumulationRegisters>AccumulationRegister.Stocks</accumulationRegisters>
</mdclass:Configuration>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<cmi:CommandInterface xmlns:cmi="http://g5.1c.ru/v8/dt/cmi"/>

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:core="http://g5.1c.ru/v8/dt/mcore" xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="a1cfe5a0-f628-46c4-a212-d7d2a6f62ba2">
<producedTypes>
<objectType typeId="3e3316a3-2006-4c03-a873-9501b2385dbb" valueTypeId="aee558a7-41b3-48c1-b52f-f353149c13f1"/>
<refType typeId="d4172139-b581-4a0d-a889-73366398d436" valueTypeId="d86ec71e-cb85-4225-b7b1-cc79a89b607a"/>
<selectionType typeId="8ce955a5-c736-4d5c-9345-d924de166fd8" valueTypeId="aeb73a85-295c-4181-9234-d5eb649c59f7"/>
<listType typeId="882dff36-89b0-4369-baf0-43a10a05b413" valueTypeId="ea8ae1c3-58e1-47f2-9d55-21ea893220ab"/>
<managerType typeId="f1893a5b-ed61-4c81-8f95-a15537577d4f" valueTypeId="84632604-aa61-4ad4-b1ed-4dde8884c2b5"/>
</producedTypes>
<name>ProductArraival</name>
<synonym>
<key>en</key>
<value>Product arraival</value>
</synonym>
<useStandardCommands>true</useStandardCommands>
<inputByString>Document.ProductArraival.StandardAttribute.Number</inputByString>
<fullTextSearchOnInputByString>DontUse</fullTextSearchOnInputByString>
<createOnInput>Use</createOnInput>
<dataLockControlMode>Managed</dataLockControlMode>
<fullTextSearch>Use</fullTextSearch>
<numberType>String</numberType>
<numberLength>9</numberLength>
<numberAllowedLength>Variable</numberAllowedLength>
<checkUnique>true</checkUnique>
<autonumbering>true</autonumbering>
<registerRecords>AccumulationRegister.Stocks</registerRecords>
<postInPrivilegedMode>true</postInPrivilegedMode>
<unpostInPrivilegedMode>true</unpostInPrivilegedMode>
<tabularSections uuid="b4de901a-e119-4944-aed6-dd5c27c25781">
<producedTypes>
<objectType typeId="485c4989-7ae0-40b7-8167-5c29107a310f" valueTypeId="8780ca2b-34f3-42ee-8d7f-b2684cf03623"/>
<rowType typeId="858adf4f-ac12-4fff-9d8a-9416bacfe35e" valueTypeId="a7d83e84-8842-4df5-b309-a197658e424b"/>
</producedTypes>
<name>PurchaseItems</name>
<synonym>
<key>en</key>
<value>Purchase items</value>
</synonym>
<attributes uuid="efa4e37d-51db-45bb-b94d-8fb9d34ee1b6">
<name>Product</name>
<synonym>
<key>en</key>
<value>Product</value>
</synonym>
<type>
<types>CatalogRef.Products</types>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<dataHistory>Use</dataHistory>
<fullTextSearch>Use</fullTextSearch>
</attributes>
<attributes uuid="bf27a77b-52bf-4fae-a08c-62b8c6fcb978">
<name>Price</name>
<synonym>
<key>en</key>
<value>Price</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
<scale>2</scale>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<dataHistory>Use</dataHistory>
<fullTextSearch>Use</fullTextSearch>
</attributes>
<attributes uuid="2d62a560-11f4-40ec-9fe5-f64b20020554">
<name>Quantity</name>
<synonym>
<key>en</key>
<value>Quantity</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
<scale>3</scale>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<dataHistory>Use</dataHistory>
<fullTextSearch>Use</fullTextSearch>
</attributes>
<attributes uuid="e9987e06-4f56-4fad-b59d-46bdb27f8b73">
<name>Amount</name>
<synonym>
<key>en</key>
<value>Amount</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
<scale>2</scale>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<dataHistory>Use</dataHistory>
<fullTextSearch>Use</fullTextSearch>
</attributes>
</tabularSections>
</mdclass:Document>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Enum xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="59447593-edb5-4636-970b-c071e693fd31">
<producedTypes>
<refType typeId="ec4a2292-f74e-4c88-bf43-dd075d3c082a" valueTypeId="1a8528aa-a132-47b9-9c80-1bc6dce460d5"/>
<listType typeId="64f1e0a3-9ee5-47df-9e0e-74ea2f1ee60f" valueTypeId="69310944-293e-405e-a9a6-5804282d5a05"/>
<managerType typeId="8555b442-268a-49c0-9477-bb0d483a1db9" valueTypeId="11f94165-a5b9-4ab1-9862-f94f5f383b06"/>
</producedTypes>
<name>ProductType</name>
<synonym>
<key>en</key>
<value>Product type</value>
</synonym>
<quickChoice>true</quickChoice>
<choiceMode>BothWays</choiceMode>
<enumValues uuid="0532e585-e0de-42f3-b629-6ebcbfa12737">
<name>Product</name>
<synonym>
<key>en</key>
<value>Product</value>
</synonym>
</enumValues>
<enumValues uuid="d3cf5a53-853c-4dbb-b9d8-1b1882e44223">
<name>Service</name>
<synonym>
<key>en</key>
<value>Service</value>
</synonym>
</enumValues>
</mdclass:Enum>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:InformationRegister xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:core="http://g5.1c.ru/v8/dt/mcore" xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="91fb3029-a519-4f5a-a2cf-f31216df515b">
<producedTypes>
<selectionType typeId="d5d001c8-e9a8-471d-b398-3c621e6184b1" valueTypeId="5cdc62cb-e36d-4251-9a45-59f4956bb94a"/>
<listType typeId="97732e48-fdaf-4297-b41e-7559ab35deba" valueTypeId="1bb99cf0-7996-4c84-a42c-5a4726df9550"/>
<managerType typeId="06ba16ac-ccba-482c-b52f-de796c412efa" valueTypeId="5c552543-839f-46a6-9248-bda4ffd0b3c4"/>
<recordSetType typeId="284f6a3a-9225-40ce-bb57-ae4f8e26ce52" valueTypeId="9178e3a6-19c4-417f-97be-784c90fc3953"/>
<recordKeyType typeId="ecbe28c5-f8a1-444f-b625-b591fc5773ca" valueTypeId="8a3586f2-16ef-44be-a62f-1dc3926b1625"/>
<recordType typeId="abaccbbd-1fa0-4168-80e9-d1ba200d8c74" valueTypeId="28ea67a7-93e6-4b06-8723-09de10086f40"/>
<recordManagerType typeId="df18176a-2242-4588-9806-003bc9bf4280" valueTypeId="2dfb944b-135b-424b-87fe-c9554901f0f3"/>
</producedTypes>
<name>Prices</name>
<synonym>
<key>en</key>
<value>Prices</value>
</synonym>
<useStandardCommands>true</useStandardCommands>
<editType>InDialog</editType>
<informationRegisterPeriodicity>Second</informationRegisterPeriodicity>
<dataLockControlMode>Managed</dataLockControlMode>
<resources uuid="cd8bbc13-c141-4ac8-bad5-c63d92475741">
<name>Price</name>
<synonym>
<key>en</key>
<value>Price</value>
</synonym>
<type>
<types>Number</types>
<numberQualifiers>
<precision>10</precision>
<scale>2</scale>
</numberQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<dataHistory>Use</dataHistory>
<fillValue xsi:type="core:UndefinedValue"/>
</resources>
<attributes uuid="e4804451-9169-4b7e-9935-91ee2a111fc1">
<name>StartDate</name>
<synonym>
<key>en</key>
<value>Start date</value>
</synonym>
<type>
<types>Date</types>
<dateQualifiers>
<dateFractions>Date</dateFractions>
</dateQualifiers>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<dataHistory>Use</dataHistory>
<fillValue xsi:type="core:UndefinedValue"/>
</attributes>
<dimensions uuid="1f1b29bb-b985-4894-aca9-e94c7c845467">
<name>Product</name>
<synonym>
<key>en</key>
<value>Product</value>
</synonym>
<type>
<types>CatalogRef.Products</types>
</type>
<minValue xsi:type="core:UndefinedValue"/>
<maxValue xsi:type="core:UndefinedValue"/>
<fullTextSearch>Use</fullTextSearch>
<dataHistory>Use</dataHistory>
<fillValue xsi:type="core:UndefinedValue"/>
<mainFilter>true</mainFilter>
</dimensions>
</mdclass:InformationRegister>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:Report xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="371328e1-5c83-488e-a08a-672cba84cf15">
<producedTypes>
<objectType typeId="2b2f04c8-02b9-43f9-b01f-9774dcae9a44" valueTypeId="46f4bdc1-b36d-4cdf-b008-e2dc88318699"/>
<managerType typeId="fa00c82b-23c4-4e17-bb98-712fe2e9a901" valueTypeId="18c251ce-dc01-47ee-a889-b558e5c66a76"/>
</producedTypes>
<name>QueryTestReport</name>
<synonym>
<key>en</key>
<value>Query test report</value>
</synonym>
<useStandardCommands>true</useStandardCommands>
<mainDataCompositionSchema>Report.QueryTestReport.Template.MainDataCompositionSchema</mainDataCompositionSchema>
<templates uuid="eb429149-cbcf-4016-93ed-c11c7919ecba">
<name>MainDataCompositionSchema</name>
<synonym>
<key>en</key>
<value>Main data composition schema</value>
</synonym>
<templateType>DataCompositionSchema</templateType>
</templates>
</mdclass:Report>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<DataCompositionSchema xmlns="http://v8.1c.ru/8.1/data-composition-system/schema" xmlns:dcscom="http://v8.1c.ru/8.1/data-composition-system/common" xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core" xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dataSource>
<name>DataSource1</name>
<dataSourceType>Local</dataSourceType>
</dataSource>
<dataSet xsi:type="DataSetQuery">
<name>DataSet1</name>
<dataSource>DataSource1</dataSource>
<query/>
</dataSet>
<settingsVariant>
<dcsset:name>Default</dcsset:name>
<dcsset:presentation xsi:type="xs:string">Default</dcsset:presentation>
<dcsset:settings xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows"/>
</settingsVariant>
</DataCompositionSchema>