mirror of
https://github.com/Qortal/qortal.git
synced 2025-03-30 09:05:52 +00:00
Now using ATv2 dated 20181101172102 ATData now uses byte[] creatorPublicKey instead of String creator. TransactionData now has hashCode() and equals() methods, which is needed for new Transaction Comparator, used to sort transactions within a block, AT-first, then timestamp, then signature. AT-Transactions generate their own signatures using SHA2-256 of serialized data. Arbitrary Transactions try to clean up their files when orphaned. Deploy AT Transactions now check creation bytes (even for old v1 ATs). Deprecated Transaction.getBlock() as it doesn't seem used and would be better to simply have getHeight() rather than a method that 'knows too much' about Blocks/BlockData. Corresponding TransactionRepository.getBlockDataFromSignature() also deprecated. Loads more comments. Tidied up some SQL: mainly correcting case, moving PRIMARY KEY clauses to end of CREATE TABLE, removing unnecessary columns from indexes. Added "type" column to TransactionCreatorIndex so users can find their transactions and optionally filter by type. In BlockTransactions table, transaction_signature is now UNIQUE as a transaction cannot be included in more than one block. Various AT-related HSQLDB table and index changes. ArbitraryTransactions transformer fixed to always return a list of payments, even if empty. (Previously could return null which broke things). Added simplistic block generator. NOTE: unit tests broken due to pending upgrade to JUnit 5
171 lines
5.7 KiB
Java
171 lines
5.7 KiB
Java
package repository.hsqldb;
|
|
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Timestamp;
|
|
import java.util.ArrayList;
|
|
import java.util.Calendar;
|
|
import java.util.List;
|
|
|
|
import data.voting.PollData;
|
|
import data.voting.PollOptionData;
|
|
import data.voting.VoteOnPollData;
|
|
import repository.VotingRepository;
|
|
import repository.DataException;
|
|
|
|
public class HSQLDBVotingRepository implements VotingRepository {
|
|
|
|
protected HSQLDBRepository repository;
|
|
|
|
public HSQLDBVotingRepository(HSQLDBRepository repository) {
|
|
this.repository = repository;
|
|
}
|
|
|
|
// Polls
|
|
|
|
@Override
|
|
public PollData fromPollName(String pollName) throws DataException {
|
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT description, creator, owner, published FROM Polls WHERE poll_name = ?", pollName)) {
|
|
if (resultSet == null)
|
|
return null;
|
|
|
|
String description = resultSet.getString(1);
|
|
byte[] creatorPublicKey = resultSet.getBytes(2);
|
|
String owner = resultSet.getString(3);
|
|
long published = resultSet.getTimestamp(4, Calendar.getInstance(HSQLDBRepository.UTC)).getTime();
|
|
|
|
try (ResultSet optionsResultSet = this.repository
|
|
.checkedExecute("SELECT option_name FROM PollOptions WHERE poll_name = ? ORDER BY option_index ASC", pollName)) {
|
|
if (optionsResultSet == null)
|
|
return null;
|
|
|
|
List<PollOptionData> pollOptions = new ArrayList<PollOptionData>();
|
|
|
|
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
|
|
do {
|
|
String optionName = optionsResultSet.getString(1);
|
|
|
|
pollOptions.add(new PollOptionData(optionName));
|
|
} while (optionsResultSet.next());
|
|
|
|
return new PollData(creatorPublicKey, owner, pollName, description, pollOptions, published);
|
|
}
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to fetch poll from repository", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean pollExists(String pollName) throws DataException {
|
|
try {
|
|
return this.repository.exists("Polls", "poll_name = ?", pollName);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to check for poll in repository", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void save(PollData pollData) throws DataException {
|
|
HSQLDBSaver saveHelper = new HSQLDBSaver("Polls");
|
|
|
|
saveHelper.bind("poll_name", pollData.getPollName()).bind("description", pollData.getDescription()).bind("creator", pollData.getCreatorPublicKey())
|
|
.bind("owner", pollData.getOwner()).bind("published", new Timestamp(pollData.getPublished()));
|
|
|
|
try {
|
|
saveHelper.execute(this.repository);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to save poll into repository", e);
|
|
}
|
|
|
|
// Now attempt to save poll options
|
|
List<PollOptionData> pollOptions = pollData.getPollOptions();
|
|
for (int optionIndex = 0; optionIndex < pollOptions.size(); ++optionIndex) {
|
|
PollOptionData pollOptionData = pollOptions.get(optionIndex);
|
|
|
|
HSQLDBSaver optionSaveHelper = new HSQLDBSaver("PollOptions");
|
|
|
|
optionSaveHelper.bind("poll_name", pollData.getPollName()).bind("option_index", optionIndex).bind("option_name", pollOptionData.getOptionName());
|
|
|
|
try {
|
|
optionSaveHelper.execute(this.repository);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to save poll option into repository", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void delete(String pollName) throws DataException {
|
|
// NOTE: The corresponding rows in PollOptions are deleted automatically by the database thanks to "ON DELETE CASCADE" in the PollOptions' FOREIGN KEY
|
|
// definition.
|
|
try {
|
|
this.repository.delete("Polls", "poll_name = ?", pollName);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to delete poll from repository", e);
|
|
}
|
|
}
|
|
|
|
// Votes
|
|
|
|
@Override
|
|
public List<VoteOnPollData> getVotes(String pollName) throws DataException {
|
|
List<VoteOnPollData> votes = new ArrayList<VoteOnPollData>();
|
|
|
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT voter, option_index FROM PollVotes WHERE poll_name = ?", pollName)) {
|
|
if (resultSet == null)
|
|
return votes;
|
|
|
|
// NOTE: do-while because checkedExecute() above has already called rs.next() for us
|
|
do {
|
|
byte[] voterPublicKey = resultSet.getBytes(1);
|
|
int optionIndex = resultSet.getInt(2);
|
|
|
|
votes.add(new VoteOnPollData(pollName, voterPublicKey, optionIndex));
|
|
} while (resultSet.next());
|
|
|
|
return votes;
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to fetch poll votes from repository", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public VoteOnPollData getVote(String pollName, byte[] voterPublicKey) throws DataException {
|
|
try (ResultSet resultSet = this.repository.checkedExecute("SELECT option_index FROM PollVotes WHERE poll_name = ? AND voter = ?", pollName,
|
|
voterPublicKey)) {
|
|
if (resultSet == null)
|
|
return null;
|
|
|
|
int optionIndex = resultSet.getInt(1);
|
|
|
|
return new VoteOnPollData(pollName, voterPublicKey, optionIndex);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to fetch poll vote from repository", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void save(VoteOnPollData voteOnPollData) throws DataException {
|
|
HSQLDBSaver saveHelper = new HSQLDBSaver("PollVotes");
|
|
|
|
saveHelper.bind("poll_name", voteOnPollData.getPollName()).bind("voter", voteOnPollData.getVoterPublicKey()).bind("option_index",
|
|
voteOnPollData.getOptionIndex());
|
|
|
|
try {
|
|
saveHelper.execute(this.repository);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to save poll vote into repository", e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void delete(String pollName, byte[] voterPublicKey) throws DataException {
|
|
try {
|
|
this.repository.delete("PollVotes", "poll_name = ? AND voter = ?", pollName, voterPublicKey);
|
|
} catch (SQLException e) {
|
|
throw new DataException("Unable to delete poll vote from repository", e);
|
|
}
|
|
}
|
|
|
|
}
|