class Neo4jStorageAccessor extends AbstractStorageAccessor {
    private final String collectionName;
    private final Driver driver;
    private final String databaseName;

    public Neo4jStorageAccessor(@NonNull Driver driver, @NonNull String collectionName, @Nullable String databaseName) {
        this.collectionName = requireNonNull(collectionName, "collectionName can not be null");
        this.driver = requireNonNull(driver, "driver can not be null");
        this.databaseName = databaseName;
        createLockNameUniqueConstraint();
    }

    private void createLockNameUniqueConstraint() {<FILL_FUNCTION_BODY>}

    @Override
    public boolean insertRecord(@NonNull LockConfiguration lockConfiguration) {
        // Try to insert if the record does not exists
        String cypher = String.format(
                "CREATE (lock:%s {name: $lockName, lock_until: $lockUntil, locked_at: $now, locked_by: $lockedBy })",
                collectionName);
        Map<String, Object> parameters = createParameterMap(lockConfiguration);
        return executeCommand(
                cypher,
                result -> {
                    int insertedNodes = result.consume().counters().nodesCreated();
                    return insertedNodes > 0;
                },
                parameters,
                this::handleInsertionException);
    }

    private Map<String, Object> createParameterMap(@NonNull LockConfiguration lockConfiguration) {
        return Map.of(
                "lockName",
                lockConfiguration.getName(),
                "lockedBy",
                getHostname(),
                "now",
                ClockProvider.now().toString(),
                "lockUntil",
                lockConfiguration.getLockAtMostUntil().toString());
    }

    @Override
    public boolean updateRecord(@NonNull LockConfiguration lockConfiguration) {
        String cypher = String.format(
                "MATCH (lock:%s) " + "WHERE lock.name = $lockName AND lock.lock_until <= $now "
                        + "SET lock._LOCK_ = true " + "WITH lock as l " + "WHERE l.lock_until <= $now "
                        + "SET l.lock_until = $lockUntil, l.locked_at = $now, l.locked_by = $lockedBy "
                        + "REMOVE l._LOCK_ ",
                collectionName);
        Map<String, Object> parameters = createParameterMap(lockConfiguration);
        return executeCommand(
                cypher,
                statement -> {
                    int updatedProperties = statement.consume().counters().propertiesSet();
                    return updatedProperties > 1; // ignore explicit lock when counting the updated properties
                },
                parameters,
                this::handleUpdateException);
    }

    @Override
    public boolean extend(@NonNull LockConfiguration lockConfiguration) {
        String cypher = String.format(
                "MATCH (lock:%s) "
                        + "WHERE lock.name = $lockName AND lock.locked_by = $lockedBy AND lock.lock_until > $now "
                        + "SET lock._LOCK_ = true " + "WITH lock as l "
                        + "WHERE l.name = $lockName AND l.locked_by = $lockedBy AND l.lock_until > $now "
                        + "SET l.lock_until = $lockUntil " + "REMOVE l._LOCK_ ",
                collectionName);
        Map<String, Object> parameters = createParameterMap(lockConfiguration);

        logger.debug("Extending lock={} until={}", lockConfiguration.getName(), lockConfiguration.getLockAtMostUntil());

        return executeCommand(
                cypher,
                statement -> {
                    int updatedProperties = statement.consume().counters().propertiesSet();
                    return updatedProperties > 1; // ignore the explicit lock when counting the updated properties
                },
                parameters,
                this::handleUnlockException);
    }

    @Override
    public void unlock(@NonNull LockConfiguration lockConfiguration) {
        String cypher = String.format(
                "MATCH (lock:%s) WHERE lock.name = $lockName " + "SET lock.lock_until = $lockUntil ", collectionName);
        Map<String, Object> parameters = Map.of(
                "lockName",
                lockConfiguration.getName(),
                "lockUntil",
                lockConfiguration.getUnlockTime().toString());
        executeCommand(cypher, statement -> null, parameters, this::handleUnlockException);
    }

    private <T> T executeCommand(
            String cypher,
            Function<Result, T> body,
            Map<String, Object> parameters,
            BiFunction<String, Exception, T> exceptionHandler) {
        try (Session session = getSession();
                Transaction transaction = session.beginTransaction()) {
            Result result = transaction.run(cypher, parameters);
            T apply = body.apply(result);
            transaction.commit();
            return apply;
        } catch (Exception e) {
            return exceptionHandler.apply(cypher, e);
        }
    }

    private Session getSession() {
        return databaseName == null ? driver.session() : driver.session(SessionConfig.forDatabase(databaseName));
    }

    boolean handleInsertionException(String cypher, Exception e) {
        // lock record already exists
        return false;
    }

    boolean handleUpdateException(String cypher, Exception e) {
        throw new LockException("Unexpected exception when locking", e);
    }

    boolean handleUnlockException(String cypher, Exception e) {
        throw new LockException("Unexpected exception when unlocking", e);
    }
}

        try (Session session = getSession();
                Transaction transaction = session.beginTransaction()) {
            transaction.run(String.format(
                    "CREATE CONSTRAINT UNIQUE_%s_name IF NOT EXISTS FOR (lock:%s) REQUIRE lock.name IS UNIQUE",
                    collectionName, collectionName));
            transaction.commit();
        }
    
<methods>public non-sealed void <init>() <variables>protected final Logger logger