2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2024 Ericsson
4 * Modifications Copyright (C) 2024 OpenInfra Foundation Europe
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 package org.oran.smo.teiv.pgsqlgenerator.schema.data;
23 import static org.oran.smo.teiv.pgsqlgenerator.Constants.ALTER;
24 import static org.oran.smo.teiv.pgsqlgenerator.Constants.CREATE;
25 import static org.oran.smo.teiv.pgsqlgenerator.Constants.DEFAULT;
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.Objects;
35 import org.springframework.stereotype.Component;
37 import org.oran.smo.teiv.pgsqlgenerator.Column;
38 import org.oran.smo.teiv.pgsqlgenerator.Table;
41 public class ModelComparator {
43 private Map<String, List<Table>> identifiedChangesToModels;
46 * Identifies differences between baseline and generated models.
48 * @param tablesFromModelService
49 * Model information from Model Service
50 * @param tablesFromBaselineSql
51 * Model information from the baseline
52 * @return A map with identified changes to models
54 public Map<String, List<Table>> identifyDifferencesInBaselineAndGenerated(List<Table> tablesFromModelService,
55 List<Table> tablesFromBaselineSql) {
56 //TODO: Throw error if there is table from model service doesn't contain any info in baseline
57 identifiedChangesToModels = identifiedModelChangeMapping();
59 List<String> tableNamesOfBaseline = extractTableNames(tablesFromBaselineSql);
60 List<String> tableNameOfModelSvc = extractTableNames(tablesFromModelService);
62 if (!tableNameOfModelSvc.equals(tableNamesOfBaseline)) {
63 storeNewTables(tablesFromModelService, tableNamesOfBaseline, tableNameOfModelSvc);
65 compareAndStoreChangesToColumns(tablesFromModelService, tablesFromBaselineSql);
67 return Collections.unmodifiableMap(identifiedChangesToModels);
70 private Map<String, List<Table>> identifiedModelChangeMapping() {
71 Map<String, List<Table>> storeIdentifiedChangesToModels = new HashMap<>();
72 storeIdentifiedChangesToModels.put(CREATE, new ArrayList<>());
73 storeIdentifiedChangesToModels.put(ALTER, new ArrayList<>());
74 storeIdentifiedChangesToModels.put(DEFAULT, new ArrayList<>());
75 return storeIdentifiedChangesToModels;
79 * Check if all tables in extracted data from module service are same as what's in baseline schema Store identified with
82 private void storeNewTables(List<Table> tablesFromModelService, List<String> tableNamesOfBaseline,
83 List<String> tableNameOfGenerated) {
84 List<String> differences = tableNameOfGenerated.stream().filter(element -> !tableNamesOfBaseline.contains(element))
86 differences.forEach(tableName -> tablesFromModelService.stream().filter(table -> table.getName().equals(tableName))
87 .findFirst().ifPresent(table -> identifiedChangesToModels.get(CREATE).add(Table.builder().name(table
88 .getName()).columns(table.getColumns()).build())));
92 * Compare columns of each table from module service with columns of each table from baseline schema
94 private void compareAndStoreChangesToColumns(List<Table> tablesFromModelService, List<Table> tablesFromBaselineSql) {
95 tablesFromModelService.forEach(tableFromModelService -> {
96 tablesFromBaselineSql.stream().filter(baselineTable -> tableFromModelService.getName().equals(baselineTable
97 .getName())).findFirst().ifPresent(baselineTable -> {
99 List<Column> columnsInBaseline = new ArrayList<>(baselineTable.getColumns());
100 List<Column> columnsFromModuleSvc = new ArrayList<>(tableFromModelService.getColumns());
102 columnsInBaseline.sort(Comparator.comparing(Column::getName));
103 columnsFromModuleSvc.sort(Comparator.comparing(Column::getName));
105 // Check for new columns in table
106 if (columnsFromModuleSvc.size() > columnsInBaseline.size()) {
107 storeNewColumns(tableFromModelService.getName(), columnsInBaseline, columnsFromModuleSvc);
109 detectAndStoreDefaultValueChanges(tableFromModelService.getName(), columnsInBaseline,
110 columnsFromModuleSvc);
115 private List<String> extractTableNames(List<Table> tables) {
116 return tables.stream().map(Table::getName).sorted().toList();
120 * Check if new columns are introduced by comparing data from module service and baseline schema
122 private void storeNewColumns(String tableName, List<Column> columnsInBaseline, List<Column> columnsFromModuleSvc) {
123 List<Column> newColumns = columnsFromModuleSvc.stream().filter(columnInGenerated -> !getListOfAllColumns(
124 columnsInBaseline).contains(columnInGenerated.getName())).toList();
125 identifiedChangesToModels.get(ALTER).add(Table.builder().name(tableName).columns(newColumns.stream().map(
126 column -> Column.builder().name(column.getName()).dataType(column.getDataType()).postgresConstraints(column
127 .getPostgresConstraints()).build()).toList()).build());
128 List<Column> columnsWithDefaultValues = newColumns.stream().filter(columnIdentified -> columnIdentified
129 .getDefaultValue() != null).toList();
130 if (!columnsWithDefaultValues.isEmpty()) {
131 identifiedChangesToModels.get(DEFAULT).add(Table.builder().name(tableName).columns(columnsWithDefaultValues)
137 * Check if default values for all columns in tables from module service are same as what's in baseline schema Store
138 * identified with a "DEFAULT" key
140 private void detectAndStoreDefaultValueChanges(String tableName, List<Column> columnsInBaseline,
141 List<Column> columnsFromModuleSvc) {
142 List<Column> list = new ArrayList<>();
143 columnsInBaseline.forEach(columnInBaseline -> {
144 columnsFromModuleSvc.forEach(columnInGenerated -> {
145 if (columnInGenerated.getName().equals(columnInBaseline.getName()) && !Objects.equals(columnInGenerated
146 .getDefaultValue(), columnInBaseline.getDefaultValue())) {
147 list.add(columnInGenerated);
151 if (!list.isEmpty()) {
152 identifiedChangesToModels.get(DEFAULT).add(Table.builder().name(tableName).columns(list).build());
156 private List<String> getListOfAllColumns(List<Column> columns) {
157 List<String> allColumns = new ArrayList<>();
158 for (Column col : columns) {
159 allColumns.add(col.getName().replace("\"", ""));