import map from 'it-map';
import { pipe } from 'it-pipe';
import { BaseDatastore } from './base.js';
/**
 * A datastore shim, that wraps around a given datastore, changing
 * the way keys look to the user, for example namespacing
 * keys, reversing them, etc.
 */
export class KeyTransformDatastore extends BaseDatastore {
    child;
    transform;
    constructor(child, transform) {
        super();
        this.child = child;
        this.transform = transform;
    }
    async put(key, val, options) {
        await this.child.put(this.transform.convert(key), val, options);
        return key;
    }
    async get(key, options) {
        return this.child.get(this.transform.convert(key), options);
    }
    async has(key, options) {
        return this.child.has(this.transform.convert(key), options);
    }
    async delete(key, options) {
        await this.child.delete(this.transform.convert(key), options);
    }
    async *putMany(source, options = {}) {
        const transform = this.transform;
        const child = this.child;
        yield* pipe(source, async function* (source) {
            yield* map(source, ({ key, value }) => ({
                key: transform.convert(key),
                value
            }));
        }, async function* (source) {
            yield* child.putMany(source, options);
        }, async function* (source) {
            yield* map(source, key => transform.invert(key));
        });
    }
    async *getMany(source, options = {}) {
        const transform = this.transform;
        const child = this.child;
        yield* pipe(source, async function* (source) {
            yield* map(source, key => transform.convert(key));
        }, async function* (source) {
            yield* child.getMany(source, options);
        }, async function* (source) {
            yield* map(source, ({ key, value }) => ({
                key: transform.invert(key),
                value
            }));
        });
    }
    async *deleteMany(source, options = {}) {
        const transform = this.transform;
        const child = this.child;
        yield* pipe(source, async function* (source) {
            yield* map(source, key => transform.convert(key));
        }, async function* (source) {
            yield* child.deleteMany(source, options);
        }, async function* (source) {
            yield* map(source, key => transform.invert(key));
        });
    }
    batch() {
        const b = this.child.batch();
        return {
            put: (key, value) => {
                b.put(this.transform.convert(key), value);
            },
            delete: (key) => {
                b.delete(this.transform.convert(key));
            },
            commit: async (options) => {
                await b.commit(options);
            }
        };
    }
    query(q, options) {
        const query = {
            ...q
        };
        query.filters = (query.filters ?? []).map(filter => {
            return ({ key, value }) => filter({ key: this.transform.convert(key), value });
        });
        const { prefix } = q;
        if (prefix != null && prefix !== '/') {
            delete query.prefix;
            query.filters.push(({ key }) => {
                return this.transform.invert(key).toString().startsWith(prefix);
            });
        }
        if (query.orders != null) {
            query.orders = query.orders.map(order => {
                return (a, b) => order({ key: this.transform.invert(a.key), value: a.value }, { key: this.transform.invert(b.key), value: b.value });
            });
        }
        return map(this.child.query(query, options), ({ key, value }) => {
            return {
                key: this.transform.invert(key),
                value
            };
        });
    }
    queryKeys(q, options) {
        const query = {
            ...q
        };
        query.filters = (query.filters ?? []).map(filter => {
            return (key) => filter(this.transform.convert(key));
        });
        const { prefix } = q;
        if (prefix != null && prefix !== '/') {
            delete query.prefix;
            query.filters.push((key) => {
                return this.transform.invert(key).toString().startsWith(prefix);
            });
        }
        if (query.orders != null) {
            query.orders = query.orders.map(order => {
                return (a, b) => order(this.transform.invert(a), this.transform.invert(b));
            });
        }
        return map(this.child.queryKeys(query, options), key => {
            return this.transform.invert(key);
        });
    }
}
//# sourceMappingURL=keytransform.js.map