content: package userservice.dao;
  
  import io.activej.promise.Promise;
  import io.activej.reactor.AbstractReactive;
  import io.activej.reactor.Reactor;
  import org.jetbrains.annotations.Nullable;
  
  import javax.sql.DataSource;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.util.LinkedHashMap;
  import java.util.Map;
  import java.util.concurrent.Executor;
  
  import static io.activej.reactor.Reactive.checkInReactorThread;
  
  /**
   * Implementation of {@link IUserDao} which uses generic SQL commands for operation
   */
  public final class SqlUserDao extends AbstractReactive
  	implements IUserDao {
  	private final DataSource dataSource;
  	private final Executor executor;
  
  	public SqlUserDao(Reactor reactor, DataSource dataSource, Executor executor) {
  		super(reactor);
  		this.dataSource = dataSource;
  		this.executor = executor;
  	}
  
  	@Override
  	public Promise<@Nullable User> get(long id) {
  		checkInReactorThread(this);
  		return Promise.ofBlocking(executor, () -> {
  			try (
  				Connection connection = dataSource.getConnection();
  				PreparedStatement statement = connection.prepareStatement("""
  					SELECT first_name, last_name
  					FROM users WHERE id = ?
  					""")
  			) {
  				statement.setLong(1, id);
  				try (ResultSet resultSet = statement.executeQuery()) {
  					if (!resultSet.next()) {
  						return null;
  					}
  
  					String firstName = resultSet.getString(1);
  					String lastName = resultSet.getString(2);
  					return new User(firstName, lastName);
  				}
  			}
  		});
  	}
  
  	@Override
  	public Promise<Map<Long, User>> getAll() {
  		checkInReactorThread(this);
  		return Promise.ofBlocking(executor, () -> {
  			try (
  				Connection connection = dataSource.getConnection();
  				PreparedStatement statement = connection.prepareStatement("""
  					SELECT *
  					FROM users
  					""")
  			) {
  				try (ResultSet resultSet = statement.executeQuery()) {
  					Map<Long, User> result = new LinkedHashMap<>();
  
  					while (resultSet.next()) {
  						long id = resultSet.getLong(1);
  						String firstName = resultSet.getString(2);
  						String lastName = resultSet.getString(3);
  
  						result.put(id, new User(firstName, lastName));
  					}
  					return result;
  				}
  			}
  		});
  	}
  
  	@Override
  	public Promise<Void> addUser(User user) {
  		checkInReactorThread(this);
  		return Promise.ofBlocking(executor, () -> {
  			try (
  				Connection connection = dataSource.getConnection();
  				PreparedStatement statement = connection.prepareStatement("""
  					INSERT INTO users(first_name, last_name)
  					VALUES(?, ?)
  					""")
  			) {
  				statement.setString(1, user.firstName());
  				statement.setString(2, user.lastName());
  
  				statement.executeUpdate();
  			}
  		});
  	}
  
  	@Override
  	public Promise<Boolean> updateUser(long id, User newUser) {
  		checkInReactorThread(this);
  		return Promise.ofBlocking(executor, () -> {
  			try (
  				Connection connection = dataSource.getConnection();
  				PreparedStatement statement = connection.prepareStatement("""
  					UPDATE users
  					SET first_name=?, last_name= ?\s
  					WHERE id = ?
  					""")
  			) {
  				statement.setString(1, newUser.firstName());
  				statement.setString(2, newUser.lastName());
  				statement.setLong(3, id);
  
  				return statement.executeUpdate() != 0;
  			}
  		});
  	}
  
  	@Override
  	public Promise<Boolean> deleteUser(long id) {
  		checkInReactorThread(this);
  		return Promise.ofBlocking(executor, () -> {
  			try (
  				Connection connection = dataSource.getConnection();
  				PreparedStatement statement = connection.prepareStatement("""
  					DELETE FROM users
  					WHERE id = ?
  					""")
  			) {
  				statement.setLong(1, id);
  
  				return statement.executeUpdate() != 0;
  			}
  		});
  	}
  }
  