Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Making user work #250

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
291c2a9
repair the damage: adding some missing piece
kjain110 Apr 23, 2024
d47f160
Merge pull request #246 from folio-org/user
kjain110 Apr 23, 2024
4b197e1
re
kjain110 Apr 24, 2024
e59b8ec
Merge pull request #247 from folio-org/trial
kjain110 Apr 25, 2024
f89a077
fixing simple user entity type
kjain110 Apr 25, 2024
691ab60
Merge pull request #249 from folio-org/another-atempt
kjain110 Apr 25, 2024
757ece3
MODFQMMGR-230: Update mod-fqm-manager to support nested entity types
bvsharp Apr 2, 2024
007df35
fix compile issues
bvsharp Apr 23, 2024
b5ca1de
Fix EntityTypeFlatteningService tests
bvsharp Apr 23, 2024
5d8b88a
Fix expected entity type for triple flatten test
bvsharp Apr 24, 2024
4a0ad90
Partial fix. Committing before breaking everything
bvsharp Apr 24, 2024
a6c589d
TripleNestedEntityTypeFlatteningTest working after changes. Still don…
bvsharp Apr 24, 2024
11edf9c
Copy entity types in tests
bvsharp Apr 24, 2024
2358293
Commit before reworking methods to be void (probably breaking things)
bvsharp Apr 24, 2024
5826069
Update simple invoice definitions
bvsharp Apr 25, 2024
0c60d6a
Update drv_locations definition
bvsharp Apr 25, 2024
e25cf5c
Update purchase_order definition
bvsharp Apr 25, 2024
654f982
Clean up definition files
bvsharp Apr 25, 2024
001f498
Update simple finance definitions
bvsharp Apr 25, 2024
7d8cea4
Update simple config_data definition
bvsharp Apr 25, 2024
69d2660
Remove unused from clauses
bvsharp Apr 25, 2024
081f25e
Use dot separator
bvsharp Apr 25, 2024
6e632b2
Properly implement dot separator
bvsharp Apr 25, 2024
1231ec5
making-user-work:making compatbile with poc changes
kjain110 Apr 25, 2024
c23063c
making-user-work: adding groups
kjain110 Apr 25, 2024
7807307
added fiscal year
kjain110 Apr 25, 2024
6098790
adding material-type
kjain110 Apr 29, 2024
b2f1d14
adding department
kjain110 Apr 29, 2024
e6a2628
adding mode of issueance
kjain110 Apr 29, 2024
ea487c4
adding stat code
kjain110 Apr 29, 2024
6c06381
adding stat code type
kjain110 Apr 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -24,7 +24,7 @@
<properties>
<!-- runtime dependencies -->
<folio-spring-base.version>8.1.0</folio-spring-base.version>
<folio-query-tool-metadata.version>2.0.0</folio-query-tool-metadata.version>
<folio-query-tool-metadata.version>2.1.0-SNAPSHOT</folio-query-tool-metadata.version>
<mapstruct.version>1.5.2.Final</mapstruct.version>
<lib-fqm-query-processor.version>2.0.0</lib-fqm-query-processor.version>
<coffee-boots.version>4.0.0</coffee-boots.version>
Expand Down
84 changes: 84 additions & 0 deletions src/main/java/org/folio/fqm/repository/EntityTypeRepository.java
@@ -1,5 +1,32 @@
package org.folio.fqm.repository;

import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;

import org.folio.fqm.exception.EntityTypeNotFoundException;
import org.folio.querytool.domain.dto.BooleanType;
import org.folio.querytool.domain.dto.EntityTypeColumn;
import org.folio.querytool.domain.dto.EntityTypeSource;
import org.folio.querytool.domain.dto.EntityTypeSourceJoin;
import org.folio.querytool.domain.dto.ValueWithLabel;
import org.jooq.DSLContext;
import org.jooq.Condition;
import org.jooq.Field;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;

import com.fasterxml.jackson.databind.ObjectMapper;

import org.folio.querytool.domain.dto.EntityType;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

import static org.apache.commons.collections4.CollectionUtils.isEmpty;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.or;
Expand Down Expand Up @@ -110,6 +137,63 @@ public void replaceEntityTypeDefinitions(List<EntityType> entityTypes) {
});
}

public Optional<EntityType> getCompositeEntityTypeDefinition(UUID entityTypeId) {
log.info("Getting COMPOSITE definition for entity type ID: {}", entityTypeId);
Field<String> definitionField = field("definition", String.class);

EntityType entityType = jooqContext
.select(definitionField)
.from(table(TABLE_NAME))
.where(field(ID_FIELD_NAME).eq(entityTypeId))
.fetchOptional(definitionField)
.map(this::unmarshallEntityType)
.map(currentEntityType -> {
String customFieldsEntityTypeId = currentEntityType.getCustomFieldEntityTypeId();
if (customFieldsEntityTypeId != null) {
currentEntityType.getColumns().addAll(fetchColumnNamesForCustomFields(UUID.fromString(customFieldsEntityTypeId)));
}
return currentEntityType;
}).orElseThrow();

// Build entity type from sources and joins
// var source1 = entityType.getSources().get(0);
// buildCompositeEntityTypeDefinition(entityType);

return Optional.of(entityType);
}

private void buildCompositeEntityTypeDefinition(EntityType entityType) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the code above is commented out, this method is unused

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method's name isn't very clear to me. When I see build_____(), I'd normally expect the method to return something. When I see that name but it's void, I have to go read the code to understand what it does

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but at a quick glance, it looks like this method can/should be static

System.out.println("BUILD COMPOSITE DEFINITION");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These System.out.println() calls should be replaced with calls to the logger

List<EntityTypeSourceJoin> entityTypeSourceJoins = new ArrayList<>();
List<EntityTypeSource> sources = entityType.getSources();
entityType.setFromClause("BUILD COMPOSITE DEFINITION");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal opinion: we should avoid using the fromClause if we're not actually using it for real, so that we can remove it from the object model ASAP. The more we use it, the harder it will be to remove

StringBuilder fromClause = new StringBuilder();
for (int i = 0; i < sources.size(); i++) {
EntityTypeSource source = sources.get(i);
System.out.println("Building source: " + source.getAlias());
// TODO: below if-block checks if source is the first in the array, since there is nothing to join if it is.
// But this needs to be done better
if (i == 0) { // TODO: think about replacing this with -- if (source.getJoin() == null)
fromClause.append(source.getAlias());
} else {
if (source.getType().equals("db")) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (source.getType().equals("db")) {
if ("db".equals(source.getType())) {

This way, we handles nulls and avoid a potential NPE

System.out.println("Building db source");
EntityTypeSourceJoin join = source.getJoin();
String joinType = join.getType();
String joinCondition = join.getCondition();
Comment on lines +181 to +183
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just stating the obvious here since this is implied by the comment above, but if source.getJoin() is null, we'll get an NPE here (and NPEs are always bugs)

String alias = source.getAlias();
fromClause.append(" " + joinType + " " + alias + " ON " + joinCondition);
} else if (source.getType().equals("entity-type")) {
System.out.println("Building entity-type source");
// get entity type definition
// get sources from that one recursively
}
}
}
String fromClauseString = fromClause.toString();
entityType.setFromClause(fromClauseString);
}

private List<EntityTypeColumn> fetchColumnNamesForCustomFields(UUID entityTypeId) {
log.info("Getting columns for entity type ID: {}", entityTypeId);
EntityType entityTypeDefinition = getEntityTypeDefinition(entityTypeId)
Expand Down
42 changes: 29 additions & 13 deletions src/main/java/org/folio/fqm/repository/IdStreamer.java
@@ -1,14 +1,17 @@
package org.folio.fqm.repository;

import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.folio.fqm.exception.EntityTypeNotFoundException;
import org.folio.fqm.model.IdsWithCancelCallback;
import org.folio.fqm.service.EntityTypeFlatteningService;
import org.folio.fqm.service.FqlToSqlConverterService;
import org.folio.fqm.utils.IdColumnUtils;
import org.folio.fqm.utils.StreamHelper;
import org.folio.fql.model.Fql;
import org.folio.querytool.domain.dto.EntityType;
import org.folio.querytool.domain.dto.EntityTypeDefaultSort;
import org.folio.querytool.domain.dto.EntityTypeSource;
import org.jooq.Condition;
import org.jooq.Cursor;
import org.jooq.DSLContext;
Expand All @@ -27,19 +30,20 @@
import java.util.stream.Stream;

import static org.apache.commons.lang3.ObjectUtils.isEmpty;
import static org.folio.fqm.repository.EntityTypeRepository.ID_FIELD_NAME;
import static org.folio.fqm.utils.IdColumnUtils.RESULT_ID_FIELD;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.select;
import static org.jooq.impl.DSL.table;

@Repository
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Log4j2
public class IdStreamer {

@Qualifier("readerJooqContext") private final DSLContext jooqContext;
private final EntityTypeRepository entityTypeRepository;
@Qualifier("readerJooqContext")
private final DSLContext jooqContext;
private final QueryDetailsRepository queryDetailsRepository;
private final EntityTypeFlatteningService entityTypeFlatteningService;

/**
* Executes the given Fql Query and stream the result Ids back.
Expand All @@ -49,7 +53,9 @@ public int streamIdsInBatch(UUID entityTypeId,
Fql fql,
int batchSize,
Consumer<IdsWithCancelCallback> idsConsumer) {
EntityType entityType = getEntityType(entityTypeId);
EntityType entityType = entityTypeFlatteningService
.getFlattenedEntityType(entityTypeId, true)
.orElseThrow(() -> new EntityTypeNotFoundException(entityTypeId));
Condition sqlWhereClause = FqlToSqlConverterService.getSqlCondition(fql.fqlCondition(), entityType);
return this.streamIdsInBatch(entityType, sortResults, sqlWhereClause, batchSize, idsConsumer);
}
Expand All @@ -63,12 +69,12 @@ public int streamIdsInBatch(UUID queryId,
Consumer<IdsWithCancelCallback> idsConsumer) {
UUID entityTypeId = queryDetailsRepository.getEntityTypeId(queryId);
EntityType entityType = getEntityType(entityTypeId);
Condition condition = field(ID_FIELD_NAME).in(
Condition condition = field("\"source1\".id").in(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to do something with this string before we merge this :)

select(RESULT_ID_FIELD)
.from(table("query_results"))
.where(field("query_id").eq(queryId))
);
return streamIdsInBatch(entityType, sortResults, condition, batchSize, idsConsumer);
return streamIdsInBatch(entityType, sortResults, condition, batchSize, idsConsumer); // TODO: fix this
}

public List<List<String>> getSortedIds(String derivedTableName,
Expand All @@ -91,19 +97,29 @@ public List<List<String>> getSortedIds(String derivedTableName,
}

private int streamIdsInBatch(EntityType entityType,
boolean sortResults,
Condition sqlWhereClause,
int batchSize,
Consumer<IdsWithCancelCallback> idsConsumer) {
boolean sortResults,
Condition sqlWhereClause,
int batchSize,
Consumer<IdsWithCancelCallback> idsConsumer) {
String finalJoinClause = entityTypeFlatteningService.getJoinClause(entityType);
Field<String[]> idValueGetter = IdColumnUtils.getResultIdValueGetter(entityType);
String finalWhereClause = sqlWhereClause.toString();
for (EntityTypeSource source : entityType.getSources()) {
String toReplace = ":" + source.getAlias();
String alias = "\"" + source.getAlias() + "\"";
finalWhereClause = finalWhereClause.replace(toReplace, alias);
}
Comment on lines +106 to +111
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should do this replacement by using SQL parameters, if at all possible. Doing it manually is generally pretty dangerous and bug-prone. The code for handling valueFunction does it that way, so it could be a useful reference

System.out.println("Final where clause: " + finalWhereClause);
try (
// NEW WAY
Cursor<Record1<String[]>> idsCursor = jooqContext.dsl()
.select(field(idValueGetter))
.from(entityType.getFromClause())
.where(sqlWhereClause)
.from(finalJoinClause)
.where(finalWhereClause)
.orderBy(getSortFields(entityType, sortResults))
.fetchSize(batchSize)
.fetchLazy();

Stream<String[]> idStream = idsCursor
.stream()
.map(row -> row.getValue(idValueGetter));
Expand Down Expand Up @@ -136,7 +152,7 @@ private static SortField<Object> toSortField(EntityTypeDefaultSort entityTypeDef
}

private EntityType getEntityType(UUID entityTypeId) {
return entityTypeRepository.getEntityTypeDefinition(entityTypeId)
return entityTypeFlatteningService.getFlattenedEntityType(entityTypeId, true)
.orElseThrow(() -> new EntityTypeNotFoundException(entityTypeId));
}
}
38 changes: 30 additions & 8 deletions src/main/java/org/folio/fqm/repository/ResultSetRepository.java
@@ -1,6 +1,5 @@
package org.folio.fqm.repository;

import static org.folio.fqm.repository.EntityTypeRepository.ID_FIELD_NAME;
import static org.jooq.impl.DSL.field;

import java.sql.SQLException;
Expand All @@ -14,6 +13,7 @@
import org.folio.fql.model.Fql;
import org.folio.fqm.exception.FieldNotFoundException;
import org.folio.fqm.exception.EntityTypeNotFoundException;
import org.folio.fqm.service.EntityTypeFlatteningService;
import org.folio.fqm.service.FqlToSqlConverterService;
import org.folio.fqm.utils.IdColumnUtils;
import org.folio.fqm.utils.SqlFieldIdentificationUtils;
Expand All @@ -22,6 +22,7 @@

import org.apache.commons.collections4.CollectionUtils;
import org.folio.querytool.domain.dto.EntityTypeColumn;
import org.folio.querytool.domain.dto.EntityTypeSource;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Field;
Expand All @@ -42,7 +43,7 @@
public class ResultSetRepository {

@Qualifier("readerJooqContext") private final DSLContext jooqContext;
private final EntityTypeRepository entityTypeRepository;
private final EntityTypeFlatteningService entityTypeFlatteningService;

public List<Map<String, Object>> getResultSet(UUID entityTypeId,
List<String> fields,
Expand Down Expand Up @@ -81,8 +82,12 @@ public List<Map<String, Object>> getResultSet(UUID entityTypeId,
whereClause = whereClause.and(field(idColumnValueGetter).in(idColumnValues));
}
}

String fromClause = entityTypeFlatteningService.getJoinClause(entityType);

// Have to get FROM clause
var result = jooqContext.select(fieldsToSelect)
.from(entityType.getFromClause())
.from(fromClause)
.where(whereClause)
.fetch();
return recordToMap(result);
Expand All @@ -104,11 +109,28 @@ public List<Map<String, Object>> getResultSet(UUID entityTypeId, Fql fql, List<S
}

Condition condition = FqlToSqlConverterService.getSqlCondition(fql.fqlCondition(), entityType);
// TODO: might want to put next 5 lines in its own method in EntityTypeFlatteningService
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree 100%, especially since this same code shows up in IdStreamer

// also is it even necessary?
String finalWhereClause = condition.toString();
for (EntityTypeSource source : entityType.getSources()) {
String toReplace = ":" + source.getAlias();
String alias = "\"" + source.getAlias() + "\"";
finalWhereClause = finalWhereClause.replace(toReplace, alias);
}
var fieldsToSelect = getSqlFields(entityType, fields);
var sortCriteria = hasIdColumn(entityType) ? field(ID_FIELD_NAME) : DSL.noField();
String idFieldWithAlias = "";
String idColumnName = entityType
.getColumns()
.stream()
.filter(EntityTypeColumn::getIsIdColumn)
.findFirst()
.orElseThrow()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should throw a specific exception, or at least a generic one with a clear error message

.getName();
var sortCriteria = hasIdColumn(entityType) ? field(idColumnName) : DSL.noField(); // TODO: new changes break sorting
String fromClause = entityTypeFlatteningService.getJoinClause(entityType);
var result = jooqContext.select(fieldsToSelect)
.from(entityType.getFromClause())
.where(condition)
.from(fromClause)
.where(finalWhereClause)
.and(afterIdCondition)
.orderBy(sortCriteria)
.limit(limit)
Expand All @@ -126,13 +148,13 @@ private List<Field<Object>> getSqlFields(EntityType entityType, List<String> fie
}

private EntityType getEntityType(UUID entityTypeId) {
return entityTypeRepository.getEntityTypeDefinition(entityTypeId)
return entityTypeFlatteningService.getFlattenedEntityType(entityTypeId, true)
.orElseThrow(() -> new EntityTypeNotFoundException(entityTypeId));
}

private boolean hasIdColumn(EntityType entityType) {
return entityType.getColumns().stream()
.anyMatch(col -> ID_FIELD_NAME.equals(col.getName()));
.anyMatch(col -> col.getIsIdColumn());
}

private List<Map<String, Object>> recordToMap(Result<Record> result) {
Expand Down