fixed various modeling issues

This commit is contained in:
2023-02-09 23:53:34 -05:00
parent e330e0ebbb
commit ed80f1bd26
10 changed files with 642 additions and 244 deletions

View File

@@ -1,7 +1,6 @@
package com.poststats.golf.api; package com.poststats.golf.api;
import com.brianlong.util.FlexMap; import com.brianlong.util.FlexMap;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.poststats.api.Constants; import com.poststats.api.Constants;
import com.poststats.golf.api.model.Event; import com.poststats.golf.api.model.Event;
import com.poststats.golf.api.model.Series; import com.poststats.golf.api.model.Series;
@@ -25,9 +24,9 @@ import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response.Status; import jakarta.ws.rs.core.Response.Status;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -75,7 +74,7 @@ public class SeriesApi {
@ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "An event series with the specified ID could not be found") @ApiResponse(responseCode = "404", description = "An event series with the specified ID could not be found")
}) })
public Series get() throws JsonProcessingException { public Series get() {
FlexMap row = this.seriesService.get(this.seriesId); FlexMap row = this.seriesService.get(this.seriesId);
if (row == null) if (row == null)
throw new WebApplicationException("Series not found", Status.NOT_FOUND); throw new WebApplicationException("Series not found", Status.NOT_FOUND);
@@ -83,21 +82,6 @@ public class SeriesApi {
return this.converter.convertValue(row, Series.class); return this.converter.convertValue(row, Series.class);
} }
@GET
@Path("/eventIds")
@Produces(Constants.V1_JSON)
@Operation(summary = "Retrieves event IDs under an event series.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "An event series with the specified ID could not be found")
})
public Set<Long> getEventIds() throws JsonProcessingException {
Set<Long> eventIds = this.eventService.getIdsBySeriesId(this.seriesId);
if (eventIds.isEmpty())
throw new WebApplicationException("Series or events not found", Status.NOT_FOUND);
return eventIds;
}
@GET @GET
@Path("/events") @Path("/events")
@Produces(Constants.V1_JSON) @Produces(Constants.V1_JSON)
@@ -109,13 +93,15 @@ public class SeriesApi {
@ApiResponse(responseCode = "200", description = "Success"), @ApiResponse(responseCode = "200", description = "Success"),
@ApiResponse(responseCode = "404", description = "An event series with the specified ID could not be found") @ApiResponse(responseCode = "404", description = "An event series with the specified ID could not be found")
}) })
public List<Event> getEvents(@QueryParam("reverse") Boolean reverse) throws JsonProcessingException { public List<Event> getEvents(@QueryParam("reverse") Boolean reverse) {
Map<Long, ? extends FlexMap> rows = this.eventService.getBySeriesId(this.seriesId, Map<Long, ? extends FlexMap> rows = this.eventService.getBySeriesId(this.seriesId);
!Boolean.TRUE.equals(reverse));
if (rows.isEmpty()) if (rows.isEmpty())
throw new WebApplicationException("Series or events not found", Status.NOT_FOUND); throw new WebApplicationException("Series or events not found", Status.NOT_FOUND);
return this.converter.convertValue(rows.values(), Event.class); List<Event> events = this.converter.convertValue(rows.values(), Event.class);
if (Boolean.TRUE.equals(reverse))
Collections.reverse(events);
return events;
} }
} }

View File

@@ -2,6 +2,12 @@ package com.poststats.golf.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.golf.api.Constants;
import com.poststats.service.impl.DefaultFormattingService;
import com.poststats.transformer.GeocodeSource;
import com.poststats.transformer.GeocodeTarget;
import com.poststats.transformer.GeocodeTarget.GeocodeField;
import com.poststats.transformer.MapCondition;
import com.poststats.transformer.MapEntry; import com.poststats.transformer.MapEntry;
import jakarta.annotation.Generated; import jakarta.annotation.Generated;
import java.time.LocalDate; import java.time.LocalDate;
@@ -24,10 +30,126 @@ public class Event extends TransientEvent {
@MapEntry @MapEntry
private LocalDate deadline; private LocalDate deadline;
@MapEntry
@GeocodeTarget(GeocodeField.City)
private String addrcity;
@MapEntry
@GeocodeTarget(GeocodeField.State)
private String addrstate;
@MapEntry
@GeocodeTarget(GeocodeField.Country)
private String addrcountry;
@JsonProperty @JsonProperty
@MapEntry @MapEntry
private Series series; private Series series;
@JsonProperty
@MapEntry
private Boolean financesEnabled;
@JsonProperty
@MapEntry
private Boolean optionsEnabled;
@JsonProperty
@MapEntry
private Boolean notebookEnabled;
@JsonProperty
@MapEntry
private Boolean calendarEnabled;
@JsonProperty
@MapEntry
private Boolean pairingsEnabled;
@JsonProperty
@MapEntry
private Boolean teamsEnabled;
@JsonProperty
@MapEntry
private Boolean lodgingEnabled;
@JsonProperty
@MapEntry
private Boolean documentsEnabled;
@JsonProperty
@MapEntry
private Boolean awardsEnabled;
@JsonProperty
@MapEntry
private Boolean specialHolesEnabled;
@JsonProperty
@MapEntry
private Boolean courseHandicapEnabled;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin"
})
private LocalDate registrationLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin"
})
private LocalDate registrationHideline;
@JsonProperty
@MapEntry
private LocalDate registrationDeadline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "finance"
})
private LocalDate financesLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "pairing"
})
private LocalDate pairingsLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "pairing"
})
private LocalDate teamsLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "options"
})
private LocalDate lodgingLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "pairing"
})
private LocalDate documentsLiveline;
@JsonProperty
@MapEntry
@MapCondition(rolesAllowed = {
Constants.EVENT_ROLE_PREFIX + "admin", Constants.EVENT_ROLE_PREFIX + "pairing"
})
private LocalDate specialHolesLiveline;
@Generated("Eclipse") @Generated("Eclipse")
public long getId() { public long getId() {
return id; return id;
@@ -58,6 +180,20 @@ public class Event extends TransientEvent {
this.deadline = deadline; this.deadline = deadline;
} }
@Override
@GeocodeSource
public String getFuzzyLocation() {
synchronized (this) {
if (super.getFuzzyLocation() == null) {
String address = new DefaultFormattingService().formatFuzzyPostalAddress(null, this.addrcity,
this.addrstate, this.addrcountry, null);
super.setFuzzyLocation(address);
}
}
return super.getFuzzyLocation();
}
public Series getSeries() { public Series getSeries() {
return series; return series;
} }
@@ -66,6 +202,166 @@ public class Event extends TransientEvent {
this.series = series; this.series = series;
} }
public Boolean getAwardsEnabled() {
return awardsEnabled;
}
public void setAwardsEnabled(Boolean awardsEnabled) {
this.awardsEnabled = awardsEnabled;
}
public Boolean getCalendarEnabled() {
return calendarEnabled;
}
public void setCalendarEnabled(Boolean calendarEnabled) {
this.calendarEnabled = calendarEnabled;
}
public Boolean getCourseHandicapEnabled() {
return courseHandicapEnabled;
}
public void setCourseHandicapEnabled(Boolean courseHandicapEnabled) {
this.courseHandicapEnabled = courseHandicapEnabled;
}
public Boolean getDocumentsEnabled() {
return documentsEnabled;
}
public void setDocumentsEnabled(Boolean documentsEnabled) {
this.documentsEnabled = documentsEnabled;
}
public Boolean getFinancesEnabled() {
return financesEnabled;
}
public void setFinancesEnabled(Boolean financesEnabled) {
this.financesEnabled = financesEnabled;
}
public Boolean getLodgingEnabled() {
return lodgingEnabled;
}
public void setLodgingEnabled(Boolean lodgingEnabled) {
this.lodgingEnabled = lodgingEnabled;
}
public Boolean getNotebookEnabled() {
return notebookEnabled;
}
public void setNotebookEnabled(Boolean notebookEnabled) {
this.notebookEnabled = notebookEnabled;
}
public Boolean getOptionsEnabled() {
return optionsEnabled;
}
public void setOptionsEnabled(Boolean optionsEnabled) {
this.optionsEnabled = optionsEnabled;
}
public Boolean getPairingsEnabled() {
return pairingsEnabled;
}
public void setPairingsEnabled(Boolean pairingsEnabled) {
this.pairingsEnabled = pairingsEnabled;
}
public Boolean getSpecialHolesEnabled() {
return specialHolesEnabled;
}
public void setSpecialHolesEnabled(Boolean specialHolesEnabled) {
this.specialHolesEnabled = specialHolesEnabled;
}
public Boolean getTeamsEnabled() {
return teamsEnabled;
}
public void setTeamsEnabled(Boolean teamsEnabled) {
this.teamsEnabled = teamsEnabled;
}
public LocalDate getRegistrationLiveline() {
return registrationLiveline;
}
public void setRegistrationLiveline(LocalDate registrationLiveline) {
this.registrationLiveline = registrationLiveline;
}
public LocalDate getRegistrationHideline() {
return registrationHideline;
}
public void setRegistrationHideline(LocalDate registrationHideline) {
this.registrationHideline = registrationHideline;
}
public LocalDate getRegistrationDeadline() {
return registrationDeadline;
}
public void setRegistrationDeadline(LocalDate registrationDeadline) {
this.registrationDeadline = registrationDeadline;
}
public LocalDate getDocumentsLiveline() {
return documentsLiveline;
}
public void setDocumentsLiveline(LocalDate documentsLiveline) {
this.documentsLiveline = documentsLiveline;
}
public LocalDate getFinancesLiveline() {
return financesLiveline;
}
public void setFinancesLiveline(LocalDate financesLiveline) {
this.financesLiveline = financesLiveline;
}
public LocalDate getLodgingLiveline() {
return lodgingLiveline;
}
public void setLodgingLiveline(LocalDate lodgingLiveline) {
this.lodgingLiveline = lodgingLiveline;
}
public LocalDate getPairingsLiveline() {
return pairingsLiveline;
}
public void setPairingsLiveline(LocalDate pairingsLiveline) {
this.pairingsLiveline = pairingsLiveline;
}
public LocalDate getSpecialHolesLiveline() {
return specialHolesLiveline;
}
public void setSpecialHolesLiveline(LocalDate specialHolesLiveline) {
this.specialHolesLiveline = specialHolesLiveline;
}
public LocalDate getTeamsLiveline() {
return teamsLiveline;
}
public void setTeamsLiveline(LocalDate teamsLiveline) {
this.teamsLiveline = teamsLiveline;
}
@Generated("Spark") @Generated("Spark")
public Event withId(long id) { public Event withId(long id) {
this.id = id; this.id = id;
@@ -89,4 +385,89 @@ public class Event extends TransientEvent {
return this; return this;
} }
public Event withDocumentsEnabled(Boolean documentsEnabled) {
this.documentsEnabled = documentsEnabled;
return this;
}
public Event withFinancesEnabled(Boolean financesEnabled) {
this.financesEnabled = financesEnabled;
return this;
}
public Event withLodgingEnabled(Boolean lodgingEnabled) {
this.lodgingEnabled = lodgingEnabled;
return this;
}
public Event withNotebookEnabled(Boolean notebookEnabled) {
this.notebookEnabled = notebookEnabled;
return this;
}
public Event withOptionsEnabled(Boolean optionsEnabled) {
this.optionsEnabled = optionsEnabled;
return this;
}
public Event withPairingsEnabled(Boolean pairingsEnabled) {
this.pairingsEnabled = pairingsEnabled;
return this;
}
public Event withSpecialHolesEnabled(Boolean specialHolesEnabled) {
this.specialHolesEnabled = specialHolesEnabled;
return this;
}
public Event withTeamsEnabled(Boolean teamsEnabled) {
this.teamsEnabled = teamsEnabled;
return this;
}
public Event withRegistrationLiveline(LocalDate registrationLiveline) {
this.registrationLiveline = registrationLiveline;
return this;
}
public Event withRegistrationHideline(LocalDate registrationHideline) {
this.registrationHideline = registrationHideline;
return this;
}
public Event withRegistrationDeadline(LocalDate registrationDeadline) {
this.registrationDeadline = registrationDeadline;
return this;
}
public Event withDocumentsLiveline(LocalDate documentsLiveline) {
this.documentsLiveline = documentsLiveline;
return this;
}
public Event withFinancesLiveline(LocalDate financesLiveline) {
this.financesLiveline = financesLiveline;
return this;
}
public Event withLodgingLiveline(LocalDate lodgingLiveline) {
this.lodgingLiveline = lodgingLiveline;
return this;
}
public Event withPairingsLiveline(LocalDate pairingsLiveline) {
this.pairingsLiveline = pairingsLiveline;
return this;
}
public Event withSpecialHolesLiveline(LocalDate specialHolesLiveline) {
this.specialHolesLiveline = specialHolesLiveline;
return this;
}
public Event withTeamsLiveline(LocalDate teamsLiveline) {
this.teamsLiveline = teamsLiveline;
return this;
}
} }

View File

@@ -10,16 +10,12 @@ import jakarta.annotation.Generated;
* @author brian.long@poststats.com * @author brian.long@poststats.com
*/ */
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class Series { public class Series extends TransientSeries {
@JsonProperty(required = true, access = Access.READ_ONLY) @JsonProperty(required = true, access = Access.READ_ONLY)
@MapEntry("seriesID") @MapEntry("seriesID")
private long id; private long id;
@JsonProperty(required = true)
@MapEntry("series")
private String name;
@Generated("Eclipse") @Generated("Eclipse")
public long getId() { public long getId() {
return id; return id;
@@ -30,26 +26,10 @@ public class Series {
this.id = id; this.id = id;
} }
@Generated("Eclipse")
public String getName() {
return name;
}
@Generated("Eclipse")
public void setName(String name) {
this.name = name;
}
@Generated("Spark") @Generated("Spark")
public Series withId(long id) { public Series withId(long id) {
this.id = id; this.id = id;
return this; return this;
} }
@Generated("Spark")
public Series withName(String name) {
this.name = name;
return this;
}
} }

View File

@@ -3,6 +3,7 @@ package com.poststats.golf.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.transformer.MapEntry; import com.poststats.transformer.MapEntry;
import jakarta.annotation.Generated; import jakarta.annotation.Generated;
/** /**
@@ -11,10 +12,32 @@ import jakarta.annotation.Generated;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class TransientEvent { public class TransientEvent {
public enum EventType {
@JsonProperty("outing")
@MapEntry("outing")
Outing, @JsonProperty("tourney")
@MapEntry("tourney")
Tourney, @JsonProperty("trip")
@MapEntry("trip")
Trip, @JsonProperty("league")
@MapEntry("league")
League
}
@JsonProperty(required = true) @JsonProperty(required = true)
@MapEntry("event") @MapEntry("event")
private String name; private String name;
@JsonProperty(required = true)
@MapEntry
private EventType type;
@JsonProperty
private boolean showPublic;
@JsonProperty
private String fuzzyLocation;
@Generated("Eclipse") @Generated("Eclipse")
public String getName() { public String getName() {
return name; return name;
@@ -25,10 +48,48 @@ public class TransientEvent {
this.name = name; this.name = name;
} }
@Generated("Spark") public EventType getType() {
return type;
}
public void setType(EventType type) {
this.type = type;
}
public boolean isShowPublic() {
return showPublic;
}
public void setShowPublic(boolean showPublic) {
this.showPublic = showPublic;
}
public String getFuzzyLocation() {
return fuzzyLocation;
}
public void setFuzzyLocation(String fuzzyLocation) {
this.fuzzyLocation = fuzzyLocation;
}
public TransientEvent withName(String name) { public TransientEvent withName(String name) {
this.name = name; this.name = name;
return this; return this;
} }
public TransientEvent withType(EventType type) {
this.type = type;
return this;
}
public TransientEvent withShowPublic(boolean showPublic) {
this.showPublic = showPublic;
return this;
}
public TransientEvent withFuzzyLocation(String fuzzyLocation) {
this.fuzzyLocation = fuzzyLocation;
return this;
}
} }

View File

@@ -0,0 +1,34 @@
package com.poststats.golf.api.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.poststats.transformer.MapEntry;
import jakarta.annotation.Generated;
/**
* @author brian.long@poststats.com
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransientSeries {
@JsonProperty(required = true)
@MapEntry("series")
private String name;
@Generated("Eclipse")
public String getName() {
return name;
}
@Generated("Eclipse")
public void setName(String name) {
this.name = name;
}
@Generated("Spark")
public TransientSeries withName(String name) {
this.name = name;
return this;
}
}

View File

@@ -25,7 +25,7 @@ public interface EventService {
Set<Long> getIdsBySeriesId(int seriesId); Set<Long> getIdsBySeriesId(int seriesId);
Map<Long, ? extends FlexMap> getBySeriesId(int seriesId, boolean chronological); Map<Long, ? extends FlexMap> getBySeriesId(int seriesId);
Integer getSeriesId(long eventId); Integer getSeriesId(long eventId);

View File

@@ -2,12 +2,14 @@ package com.poststats.golf.service.db;
import com.brianlong.sql.DataSet; import com.brianlong.sql.DataSet;
import com.brianlong.sql.FlexPreparedStatement; import com.brianlong.sql.FlexPreparedStatement;
import com.poststats.golf.api.Constants;
import com.poststats.golf.service.EventFinanceService; import com.poststats.golf.service.EventFinanceService;
import com.poststats.golf.sql.GolfSQL; import com.poststats.provider.Statement;
import com.poststats.provider.StatementProvider;
import com.poststats.service.ServiceException; import com.poststats.service.ServiceException;
import com.poststats.sql.PostStatsDataSource;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import java.sql.Connection; import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
@@ -16,65 +18,60 @@ public class EventFinanceServiceDAO implements EventFinanceService {
@Override @Override
public List<DataSet> getPersonsBalances(long eventId) { public List<DataSet> getPersonsBalances(long eventId) {
Connection dbcon = PostStatsDataSource.getInstance().acquire(true);
try { try {
return this.queryPersonsBalances(dbcon, eventId); FlexPreparedStatement fps = this.sqlSelectBalances.buildPreparedStatement();
try {
for (int i = 1; i <= 5; i++)
fps.setIntegerU(i, eventId);
return fps.executeQuery().getAllRows();
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
PostStatsDataSource.getInstance().release(dbcon);
} }
} }
private List<DataSet> queryPersonsBalances(Connection dbcon, long eventId) throws SQLException { @Inject
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, SQL_SELECT_BALANCES); @Named(Constants.STATEMENT_PROVIDER_GOLF)
try { @Statement(
for (int i = 1; i <= 5; i++) sql = "SELECT P.personID, P.prefix, P.fname, P.lname, P.suffix, "
fps.setIntegerU(i, eventId); + " TT.epersonID, SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance "
return fps.executeQuery().getAllRows(); + "FROM ("
} finally { + " SELECT ALL EP.personID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid "
fps.close(); + " FROM ~g~.EventPerson EP "
} + " LEFT JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) "
} + " WHERE EP.eventID=? "
+ " UNION ALL "
+ " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
+ " FROM ~g~.EventPerson EP "
private static final String SQL_SELECT_BALANCES = GolfSQL.changeSchema(new StringBuilder() + " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
.append("SELECT P.personID, P.prefix, P.fname, P.lname, P.suffix, ") + " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
.append("TT.epersonID, SUM(TT.expenses) expenses, SUM(TT.paid) paid, (SUM(TT.paid)-SUM(TT.expenses)) balance ") + " WHERE EP.eventID=? AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
.append("FROM (") + " UNION ALL "
.append("SELECT ALL EP.personID, EP.epersonID, IF(EB.projectedValue IS NULL, 0, EB.projectedValue) expenses, 0 paid ") + " SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid "
.append("FROM ~g~.EventPerson EP ") + " FROM ~g~.EventPerson EP "
.append("LEFT JOIN ~g~.EventBudget EB ON (EP.eventID=EB.eventID) ") + " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
.append("WHERE EP.eventID=? ") + " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
.append("UNION ALL ") + " WHERE EP.eventID=? AND EPO.itemID IS NOT NULL "
.append("SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid ") + " AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) "
.append("FROM ~g~.EventPerson EP ") + " AND EO.amount IS NOT NULL AND EO.waive IS FALSE "
.append("INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) ") + " UNION ALL "
.append("INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) ") + " SELECT ALL EP.personID, EP.epersonID, EOI.amount expenses, 0 paid "
.append("WHERE EP.eventID=? AND EPO.answer='Y' AND EO.amount IS NOT NULL AND EO.waive IS FALSE ") + " FROM ~g~.EventPerson EP "
.append("UNION ALL ") + " INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) "
.append("SELECT ALL EP.personID, EP.epersonID, EO.amount expenses, 0 paid ") + " INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) "
.append("FROM ~g~.EventPerson EP ") + " INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) "
.append("INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) ") + " WHERE EP.eventID=? AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL "
.append("INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) ") + " UNION ALL "
.append("WHERE EP.eventID=? AND EPO.itemID IS NOT NULL ") + " SELECT ALL EPP.personID, EP.epersonID, 0 expenses, EPP.amount paid "
.append("AND (EO.multiple IS FALSE OR EO.funded='option' OR EO.static IS NOT NULL) ") + " FROM ~g~.EventPersonPayment EPP "
.append("AND EO.amount IS NOT NULL AND EO.waive IS FALSE ") + " LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) "
.append("UNION ALL ") + " WHERE EPP.eventID=?) TT "
.append("SELECT ALL EP.personID, EP.epersonID, EOI.amount expenses, 0 paid ") + " INNER JOIN ~p~.Person P "
.append("FROM ~g~.EventPerson EP ") + "GROUP BY P.personID "
.append("INNER JOIN ~g~.EventPersonOption EPO ON (EP.epersonID=EPO.epersonID) ") + "ORDER BY P.lname, P.fname, P.suffix"
.append("INNER JOIN ~g~.EventOption EO ON (EPO.optionID=EO.optionID) ") )
.append("INNER JOIN ~g~.EventOptionItem EOI ON (EPO.itemID=EOI.itemID) ") private StatementProvider sqlSelectBalances;
.append("WHERE EP.eventID=? AND EO.waive IS FALSE AND EO.funded='selection' AND EOI.amount IS NOT NULL ")
.append("UNION ALL ")
.append("SELECT ALL EPP.personID, EP.epersonID, 0 expenses, EPP.amount paid ")
.append("FROM ~g~.EventPersonPayment EPP ")
.append("LEFT JOIN ~g~.EventPerson EP ON (EPP.eventID=EP.eventID AND EPP.personID=EP.personID) ")
.append("WHERE EPP.eventID=?) TT ")
.append("INNER JOIN ~p~.Person P ")
.append("GROUP BY P.personID ")
.append("ORDER BY P.lname, P.fname, P.suffix").toString());
} }

View File

@@ -1,15 +1,18 @@
package com.poststats.golf.service.db; package com.poststats.golf.service.db;
import com.brianlong.cache.CacheRetrievalException; import com.brianlong.cache.CacheRetrievalException;
import com.brianlong.sql.DataSet;
import com.brianlong.sql.FlexPreparedStatement; import com.brianlong.sql.FlexPreparedStatement;
import com.brianlong.util.FlexMap; import com.brianlong.util.FlexMap;
import com.poststats.golf.cache.GolferCache; import com.poststats.golf.api.Constants;
import com.poststats.golf.service.EventPersonService; import com.poststats.golf.service.EventPersonService;
import com.poststats.golf.sql.GolfSQL; import com.poststats.golf.service.PersonService;
import com.poststats.provider.Statement;
import com.poststats.provider.StatementProvider;
import com.poststats.service.ServiceException; import com.poststats.service.ServiceException;
import com.poststats.sql.PostStatsDataSource; import com.poststats.sql.PostStatsDataSource;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@@ -23,25 +26,37 @@ import java.util.Set;
@ApplicationScoped @ApplicationScoped
public class EventPersonServiceDAO implements EventPersonService { public class EventPersonServiceDAO implements EventPersonService {
@Inject
private PersonService golferService;
@Override @Override
public List<FlexMap> getPeople(long eventId, boolean includeDetails) { public List<FlexMap> getPeople(long eventId, boolean includeDetails) {
Connection dbcon = PostStatsDataSource.getInstance().acquire(true);
try { try {
return this.queryPersons(dbcon, eventId, includeDetails); return this.query(this.sqlSelectPersonIds, eventId, 2, includeDetails);
} catch (CacheRetrievalException cre) { } catch (CacheRetrievalException cre) {
throw new ServiceException(cre); throw new ServiceException(cre);
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
PostStatsDataSource.getInstance().release(dbcon);
} }
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(
sql = "SELECT epersonID, personID FROM ~g~.EventPerson WHERE eventID=? "
+ "UNION "
+ "SELECT DISTINCT NULL, personID "
+ "FROM ~g~.EventPersonAccessControl EPAC "
+ " LEFT JOIN ~g~.EventPerson EP ON (EPAC.eventID=EP.eventID AND EPAC.personID=EP.personID) "
+ "WHERE eventID=? AND EP.personID IS NULL "
)
private StatementProvider sqlSelectPersonIds;
@Override @Override
public List<FlexMap> getParticipants(long eventId, boolean includeDetails) { public List<FlexMap> getParticipants(long eventId, boolean includeDetails) {
Connection dbcon = PostStatsDataSource.getInstance().acquire(true); Connection dbcon = PostStatsDataSource.getInstance().acquire(true);
try { try {
return this.queryParticipants(dbcon, eventId, includeDetails); return this.query(this.sqlSelectParticipantIds, eventId, 1, includeDetails);
} catch (CacheRetrievalException cre) { } catch (CacheRetrievalException cre) {
throw new ServiceException(cre); throw new ServiceException(cre);
} catch (SQLException se) { } catch (SQLException se) {
@@ -51,33 +66,43 @@ public class EventPersonServiceDAO implements EventPersonService {
} }
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(sql = "SELECT epersonID, personID FROM ~g~.EventPerson WHERE eventID=?")
private StatementProvider sqlSelectParticipantIds;
@Override @Override
public Set<Long> getSeriesEventIdsAsParticipant(int seriesId, long personId) { public Set<Long> getSeriesEventIdsAsParticipant(int seriesId, long personId) {
Connection dbcon = PostStatsDataSource.getInstance().acquire(true);
try { try {
return this.querySeriesEventIdsAsParticipant(dbcon, seriesId, personId); FlexPreparedStatement fps = this.sqlSelectFellowParticipants.buildPreparedStatement();
try {
fps.setSmallintU(1, seriesId);
fps.setIntegerU(2, personId);
return fps.executeQuery().getFirstColumn(Long.class, new HashSet<>());
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
PostStatsDataSource.getInstance().release(dbcon);
} }
} }
private List<FlexMap> queryPersons(Connection dbcon, long eventId, boolean includeDetails) @Inject
throws CacheRetrievalException, SQLException { @Named(Constants.STATEMENT_PROVIDER_GOLF)
return this.query(dbcon, SQL_SELECT_PERSONS, eventId, 2, includeDetails); @Statement(
} sql = "SELECT DISTINCT EP2.personID "
+ "FROM ~g~.EventPerson EP1 "
+ " INNER JOIN Event E ON (EP1.eventID=E.eventID) "
+ " INNER JOIN EventPerson EP2 ON (E.eventID=EP2.eventID) "
+ "WHERE EP1.personID=? AND E.seriesID=?"
)
private StatementProvider sqlSelectFellowParticipants;
private List<FlexMap> queryParticipants(Connection dbcon, long eventId, boolean includeDetails) private List<FlexMap> query(StatementProvider provider, long eventId, int parameterCount, boolean includeDetails)
throws CacheRetrievalException, SQLException {
return this.query(dbcon, SQL_SELECT_PARTICIPANTS, eventId, 1, includeDetails);
}
private List<FlexMap> query(Connection dbcon, String sql, long eventId, int parameterCount, boolean includeDetails)
throws CacheRetrievalException, SQLException { throws CacheRetrievalException, SQLException {
Map<BigInteger, Long> epersonIdMap; Map<BigInteger, Long> epersonIdMap;
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, sql); FlexPreparedStatement fps = provider.buildPreparedStatement();
try { try {
for (int i = 1; i <= parameterCount; i++) for (int i = 1; i <= parameterCount; i++)
fps.setIntegerU(i, eventId); fps.setIntegerU(i, eventId);
@@ -86,7 +111,7 @@ public class EventPersonServiceDAO implements EventPersonService {
fps.close(); fps.close();
} }
Map<Long, DataSet> personMap = GolferCache.getInstance().get(epersonIdMap.values()); Map<Long, ? extends FlexMap> personMap = this.golferService.get(epersonIdMap.values());
List<FlexMap> rows = new ArrayList<>(personMap.size()); List<FlexMap> rows = new ArrayList<>(personMap.size());
for (Entry<BigInteger, Long> eperson : epersonIdMap.entrySet()) { for (Entry<BigInteger, Long> eperson : epersonIdMap.entrySet()) {
@@ -98,39 +123,4 @@ public class EventPersonServiceDAO implements EventPersonService {
return rows; return rows;
} }
private Set<Long> querySeriesEventIdsAsParticipant(Connection dbcon, int seriesId, long personId)
throws SQLException {
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, SQL_SELECT_SERIES_PARTICIPANTS);
try {
fps.setSmallintU(1, seriesId);
fps.setIntegerU(2, personId);
Set<Long> set = new HashSet<>();
fps.executeQuery().getFirstColumn(Long.class, set);
return set;
} finally {
fps.close();
}
}
private static final String SQL_SELECT_PARTICIPANTS = GolfSQL.changeSchema(
"SELECT epersonID, personID FROM ~g~.EventPerson WHERE eventID=?");
private static final String SQL_SELECT_SERIES_PARTICIPANTS = GolfSQL.changeSchema(
"SELECT DISTINCT EP2.personID "
+ "FROM ~g~.EventPerson EP1 "
+ " INNER JOIN Event E ON (EP1.eventID=E.eventID) "
+ " INNER JOIN EventPerson EP2 ON (E.eventID=EP2.eventID) "
+ "WHERE EP1.personID=? AND E.seriesID=?");
private static final String SQL_SELECT_PERSONS = GolfSQL.changeSchema(
"SELECT epersonID, personID FROM ~g~.EventPerson WHERE eventID=? "
+ "UNION "
+ "SELECT DISTINCT NULL, personID "
+ "FROM ~g~.EventPersonAccessControl EPAC "
+ " LEFT JOIN ~g~.EventPerson EP ON (EPAC.eventID=EP.eventID AND EPAC.personID=EP.personID) "
+ "WHERE eventID=? AND EP.personID IS NULL ");
} }

View File

@@ -5,8 +5,6 @@ import com.brianlong.sql.FlexPreparedStatement;
import com.brianlong.util.FlexMap; import com.brianlong.util.FlexMap;
import com.poststats.golf.api.Constants; import com.poststats.golf.api.Constants;
import com.poststats.golf.service.EventService; import com.poststats.golf.service.EventService;
import com.poststats.golf.sql.GolfDataSource;
import com.poststats.golf.sql.GolfSQL;
import com.poststats.provider.Statement; import com.poststats.provider.Statement;
import com.poststats.provider.StatementProvider; import com.poststats.provider.StatementProvider;
import com.poststats.service.ServiceException; import com.poststats.service.ServiceException;
@@ -14,12 +12,9 @@ import com.poststats.service.db.CacheableServiceDAO;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@@ -34,53 +29,69 @@ public class EventServiceDAO extends CacheableServiceDAO<Long> implements EventS
} }
@Override @Override
public Map<Long, ? extends FlexMap> getBySeriesId(int seriesId, boolean chronological) { public Set<Long> getIdsBySeriesId(int seriesId) {
List<Long> eventIds = new LinkedList<>();
Connection dbcon = GolfDataSource.getInstance().acquire(true);
try { try {
this.queryEventIds(dbcon, seriesId, chronological, eventIds); FlexPreparedStatement fps = this.sqlSelectIdsBySeriesId.buildPreparedStatement();
try {
fps.setSmallintU(1, seriesId);
return fps.executeQuery().getFirstColumn(Long.class, new HashSet<>());
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
GolfDataSource.getInstance().release(dbcon);
} }
return this.get(eventIds);
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(sql = "SELECT eventId FROM ~g~.Event WHERE seriesID=? ")
private StatementProvider sqlSelectIdsBySeriesId;
@Override @Override
public Set<Long> getIdsBySeriesId(int seriesId) { public Map<Long, DataSet> getBySeriesId(int seriesId) {
Set<Long> eventIds = new HashSet<>();
Connection dbcon = GolfDataSource.getInstance().acquire(true);
try { try {
this.queryEventIds(dbcon, seriesId, null, eventIds); FlexPreparedStatement fps = this.sqlSelectBySeriesId.buildPreparedStatement();
try {
fps.setSmallintU(1, seriesId);
return fps.executeQuery().getAllRows("eventID", Long.class);
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
GolfDataSource.getInstance().release(dbcon);
} }
return eventIds;
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(sql = "SELECT * FROM ~g~.Event WHERE seriesID=? ORDER BY E.liveline DESC ")
private StatementProvider sqlSelectBySeriesId;
@Override @Override
public Integer getSeriesId(long eventId) { public Integer getSeriesId(long eventId) {
FlexMap event = this.getIfHit(eventId); FlexMap event = this.getIfHit(eventId);
if (event != null) if (event != null)
return event.getInteger("seriesID"); return event.getInteger("seriesID");
Connection dbcon = GolfDataSource.getInstance().acquire(true);
try { try {
return this.querySeriesId(dbcon, eventId); FlexPreparedStatement fps = this.sqlSelectSeriesId.buildPreparedStatement();
try {
fps.setSmallintU(1, eventId);
return fps.executeQuery().getOne(Integer.class);
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
GolfDataSource.getInstance().release(dbcon);
} }
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(sql = "SELECT seriesID FROM ~g~.Event WHERE eventID=? ")
private StatementProvider sqlSelectSeriesId;
@Override @Override
protected long getCacheExpirationInSeconds() { protected long getCacheExpirationInSeconds() {
return this.defaultCacheExpirationInSeconds; return this.defaultCacheExpirationInSeconds;
@@ -103,7 +114,7 @@ public class EventServiceDAO extends CacheableServiceDAO<Long> implements EventS
sql = "SELECT EF.*, E.* " sql = "SELECT EF.*, E.* "
+ "FROM ~g~.Event E " + "FROM ~g~.Event E "
+ " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) " + " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) "
+ "WHERE eventID=? " + "WHERE E.eventID=? "
) )
private StatementProvider sqlSelectEvent; private StatementProvider sqlSelectEvent;
@@ -123,40 +134,8 @@ public class EventServiceDAO extends CacheableServiceDAO<Long> implements EventS
sql = "SELECT EF.*, E.* " sql = "SELECT EF.*, E.* "
+ "FROM ~g~.Event E " + "FROM ~g~.Event E "
+ " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) " + " INNER JOIN ~g~.EventFeature EF ON (E.eventID=EF.eventID) "
+ "WHERE eventID IN (??) " + "WHERE E.eventID IN (??) "
) )
private StatementProvider sqlSelectEvents; private StatementProvider sqlSelectEvents;
private void queryEventIds(Connection dbcon, int seriesId, Boolean chronological, Collection<Long> eventIds)
throws SQLException {
String sql = SQL_SELECT_EVENTS;
if (chronological != null)
sql += chronological ? SQL_ORDER_EVENTS_ASC : SQL_ORDER_EVENTS_DESC;
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, sql);
try {
fps.setSmallintU(1, seriesId);
fps.executeQuery().getFirstColumn(Long.class, eventIds);
} finally {
fps.close();
}
}
private static final String SQL_SELECT_EVENTS = GolfSQL.changeSchema(
"SELECT E.eventID FROM ~g~.Event E WHERE E.seriesID=? ");
private static final String SQL_ORDER_EVENTS_ASC = "ORDER BY E.liveline ASC";
private static final String SQL_ORDER_EVENTS_DESC = "ORDER BY E.liveline DESC";
private Integer querySeriesId(Connection dbcon, long eventId) throws SQLException {
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, SQL_SELECT_SERIES_REF);
try {
fps.setIntegerU(1, eventId);
return fps.executeQuery().getOne(Integer.class);
} finally {
fps.close();
}
}
private static final String SQL_SELECT_SERIES_REF = GolfSQL.changeSchema(
"SELECT seriesID FROM ~g~.Event WHERE eventID=?");
} }

View File

@@ -5,8 +5,6 @@ import com.brianlong.sql.FlexPreparedStatement;
import com.brianlong.util.FlexMap; import com.brianlong.util.FlexMap;
import com.poststats.golf.api.Constants; import com.poststats.golf.api.Constants;
import com.poststats.golf.service.SeriesService; import com.poststats.golf.service.SeriesService;
import com.poststats.golf.sql.GolfDataSource;
import com.poststats.golf.sql.GolfSQL;
import com.poststats.provider.Statement; import com.poststats.provider.Statement;
import com.poststats.provider.StatementProvider; import com.poststats.provider.StatementProvider;
import com.poststats.service.ServiceException; import com.poststats.service.ServiceException;
@@ -14,7 +12,6 @@ import com.poststats.service.db.CacheableServiceDAO;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@@ -31,16 +28,24 @@ public class SeriesServiceDAO extends CacheableServiceDAO<Integer> implements Se
@Override @Override
public DataSet getByEventId(long eventId) { public DataSet getByEventId(long eventId) {
Connection dbcon = GolfDataSource.getInstance().acquire(true);
try { try {
return this.querySeries(dbcon, eventId); FlexPreparedStatement fps = this.sqlSelectByEventId.buildPreparedStatement();
try {
fps.setIntegerU(1, eventId);
return fps.executeQuery().getNextRow();
} finally {
fps.close();
}
} catch (SQLException se) { } catch (SQLException se) {
throw new ServiceException(se); throw new ServiceException(se);
} finally {
GolfDataSource.getInstance().release(dbcon);
} }
} }
@Inject
@Named(Constants.STATEMENT_PROVIDER_GOLF)
@Statement(sql = "SELECT * FROM ~g~.Series WHERE eventID=? ")
private StatementProvider sqlSelectByEventId;
@Override @Override
protected long getCacheExpirationInSeconds() { protected long getCacheExpirationInSeconds() {
return this.defaultCacheExpirationInSeconds; return this.defaultCacheExpirationInSeconds;
@@ -77,19 +82,4 @@ public class SeriesServiceDAO extends CacheableServiceDAO<Integer> implements Se
@Statement(sql = "SELECT S.* FROM ~g~.Series S WHERE seriesID IN (??) ") @Statement(sql = "SELECT S.* FROM ~g~.Series S WHERE seriesID IN (??) ")
private StatementProvider sqlSelectSerieses; private StatementProvider sqlSelectSerieses;
private DataSet querySeries(Connection dbcon, long eventId) throws SQLException {
FlexPreparedStatement fps = new FlexPreparedStatement(dbcon, SQL_SELECT_SERIES_BY_EVENT_ID);
try {
fps.setIntegerU(1, eventId);
return fps.executeQuery().getNextRow();
} finally {
fps.close();
}
}
private static final String SQL_SELECT = GolfSQL.changeSchema(
"SELECT * FROM ~g~.Series ");
private static final String SQL_SELECT_SERIES_BY_EVENT_ID = GolfSQL.changeSchema(
"SELECT * FROM ~g~.Series WHERE eventID=? ");
} }