Changes between Initial Version and Version 1 of AdvancedQueries


Ignore:
Timestamp:
08/24/25 20:29:04 (9 days ago)
Author:
221007
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedQueries

    v1 v1  
     1== Употреба на напредно кверирање во базата
     2
     3Следното парче код е познато како „градење на спецификација“, која во JAVA светот е во суштина некакво си генеричко квери кое се извршува во позадината. Наместо да се изгради со SQL, се гради со Specification објект, кој потоа се преведува во SQL квери и враќа резултат од истото. Ќе го покажам тоа со неколку различни случаи.
     4
     5Идејата е да се овозможи напредно филтрирање на извештаи од различен тип.
     6
     7{{{
     8public static Specification<Report> build(ReportFilterDTO filter) {
     9        return (root, query, cb) -> {
     10            query.distinct(false);
     11            LocalDate now = LocalDate.now();
     12            List<Predicate> predicates = new ArrayList<>();
     13            Join<Report, Person> report_on_person_join = root.join("person", JoinType.LEFT);
     14
     15            /* Person */
     16            if (filter.getFilter_selected().equals(SelectedFilterSection.PERSON)) {
     17                // predicate that checks if there exists a person with the string provided in the name
     18                if (filter.getPerson_name_string() != null && !filter.getPerson_name_string().isBlank()) {
     19                    predicates.add(cb.like(cb.lower(report_on_person_join.get("name")),
     20                            "%" + filter.getPerson_name_string().toLowerCase() + "%"));
     21                }
     22                // predicate that checks if there exists a person with the string provided in the surname
     23                if (filter.getPerson_surname_string() != null && !filter.getPerson_surname_string().isBlank()) {
     24                    predicates.add(cb.like(cb.lower(report_on_person_join.get("surname")), "%" + filter.getPerson_surname_string().toLowerCase() + "%"));
     25                }
     26                // Age filters work for people who are alive only, otherwise no
     27                if (filter.getIs_alive()) {
     28                    if (filter.getCorrect_age() != null && filter.getCorrect_age() > 0) {
     29                        Expression<Integer> years_age = cb.function("date_part", Integer.class, cb.literal("year"),
     30                                cb.function("age", String.class, cb.currentDate(), report_on_person_join.get("dateOfBirth")));
     31                        predicates.add(cb.equal(years_age, filter.getCorrect_age()));
     32                    } else if (filter.getCorrect_age() == null || filter.getCorrect_age() == 0) {
     33                        if (filter.getAge_start() > 0) {
     34                            LocalDate start_age = now.minusYears(filter.getAge_start());//
     35                            predicates.add(cb.lessThanOrEqualTo(report_on_person_join.get("dateOfBirth"), start_age));
     36                        }
     37                        if (filter.getAge_end() < 120) {
     38                            LocalDate end_age = now.minusYears(filter.getAge_end() + 1).plusDays(1);
     39                            predicates.add(cb.greaterThanOrEqualTo(report_on_person_join.get("dateOfBirth"), end_age));
     40                        }
     41                    }
     42                    predicates.add(cb.isNull(report_on_person_join.get("dateOfDeath")));
     43                } else {
     44                    predicates.add(cb.isNotNull(report_on_person_join.get("dateOfDeath")));
     45                }
     46                // Gender
     47                if (filter.getGender() != null) {
     48                    predicates.add(cb.equal(report_on_person_join.get("gender"), filter.getGender()));
     49                }
     50                // Address
     51                if (filter.getAddress_string() != null && !filter.getAddress_string().isBlank()) {
     52                    predicates.add(cb.like(
     53                            cb.lower(report_on_person_join.get("address")),
     54                            "%" + filter.getAddress_string().toLowerCase() + "%"
     55                    ));
     56                }
     57            }
     58
     59            /* Employment Report */
     60            //ALL TESTED!
     61            if (filter.getFilter_selected().equals(SelectedFilterSection.EMPLOYMENT)) {
     62                Join<Report, EmploymentReport> employment_report_join = root.join("employmentReport", JoinType.LEFT);
     63                //predicate for income check (more,less,equal)
     64                if (filter.getIncome_comparison() != null && filter.getIncome_amount() > 0) {
     65                    switch (filter.getIncome_comparison()) {
     66                        case more ->
     67                                predicates.add(cb.greaterThan(employment_report_join.get("incomePerMonth"), filter.getIncome_amount()));
     68                        case equal ->
     69                                predicates.add(cb.equal(employment_report_join.get("incomePerMonth"), filter.getIncome_amount()));
     70                        case less ->
     71                                predicates.add(cb.lessThan(employment_report_join.get("incomePerMonth"), filter.getIncome_amount()));
     72                    }
     73                }
     74                //predicate for years_experience check (more,less,equal)
     75                if (filter.getYears_experience_comparison() != null && filter.getYears_experience() > 0) {
     76                    //this function is in the database, and I execute it
     77                    Expression<Integer> totalYearsExpr = cb.function(
     78                            "years_total", Integer.class,
     79                            employment_report_join.get("startDate"), employment_report_join.get("endDate")
     80                    );
     81                    switch (filter.getYears_experience_comparison()) {
     82                        case more -> predicates.add(cb.greaterThan(totalYearsExpr, filter.getYears_experience()));
     83                        case equal -> predicates.add(cb.equal(totalYearsExpr, filter.getYears_experience()));
     84                        case less -> predicates.add(cb.lessThan(totalYearsExpr, filter.getYears_experience()));
     85                    }
     86                }
     87            }
     88
     89            /* Academic Report */
     90            //ALL TESTED!
     91            if (filter.getFilter_selected().equals(SelectedFilterSection.ACADEMIC)) {
     92                Join<Report, AcademicReport> academic_report_join = root.join("academicReport", JoinType.LEFT);
     93                //predicate for field of study
     94                if (filter.getAcademic_field() != null && !filter.getAcademic_field().isBlank()) {
     95                    predicates.add(cb.like(cb.lower(academic_report_join.get("academicField")), "%" + filter.getAcademic_field().toLowerCase() + "%"));
     96                }
     97                //predicate for institution field
     98                Join<AcademicReport, Institution> academic_report_institution_join = academic_report_join.join("institution", JoinType.LEFT);
     99                if (filter.getInstitution_type() != null) {
     100                    predicates.add(cb.equal(academic_report_institution_join.get("type"), filter.getInstitution_type()));
     101                }
     102            }
     103
     104            /* Medical Report */
     105            //ALL TESTED!
     106            if (filter.getFilter_selected().equals(SelectedFilterSection.MEDICAL)) {
     107                // Join to MedicalReport and Doctor
     108                Join<Report, MedicalReport> medicalReportJoin = root.join("medicalReport", JoinType.LEFT);
     109                Join<MedicalReport, Doctor> doctorJoin = medicalReportJoin.join("doctor", JoinType.LEFT);
     110                Join<MedicalReport, MedicalReportDiagnosis> diagnosisLinkJoin = medicalReportJoin.join("medicalReportDiagnoses", JoinType.LEFT);
     111                Join<MedicalReportDiagnosis, Diagnosis> diagnosisJoin = diagnosisLinkJoin.join("diagnosis", JoinType.LEFT);
     112                // Has Next Medical Control
     113                if (Boolean.TRUE.equals(filter.getHas_next_control())) {
     114                    predicates.add(cb.isNotNull(medicalReportJoin.get("nextControlDate")));
     115                } else {
     116                    predicates.add(cb.isNull(medicalReportJoin.get("nextControlDate")));
     117                }
     118                // Doctor Name
     119                if (filter.getDoctor_name_string() != null && !filter.getDoctor_name_string().isBlank()) {
     120                    predicates.add(cb.like(cb.lower(doctorJoin.get("name")), "%" + filter.getDoctor_name_string().toLowerCase() + "%"));
     121                }
     122                // Doctor Surname
     123                if (filter.getDoctor_surname_string() != null && !filter.getDoctor_surname_string().isBlank()) {
     124                    predicates.add(cb.like(cb.lower(doctorJoin.get("surname")), "%" + filter.getDoctor_surname_string().toLowerCase() + "%"));
     125                }
     126                // Specialization
     127                if (filter.getSpecialization() != null) {
     128                    predicates.add(cb.equal(doctorJoin.get("specialization"), filter.getSpecialization()));
     129                }
     130                // Chronic diagnosis
     131                if (filter.getIs_chronic() != null) {
     132                    predicates.add(cb.equal(diagnosisJoin.get("isChronic"), filter.getIs_chronic()));
     133                }
     134            }
     135           
     136            /* Criminal Report */
     137            if (filter.getFilter_selected().equals(SelectedFilterSection.CRIMINAL)) {
     138                Join<Report, CriminalReport> criminal_report_join = root.join("criminalReport", JoinType.LEFT);
     139                Join<CriminalReport, CrimeType> crime_type_join = criminal_report_join.join("crimeType", JoinType.LEFT);
     140                //predicate for severity level
     141                if (filter.getCrime_severity_level() != null) {
     142                    predicates.add(cb.equal(crime_type_join.get("severityLevel"), filter.getCrime_severity_level()));
     143                }
     144                //predicate for resolved
     145                if (filter.getIs_resolved() != null) {
     146                    predicates.add(cb.equal(criminal_report_join.get("resolved"), filter.getIs_resolved()));
     147                }
     148                Join<CriminalReport, Punishment> punishment_join = criminal_report_join.join("punishment", JoinType.INNER);
     149                //predicate for punishment as fine
     150                if (PunishmentType.FINE.equals(filter.getPunishment_type()) && filter.getPunishment_fine() != null && filter.getPunishment_fine() > 0) {
     151                    predicates.add(cb.equal(punishment_join.get("fineToPay"), filter.getPunishment_fine()));
     152                }
     153                //predicate for punishment as prison
     154                if (PunishmentType.PRISON.equals(filter.getPunishment_type()) && filter.getPunishment_years() != null && filter.getPunishment_years() > 0) {
     155                    Expression<LocalDate> created_at = root.get("createdAt");
     156                    Expression<Integer> years_in_prison = cb.function("years_total", Integer.class,
     157                            created_at, punishment_join.get("releaseDate"));
     158                    predicates.add(cb.equal(years_in_prison, filter.getPunishment_years()));
     159                }
     160                //predicate for criminal type
     161                if (filter.getCrime_type_label() != null && !filter.getCrime_type_label().isBlank()) {
     162                    predicates.add(cb.like(cb.lower(crime_type_join.get("label")), "%" + filter.getCrime_type_label().toLowerCase() + "%"));
     163                }
     164            }
     165            return cb.and(predicates.toArray(new Predicate[0]));
     166        };
     167    }
     168}}}
     169