"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetRepository = void 0;
const common_1 = require("@nestjs/common");
const kysely_1 = require("kysely");
const postgres_1 = require("kysely/helpers/postgres");
const lodash_1 = require("lodash");
const nestjs_kysely_1 = require("nestjs-kysely");
const decorators_1 = require("../decorators");
const enum_1 = require("../enum");
const database_1 = require("../utils/database");
const misc_1 = require("../utils/misc");
const distinctLocked = (eb, columns) => (0, kysely_1.sql) `nullif(array(select distinct unnest(${eb.ref('asset_exif.lockedProperties')} || ${columns})), '{}')`;
const getBoundingCircle = (bbox) => {
    const { west, south, east, north } = bbox;
    const eastUnwrapped = west <= east ? east : east + 360;
    const centerLongitude = (((west + eastUnwrapped) / 2 + 540) % 360) - 180;
    const centerLatitude = (south + north) / 2;
    const radius = (0, kysely_1.sql) `greatest(
    earth_distance(ll_to_earth_public(${centerLatitude}, ${centerLongitude}), ll_to_earth_public(${south}, ${west})),
    earth_distance(ll_to_earth_public(${centerLatitude}, ${centerLongitude}), ll_to_earth_public(${south}, ${east})),
    earth_distance(ll_to_earth_public(${centerLatitude}, ${centerLongitude}), ll_to_earth_public(${north}, ${west})),
    earth_distance(ll_to_earth_public(${centerLatitude}, ${centerLongitude}), ll_to_earth_public(${north}, ${east}))
  )`;
    return { centerLatitude, centerLongitude, radius };
};
const withBoundingBox = (qb, bbox) => {
    const { west, south, east, north } = bbox;
    const withLatitude = qb.where('asset_exif.latitude', '>=', south).where('asset_exif.latitude', '<=', north);
    if (west <= east) {
        return withLatitude.where('asset_exif.longitude', '>=', west).where('asset_exif.longitude', '<=', east);
    }
    return withLatitude.where((eb) => eb.or([eb('asset_exif.longitude', '>=', west), eb('asset_exif.longitude', '<=', east)]));
};
let AssetRepository = class AssetRepository {
    db;
    constructor(db) {
        this.db = db;
    }
    async upsertExif({ exif, audio, video, keyframes, lockedPropertiesBehavior }) {
        let query = this.db;
        if (audio) {
            query = this.db.with('audio', (qb) => qb
                .insertInto('asset_audio')
                .values(audio)
                .onConflict((oc) => oc.column('assetId').doUpdateSet(({ ref }) => ({
                bitrate: ref('asset_audio.bitrate'),
                index: ref('asset_audio.index'),
                profile: ref('asset_audio.profile'),
                codecName: ref('asset_audio.codecName'),
            }))));
        }
        if (video) {
            query = query.with('video', (qb) => qb
                .insertInto('asset_video')
                .values(video)
                .onConflict((oc) => oc.column('assetId').doUpdateSet(({ ref }) => ({
                bitrate: ref('asset_video.bitrate'),
                timeBase: ref('asset_video.timeBase'),
                index: ref('asset_video.index'),
                profile: ref('asset_video.profile'),
                level: ref('asset_video.level'),
                colorPrimaries: ref('asset_video.colorPrimaries'),
                colorTransfer: ref('asset_video.colorTransfer'),
                colorMatrix: ref('asset_video.colorMatrix'),
                dvProfile: ref('asset_video.dvProfile'),
                dvLevel: ref('asset_video.dvLevel'),
                dvBlSignalCompatibilityId: ref('asset_video.dvBlSignalCompatibilityId'),
                codecName: ref('asset_video.codecName'),
                formatName: ref('asset_video.formatName'),
                formatLongName: ref('asset_video.formatLongName'),
                pixelFormat: ref('asset_video.pixelFormat'),
            }))));
        }
        if (keyframes) {
            query = query.with('keyframe', (qb) => qb
                .insertInto('asset_keyframe')
                .values(keyframes)
                .onConflict((oc) => oc.column('assetId').doUpdateSet(({ ref }) => ({
                pts: ref('asset_keyframe.pts'),
                accDuration: ref('asset_keyframe.accDuration'),
                ownDuration: ref('asset_keyframe.ownDuration'),
                totalDuration: ref('asset_keyframe.totalDuration'),
                packetCount: ref('asset_keyframe.packetCount'),
                outputFrames: ref('asset_keyframe.outputFrames'),
            }))));
        }
        await query
            .insertInto('asset_exif')
            .values(exif)
            .onConflict((oc) => oc.column('assetId').doUpdateSet((eb) => {
            const updateLocked = (col) => eb.ref(`excluded.${col}`);
            const skipLocked = (col) => eb
                .case()
                .when((0, kysely_1.sql) `${col}`, '=', eb.fn.any('asset_exif.lockedProperties'))
                .then(eb.ref(`asset_exif.${col}`))
                .else(eb.ref(`excluded.${col}`))
                .end();
            const ref = lockedPropertiesBehavior === 'skip' ? skipLocked : updateLocked;
            return {
                ...(0, database_1.removeUndefinedKeys)({
                    description: ref('description'),
                    exifImageWidth: ref('exifImageWidth'),
                    exifImageHeight: ref('exifImageHeight'),
                    fileSizeInByte: ref('fileSizeInByte'),
                    orientation: ref('orientation'),
                    dateTimeOriginal: ref('dateTimeOriginal'),
                    modifyDate: ref('modifyDate'),
                    timeZone: ref('timeZone'),
                    latitude: ref('latitude'),
                    longitude: ref('longitude'),
                    projectionType: ref('projectionType'),
                    city: ref('city'),
                    livePhotoCID: ref('livePhotoCID'),
                    autoStackId: ref('autoStackId'),
                    state: ref('state'),
                    country: ref('country'),
                    make: ref('make'),
                    model: ref('model'),
                    lensModel: ref('lensModel'),
                    fNumber: ref('fNumber'),
                    focalLength: ref('focalLength'),
                    iso: ref('iso'),
                    exposureTime: ref('exposureTime'),
                    profileDescription: ref('profileDescription'),
                    colorspace: ref('colorspace'),
                    bitsPerSample: ref('bitsPerSample'),
                    rating: ref('rating'),
                    fps: ref('fps'),
                    tags: ref('tags'),
                    lockedProperties: lockedPropertiesBehavior === 'append'
                        ? distinctLocked(eb, exif.lockedProperties ?? null)
                        : ref('lockedProperties'),
                }, exif),
            };
        }))
            .execute();
    }
    async updateAllExif(ids, options) {
        if (ids.length === 0) {
            return;
        }
        await this.db
            .updateTable('asset_exif')
            .set((eb) => ({
            ...options,
            lockedProperties: distinctLocked(eb, Object.keys(options)),
        }))
            .where('assetId', 'in', ids)
            .execute();
    }
    updateDateTimeOriginal(ids, delta, timeZone) {
        return this.db
            .updateTable('asset_exif')
            .set((eb) => ({
            dateTimeOriginal: (0, kysely_1.sql) `"dateTimeOriginal" + ${(delta ?? 0) + ' minute'}::interval`,
            timeZone,
            lockedProperties: distinctLocked(eb, ['dateTimeOriginal', 'timeZone']),
        }))
            .where('assetId', 'in', ids)
            .returning(['assetId', 'dateTimeOriginal', 'timeZone'])
            .execute();
    }
    unlockProperties(assetId, properties) {
        return this.db
            .updateTable('asset_exif')
            .where('assetId', '=', assetId)
            .set((eb) => ({
            lockedProperties: (0, kysely_1.sql) `nullif(array(select distinct property from unnest(${eb.ref('asset_exif.lockedProperties')}) property where not property = any(${properties})), '{}')`,
        }))
            .execute();
    }
    async upsertJobStatus(...jobStatus) {
        if (jobStatus.length === 0) {
            return;
        }
        const values = jobStatus.map((row) => ({ ...row, assetId: (0, database_1.asUuid)(row.assetId) }));
        await this.db
            .insertInto('asset_job_status')
            .values(values)
            .onConflict((oc) => oc.column('assetId').doUpdateSet((eb) => (0, database_1.removeUndefinedKeys)({
            duplicatesDetectedAt: eb.ref('excluded.duplicatesDetectedAt'),
            facesRecognizedAt: eb.ref('excluded.facesRecognizedAt'),
            metadataExtractedAt: eb.ref('excluded.metadataExtractedAt'),
            ocrAt: eb.ref('excluded.ocrAt'),
        }, values[0])))
            .execute();
    }
    getMetadata(assetId) {
        return this.db
            .selectFrom('asset_metadata')
            .select(['key', 'value', 'updatedAt'])
            .where('assetId', '=', assetId)
            .execute();
    }
    upsertMetadata(id, items) {
        if (items.length === 0) {
            return [];
        }
        return this.db
            .insertInto('asset_metadata')
            .values(items.map((item) => ({ assetId: id, ...item })))
            .onConflict((oc) => oc
            .columns(['assetId', 'key'])
            .doUpdateSet((eb) => ({ key: eb.ref('excluded.key'), value: eb.ref('excluded.value') })))
            .returning(['key', 'value', 'updatedAt'])
            .execute();
    }
    upsertBulkMetadata(items) {
        return this.db
            .insertInto('asset_metadata')
            .values(items)
            .onConflict((oc) => oc
            .columns(['assetId', 'key'])
            .doUpdateSet((eb) => ({ key: eb.ref('excluded.key'), value: eb.ref('excluded.value') })))
            .returning(['assetId', 'key', 'value', 'updatedAt'])
            .execute();
    }
    getMetadataByKey(assetId, key) {
        return this.db
            .selectFrom('asset_metadata')
            .select(['key', 'value', 'updatedAt'])
            .where('assetId', '=', assetId)
            .where('key', '=', key)
            .executeTakeFirst();
    }
    async deleteMetadataByKey(id, key) {
        await this.db.deleteFrom('asset_metadata').where('assetId', '=', id).where('key', '=', key).execute();
    }
    async deleteBulkMetadata(items) {
        if (items.length === 0) {
            return;
        }
        await this.db.transaction().execute(async (tx) => {
            for (const { assetId, key } of items) {
                await tx.deleteFrom('asset_metadata').where('assetId', '=', assetId).where('key', '=', key).execute();
            }
        });
    }
    create(asset) {
        return this.db.insertInto('asset').values(asset).returningAll().executeTakeFirstOrThrow();
    }
    async createAll(assets) {
        const ids = await this.db.insertInto('asset').values(assets).returning('id').execute();
        return ids.map(({ id }) => id);
    }
    getByDayOfYear(ownerIds, { year, day, month }) {
        return this.db
            .with('res', (qb) => qb
            .with('today', (qb) => qb
            .selectFrom((eb) => eb
            .fn('generate_series', [
            (0, kysely_1.sql) `(select date_part('year', min(("localDateTime" at time zone 'UTC')::date))::int from asset)`,
            (0, kysely_1.sql) `${year - 1}`,
        ])
            .as('year'))
            .select((eb) => eb.fn('make_date', [(0, kysely_1.sql) `year::int`, (0, kysely_1.sql) `${month}::int`, (0, kysely_1.sql) `${day}::int`]).as('date')))
            .selectFrom('today')
            .innerJoinLateral((qb) => qb
            .selectFrom('asset')
            .select(['asset.id', 'asset.localDateTime'])
            .innerJoin('asset_job_status', 'asset.id', 'asset_job_status.assetId')
            .where((0, kysely_1.sql) `(asset."localDateTime" at time zone 'UTC')::date`, '=', (0, kysely_1.sql) `today.date`)
            .where('asset.ownerId', '=', (0, database_1.anyUuid)(ownerIds))
            .where('asset.visibility', '=', enum_1.AssetVisibility.Timeline)
            .where((eb) => eb.exists((qb) => qb
            .selectFrom('asset_file')
            .whereRef('assetId', '=', 'asset.id')
            .where('asset_file.type', '=', enum_1.AssetFileType.Preview)))
            .where('asset.deletedAt', 'is', null)
            .orderBy((0, kysely_1.sql) `(asset."localDateTime" at time zone 'UTC')::date`, 'desc')
            .limit(20)
            .as('a'), (join) => join.onTrue())
            .selectAll('a'))
            .selectFrom('res')
            .select((0, kysely_1.sql) `date_part('year', ("localDateTime" at time zone 'UTC')::date)::int`.as('year'))
            .select((eb) => eb.fn.jsonAgg(eb.table('res')).as('assets'))
            .groupBy((0, kysely_1.sql) `("localDateTime" at time zone 'UTC')::date`)
            .orderBy((0, kysely_1.sql) `("localDateTime" at time zone 'UTC')::date`, 'desc')
            .execute();
    }
    getByIds(ids) {
        return this.db.selectFrom('asset').selectAll('asset').where('asset.id', '=', (0, database_1.anyUuid)(ids)).execute();
    }
    getByIdsWithAllRelationsButStacks(ids) {
        return this.db
            .selectFrom('asset')
            .selectAll('asset')
            .select(database_1.withFacesAndPeople)
            .select(database_1.withTags)
            .$call(database_1.withExif)
            .where('asset.id', '=', (0, database_1.anyUuid)(ids))
            .execute();
    }
    async deleteAll(ownerId) {
        await this.db.deleteFrom('asset').where('ownerId', '=', ownerId).execute();
    }
    getByLibraryIdAndOriginalPath(libraryId, originalPath) {
        return this.db
            .selectFrom('asset')
            .selectAll('asset')
            .where('libraryId', '=', (0, database_1.asUuid)(libraryId))
            .where('originalPath', '=', originalPath)
            .limit(1)
            .executeTakeFirst();
    }
    async getLivePhotoCount(motionId) {
        const [{ count }] = await this.db
            .selectFrom('asset')
            .select((eb) => eb.fn.countAll().as('count'))
            .where('livePhotoVideoId', '=', (0, database_1.asUuid)(motionId))
            .execute();
        return count;
    }
    getFileSamples() {
        return this.db.selectFrom('asset_file').select(['assetId', 'path']).limit(kysely_1.sql.lit(3)).execute();
    }
    getForCopy(id) {
        return this.db
            .selectFrom('asset')
            .select(['id', 'stackId', 'originalPath', 'isFavorite'])
            .select(database_1.withFiles)
            .where('id', '=', (0, database_1.asUuid)(id))
            .limit(1)
            .executeTakeFirst();
    }
    getById(id, { exifInfo, faces, files, library, owner, smartSearch, stack, tags, edits } = {}) {
        return this.db
            .selectFrom('asset')
            .selectAll('asset')
            .where('asset.id', '=', (0, database_1.asUuid)(id))
            .$if(!!exifInfo, database_1.withExif)
            .$if(!!faces, (qb) => qb.select(faces?.person ? database_1.withFacesAndPeople : database_1.withFaces).$narrowType())
            .$if(!!library, (qb) => qb.select(database_1.withLibrary))
            .$if(!!owner, (qb) => qb.select(database_1.withOwner))
            .$if(!!smartSearch, database_1.withSmartSearch)
            .$if(!!stack, (qb) => qb
            .leftJoin('stack', 'stack.id', 'asset.stackId')
            .$if(!stack.assets, (qb) => qb.select((eb) => eb.fn.toJson(eb.table('stack')).$castTo().as('stack')))
            .$if(!!stack.assets, (qb) => qb
            .leftJoinLateral((eb) => eb
            .selectFrom('asset as stacked')
            .selectAll('stack')
            .select((eb) => eb
            .fn('array_agg', [eb.table('stacked')])
            .as('assets'))
            .whereRef('stacked.stackId', '=', 'stack.id')
            .whereRef('stacked.id', '!=', 'stack.primaryAssetId')
            .where('stacked.deletedAt', 'is', null)
            .where('stacked.visibility', '=', enum_1.AssetVisibility.Timeline)
            .groupBy('stack.id')
            .as('stacked_assets'), (join) => join.on('stack.id', 'is not', null))
            .select((eb) => eb.fn.toJson(eb.table('stacked_assets')).as('stack'))))
            .$if(!!files, (qb) => qb.select(database_1.withFiles))
            .$if(!!tags, (qb) => qb.select(database_1.withTags))
            .$if(!!edits, (qb) => qb.select(database_1.withEdits))
            .limit(1)
            .executeTakeFirst();
    }
    async updateAll(ids, options) {
        if (ids.length === 0) {
            return;
        }
        await this.db.updateTable('asset').set(options).where('id', '=', (0, database_1.anyUuid)(ids)).execute();
    }
    async updateByLibraryId(libraryId, options) {
        await this.db.updateTable('asset').set(options).where('libraryId', '=', (0, database_1.asUuid)(libraryId)).execute();
    }
    async update(asset) {
        const value = (0, lodash_1.omitBy)(asset, lodash_1.isUndefined);
        delete value.id;
        if (!(0, lodash_1.isEmpty)(value)) {
            return this.db
                .with('asset', (qb) => qb.updateTable('asset').set(asset).where('id', '=', (0, database_1.asUuid)(asset.id)).returningAll())
                .selectFrom('asset')
                .selectAll('asset')
                .$call(database_1.withExif)
                .$call((qb) => qb.select(database_1.withFacesAndPeople))
                .$call((qb) => qb.select(database_1.withEdits))
                .executeTakeFirst();
        }
        return this.getById(asset.id, { exifInfo: true, faces: { person: true }, edits: true });
    }
    async remove(asset) {
        await this.db.deleteFrom('asset').where('id', '=', (0, database_1.asUuid)(asset.id)).execute();
    }
    getByChecksum({ ownerId, libraryId, checksum }) {
        return this.db
            .selectFrom('asset')
            .selectAll('asset')
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where('checksum', '=', checksum)
            .$call((qb) => (libraryId ? qb.where('libraryId', '=', (0, database_1.asUuid)(libraryId)) : qb.where('libraryId', 'is', null)))
            .limit(1)
            .executeTakeFirst();
    }
    getByChecksums(userId, checksums) {
        return this.db
            .selectFrom('asset')
            .select(['id', 'checksum', 'deletedAt'])
            .where('ownerId', '=', (0, database_1.asUuid)(userId))
            .where('checksum', 'in', checksums)
            .execute();
    }
    async getUploadAssetIdByChecksum(ownerId, checksum) {
        const asset = await this.db
            .selectFrom('asset')
            .select('id')
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where('checksum', '=', checksum)
            .where('libraryId', 'is', null)
            .limit(1)
            .executeTakeFirst();
        return asset?.id;
    }
    findLivePhotoMatch(options) {
        const { ownerId, otherAssetId, livePhotoCID, type } = options;
        return this.db
            .selectFrom('asset')
            .select(['asset.id', 'asset.ownerId'])
            .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
            .where('id', '!=', (0, database_1.asUuid)(otherAssetId))
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where('type', '=', type)
            .where('asset_exif.livePhotoCID', '=', livePhotoCID)
            .limit(1)
            .executeTakeFirst();
    }
    getStatistics(ownerId, { visibility, isFavorite, isTrashed }) {
        return this.db
            .selectFrom('asset')
            .select((eb) => eb.fn.countAll().filterWhere('type', '=', enum_1.AssetType.Audio).as(enum_1.AssetType.Audio))
            .select((eb) => eb.fn.countAll().filterWhere('type', '=', enum_1.AssetType.Image).as(enum_1.AssetType.Image))
            .select((eb) => eb.fn.countAll().filterWhere('type', '=', enum_1.AssetType.Video).as(enum_1.AssetType.Video))
            .select((eb) => eb.fn.countAll().filterWhere('type', '=', enum_1.AssetType.Other).as(enum_1.AssetType.Other))
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .$if(visibility === undefined, database_1.withDefaultVisibility)
            .$if(!!visibility, (qb) => qb.where('asset.visibility', '=', visibility))
            .$if(isFavorite !== undefined, (qb) => qb.where('isFavorite', '=', isFavorite))
            .$if(!!isTrashed, (qb) => qb.where('asset.status', '!=', enum_1.AssetStatus.Deleted))
            .where('deletedAt', isTrashed ? 'is not' : 'is', null)
            .executeTakeFirstOrThrow();
    }
    getCalendarHeatmap(ownerId, dto) {
        const dateColumns = {
            [enum_1.CalendarHeatmapType.Upload]: { order: enum_1.AssetOrderBy.CreatedAt, column: 'createdAt' },
            [enum_1.CalendarHeatmapType.Taken]: { order: enum_1.AssetOrderBy.TakenAt, column: 'localDateTime' },
        };
        const { order, column } = dateColumns[dto.type];
        const date = (0, database_1.truncatedDate)(order, 'DAY');
        return this.db
            .selectFrom('asset')
            .select(date.as('date'))
            .select((eb) => eb.fn.countAll().as('count'))
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where(column, '>=', dto.from)
            .where(column, '<', dto.to)
            .where('deletedAt', 'is', null)
            .groupBy(date)
            .orderBy('date', 'asc')
            .execute();
    }
    async getTimeBuckets(options) {
        return this.db
            .with('asset', (qb) => qb
            .selectFrom('asset')
            .select((0, database_1.truncatedDate)(options.orderBy).as('timeBucket'))
            .$if(!!options.isTrashed, (qb) => qb.where('asset.status', '!=', enum_1.AssetStatus.Deleted))
            .where('asset.deletedAt', options.isTrashed ? 'is not' : 'is', null)
            .$if(!!options.bbox, (qb) => {
            const bbox = options.bbox;
            const circle = getBoundingCircle(bbox);
            const withBoundingCircle = qb
                .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
                .where((0, kysely_1.sql) `earth_box(ll_to_earth_public(${circle.centerLatitude}, ${circle.centerLongitude}), ${circle.radius})`, '@>', (0, kysely_1.sql) `ll_to_earth_public(asset_exif.latitude, asset_exif.longitude)`);
            return withBoundingBox(withBoundingCircle, bbox);
        })
            .$if(options.visibility === undefined, database_1.withDefaultVisibility)
            .$if(!!options.visibility, (qb) => qb.where('asset.visibility', '=', options.visibility))
            .$if(!!options.albumId, (qb) => qb
            .innerJoin('album_asset', 'asset.id', 'album_asset.assetId')
            .where('album_asset.albumId', '=', (0, database_1.asUuid)(options.albumId)))
            .$if(!!options.personId, (qb) => (0, database_1.hasPeople)(qb, [options.personId]))
            .$if(!!options.withStacked, (qb) => qb
            .leftJoin('stack', (join) => join.onRef('stack.id', '=', 'asset.stackId').onRef('stack.primaryAssetId', '=', 'asset.id'))
            .where((eb) => eb.or([eb('asset.stackId', 'is', null), eb(eb.table('stack'), 'is not', null)])))
            .$if(!!options.userIds, (qb) => qb.where('asset.ownerId', '=', (0, database_1.anyUuid)(options.userIds)))
            .$if(options.isFavorite !== undefined, (qb) => qb.where('asset.isFavorite', '=', options.isFavorite))
            .$if(!!options.assetType, (qb) => qb.where('asset.type', '=', options.assetType))
            .$if(options.isDuplicate !== undefined, (qb) => qb.where('asset.duplicateId', options.isDuplicate ? 'is not' : 'is', null))
            .$if(!!options.tagId, (qb) => (0, database_1.withTagId)(qb, options.tagId)))
            .selectFrom('asset')
            .select((0, kysely_1.sql) `("timeBucket" AT TIME ZONE 'UTC')::date::text`.as('timeBucket'))
            .select((eb) => eb.fn.countAll().as('count'))
            .groupBy('timeBucket')
            .orderBy('timeBucket', options.order ?? 'desc')
            .execute();
    }
    getTimeBucket(timeBucket, options, auth) {
        const order = options.order ?? 'desc';
        const query = this.db
            .with('cte', (qb) => qb
            .selectFrom('asset')
            .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
            .select((eb) => [
            'asset.duration',
            'asset.id',
            'asset.visibility',
            (0, kysely_1.sql) `asset."isFavorite" and asset."ownerId" = ${auth.user.id}`.as('isFavorite'),
            (0, kysely_1.sql) `asset.type = 'IMAGE'`.as('isImage'),
            (0, kysely_1.sql) `asset."deletedAt" is not null`.as('isTrashed'),
            'asset.livePhotoVideoId',
            (0, kysely_1.sql) `extract(epoch from (asset."localDateTime" AT TIME ZONE 'UTC' - asset."fileCreatedAt" at time zone 'UTC'))::real / 3600`.as('localOffsetHours'),
            'asset.ownerId',
            'asset.status',
            (0, kysely_1.sql) `asset."fileCreatedAt" at time zone 'utc'`.as('fileCreatedAt'),
            (0, kysely_1.sql) `asset."createdAt" at time zone 'utc'`.as('createdAt'),
            eb.fn('encode', ['asset.thumbhash', kysely_1.sql.lit('base64')]).as('thumbhash'),
            'asset_exif.projectionType',
            eb.fn
                .coalesce(eb
                .case()
                .when((0, kysely_1.sql) `asset."height" = 0 or asset."width" = 0`)
                .then(eb.lit(1))
                .else((0, kysely_1.sql) `round(asset."width"::numeric / asset."height"::numeric, 3)`)
                .end(), eb.lit(1))
                .as('ratio'),
        ])
            .$if(!auth.sharedLink || auth.sharedLink.showExif, (qb) => qb.select(['asset_exif.city', 'asset_exif.country']))
            .$if(!!options.withCoordinates, (qb) => qb.select(['asset_exif.latitude', 'asset_exif.longitude']))
            .where('asset.deletedAt', options.isTrashed ? 'is not' : 'is', null)
            .$if(options.visibility == undefined, database_1.withDefaultVisibility)
            .$if(!!options.visibility, (qb) => qb.where('asset.visibility', '=', options.visibility))
            .$if(!!options.bbox, (qb) => {
            const bbox = options.bbox;
            const circle = getBoundingCircle(bbox);
            const withBoundingCircle = qb.where((0, kysely_1.sql) `earth_box(ll_to_earth_public(${circle.centerLatitude}, ${circle.centerLongitude}), ${circle.radius})`, '@>', (0, kysely_1.sql) `ll_to_earth_public(asset_exif.latitude, asset_exif.longitude)`);
            return withBoundingBox(withBoundingCircle, bbox);
        })
            .where((0, database_1.truncatedDate)(options.orderBy), '=', timeBucket.replace(/^[+-]/, ''))
            .$if(!!options.albumId, (qb) => qb.where((eb) => eb.exists(eb
            .selectFrom('album_asset')
            .whereRef('album_asset.assetId', '=', 'asset.id')
            .where('album_asset.albumId', '=', (0, database_1.asUuid)(options.albumId)))))
            .$if(!!options.personId, (qb) => (0, database_1.hasPeople)(qb, [options.personId]))
            .$if(!!options.userIds, (qb) => qb.where('asset.ownerId', '=', (0, database_1.anyUuid)(options.userIds)))
            .$if(options.isFavorite !== undefined, (qb) => qb.where('asset.isFavorite', '=', options.isFavorite))
            .$if(!!options.withStacked, (qb) => qb
            .where((eb) => eb.not(eb.exists(eb
            .selectFrom('stack')
            .whereRef('stack.id', '=', 'asset.stackId')
            .whereRef('stack.primaryAssetId', '!=', 'asset.id'))))
            .leftJoinLateral((eb) => eb
            .selectFrom('asset as stacked')
            .select((0, kysely_1.sql) `array[stacked."stackId"::text, count('stacked')::text]`.as('stack'))
            .whereRef('stacked.stackId', '=', 'asset.stackId')
            .where('stacked.deletedAt', 'is', null)
            .where('stacked.visibility', '=', enum_1.AssetVisibility.Timeline)
            .groupBy('stacked.stackId')
            .as('stacked_assets'), (join) => join.onTrue())
            .select('stack'))
            .$if(!!options.assetType, (qb) => qb.where('asset.type', '=', options.assetType))
            .$if(options.isDuplicate !== undefined, (qb) => qb.where('asset.duplicateId', options.isDuplicate ? 'is not' : 'is', null))
            .$if(!!options.isTrashed, (qb) => qb.where('asset.status', '!=', enum_1.AssetStatus.Deleted))
            .$if(!!options.tagId, (qb) => (0, database_1.withTagId)(qb, options.tagId))
            .orderBy(options.orderBy == enum_1.AssetOrderBy.CreatedAt
            ? (0, kysely_1.sql) `"createdAt"`
            : (0, kysely_1.sql) `(asset."localDateTime" AT TIME ZONE 'UTC')::date`, order)
            .orderBy('asset.fileCreatedAt', order))
            .with('agg', (qb) => qb
            .selectFrom('cte')
            .select((eb) => [
            eb.fn.coalesce(eb.fn('array_agg', ['duration']), kysely_1.sql.lit('{}')).as('duration'),
            eb.fn.coalesce(eb.fn('array_agg', ['id']), kysely_1.sql.lit('{}')).as('id'),
            eb.fn.coalesce(eb.fn('array_agg', ['visibility']), kysely_1.sql.lit('{}')).as('visibility'),
            eb.fn.coalesce(eb.fn('array_agg', ['isFavorite']), kysely_1.sql.lit('{}')).as('isFavorite'),
            eb.fn.coalesce(eb.fn('array_agg', ['isImage']), kysely_1.sql.lit('{}')).as('isImage'),
            eb.fn.coalesce(eb.fn('array_agg', ['isTrashed']), kysely_1.sql.lit('{}')).as('isTrashed'),
            eb.fn.coalesce(eb.fn('array_agg', ['livePhotoVideoId']), kysely_1.sql.lit('{}')).as('livePhotoVideoId'),
            eb.fn.coalesce(eb.fn('array_agg', ['fileCreatedAt']), kysely_1.sql.lit('{}')).as('fileCreatedAt'),
            eb.fn.coalesce(eb.fn('array_agg', ['localOffsetHours']), kysely_1.sql.lit('{}')).as('localOffsetHours'),
            eb.fn.coalesce(eb.fn('array_agg', ['createdAt']), kysely_1.sql.lit('{}')).as('createdAt'),
            eb.fn.coalesce(eb.fn('array_agg', ['ownerId']), kysely_1.sql.lit('{}')).as('ownerId'),
            eb.fn.coalesce(eb.fn('array_agg', ['projectionType']), kysely_1.sql.lit('{}')).as('projectionType'),
            eb.fn.coalesce(eb.fn('array_agg', ['ratio']), kysely_1.sql.lit('{}')).as('ratio'),
            eb.fn.coalesce(eb.fn('array_agg', ['status']), kysely_1.sql.lit('{}')).as('status'),
            eb.fn.coalesce(eb.fn('array_agg', ['thumbhash']), kysely_1.sql.lit('{}')).as('thumbhash'),
        ])
            .$if(!auth.sharedLink || auth.sharedLink.showExif, (qb) => qb.select((eb) => [
            eb.fn.coalesce(eb.fn('array_agg', ['city']), kysely_1.sql.lit('{}')).as('city'),
            eb.fn.coalesce(eb.fn('array_agg', ['country']), kysely_1.sql.lit('{}')).as('country'),
        ]))
            .$if(!!options.withCoordinates, (qb) => qb.select((eb) => [
            eb.fn.coalesce(eb.fn('array_agg', ['latitude']), kysely_1.sql.lit('{}')).as('latitude'),
            eb.fn.coalesce(eb.fn('array_agg', ['longitude']), kysely_1.sql.lit('{}')).as('longitude'),
        ]))
            .$if(!!options.withStacked, (qb) => qb.select((eb) => eb.fn.coalesce(eb.fn('json_agg', ['stack']), kysely_1.sql.lit('[]')).as('stack'))))
            .selectFrom('agg')
            .select((0, kysely_1.sql) `to_json(agg)::text`.as('assets'));
        return query.executeTakeFirstOrThrow();
    }
    async getAssetIdByCity(ownerId, { minAssetsPerField, maxFields }) {
        const items = await this.db
            .with('cities', (qb) => qb
            .selectFrom('asset_exif')
            .select('city')
            .where('city', 'is not', null)
            .groupBy('city')
            .having((eb) => eb.fn('count', [eb.ref('assetId')]), '>=', minAssetsPerField))
            .selectFrom('asset')
            .innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
            .innerJoin('cities', 'asset_exif.city', 'cities.city')
            .distinctOn('asset_exif.city')
            .select(['assetId as data', 'asset_exif.city as value'])
            .$narrowType()
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where('visibility', '=', enum_1.AssetVisibility.Timeline)
            .where('type', '=', enum_1.AssetType.Image)
            .where('deletedAt', 'is', null)
            .limit(maxFields)
            .execute();
        return { fieldName: 'exifInfo.city', items };
    }
    async getRecentlyCreatedAssetIds(ownerId, maxAssets) {
        const items = await this.db
            .selectFrom('asset')
            .select(['id as data', 'createdAt as value'])
            .where('ownerId', '=', (0, database_1.asUuid)(ownerId))
            .where('asset.visibility', '=', enum_1.AssetVisibility.Timeline)
            .where('type', '=', enum_1.AssetType.Image)
            .where('deletedAt', 'is', null)
            .orderBy('value', 'desc')
            .limit(maxAssets)
            .execute();
        return { fieldName: 'createdAt', items };
    }
    async upsertFile(file) {
        await this.db
            .insertInto('asset_file')
            .values(file)
            .onConflict((oc) => oc.columns(['assetId', 'type', 'isEdited']).doUpdateSet((eb) => ({
            path: eb.ref('excluded.path'),
        })))
            .execute();
    }
    async upsertFiles(files) {
        if (files.length === 0) {
            return;
        }
        await this.db
            .insertInto('asset_file')
            .values(files)
            .onConflict((oc) => oc.columns(['assetId', 'type', 'isEdited']).doUpdateSet((eb) => ({
            path: eb.ref('excluded.path'),
            isProgressive: eb.ref('excluded.isProgressive'),
            isTransparent: eb.ref('excluded.isTransparent'),
        })))
            .execute();
    }
    async deleteFile({ assetId, type, edited, }) {
        await this.db
            .deleteFrom('asset_file')
            .where('assetId', '=', (0, database_1.asUuid)(assetId))
            .where('type', '=', type)
            .$if(edited !== undefined, (qb) => qb.where('isEdited', '=', edited))
            .execute();
    }
    async deleteFiles(files) {
        if (files.length === 0) {
            return;
        }
        await this.db
            .deleteFrom('asset_file')
            .where('id', '=', (0, database_1.anyUuid)(files.map((file) => file.id)))
            .execute();
    }
    async detectOfflineExternalAssets(libraryId, importPaths, exclusionPatterns) {
        const paths = importPaths.map((importPath) => `${importPath}%`);
        const exclusions = exclusionPatterns.map((pattern) => (0, misc_1.globToSqlPattern)(pattern));
        return this.db
            .updateTable('asset')
            .set({
            isOffline: true,
            deletedAt: new Date(),
        })
            .where('isOffline', '=', false)
            .where('isExternal', '=', true)
            .where('libraryId', '=', (0, database_1.asUuid)(libraryId))
            .where((eb) => eb.or([
            eb.not(eb.or(paths.map((path) => eb('originalPath', 'like', path)))),
            eb.or(exclusions.map((path) => eb('originalPath', 'like', path))),
        ]))
            .executeTakeFirstOrThrow();
    }
    async filterNewExternalAssetPaths(libraryId, paths) {
        const result = await this.db
            .selectFrom((0, database_1.unnest)(paths).as('path'))
            .select('path')
            .where((eb) => eb.not(eb.exists(this.db
            .selectFrom('asset')
            .select('originalPath')
            .whereRef('asset.originalPath', '=', eb.ref('path'))
            .where('libraryId', '=', (0, database_1.asUuid)(libraryId))
            .where('isExternal', '=', true))))
            .execute();
        return result.map((row) => row.path);
    }
    async getLibraryAssetCount(libraryId) {
        const { count } = await this.db
            .selectFrom('asset')
            .select((eb) => eb.fn.countAll().as('count'))
            .where('libraryId', '=', (0, database_1.asUuid)(libraryId))
            .executeTakeFirstOrThrow();
        return count;
    }
    buildGetForOriginal(ids, isEdited) {
        return this.db
            .selectFrom('asset')
            .select('asset.id')
            .select('originalFileName')
            .where('asset.id', 'in', ids)
            .$if(isEdited, (qb) => qb
            .leftJoin('asset_file', (join) => join
            .onRef('asset.id', '=', 'asset_file.assetId')
            .on('asset_file.isEdited', '=', true)
            .on('asset_file.type', '=', enum_1.AssetFileType.FullSize))
            .select('asset_file.path as editedPath'))
            .select('originalPath');
    }
    getForOriginal(id, isEdited) {
        return this.buildGetForOriginal([id], isEdited).executeTakeFirstOrThrow();
    }
    getForOriginals(ids, isEdited) {
        return this.buildGetForOriginal(ids, isEdited).execute();
    }
    async getForThumbnail(id, type, isEdited) {
        return this.db
            .selectFrom('asset')
            .where('asset.id', '=', id)
            .leftJoin('asset_file', (join) => join.onRef('asset.id', '=', 'asset_file.assetId').on('asset_file.type', '=', type))
            .select(['asset.originalPath', 'asset.originalFileName', 'asset_file.path as path'])
            .orderBy('asset_file.isEdited', isEdited ? 'desc' : 'asc')
            .executeTakeFirstOrThrow();
    }
    async getForVideo(id) {
        return this.db
            .selectFrom('asset')
            .select(['asset.originalPath'])
            .select((eb) => (0, database_1.withFilePath)(eb, enum_1.AssetFileType.EncodedVideo).as('encodedVideoPath'))
            .where('asset.id', '=', id)
            .where('asset.type', '=', enum_1.AssetType.Video)
            .executeTakeFirst();
    }
    async getForOcr(id) {
        return this.db
            .selectFrom('asset')
            .where('asset.id', '=', id)
            .select(database_1.withEdits)
            .innerJoin('asset_exif', (join) => join.onRef('asset_exif.assetId', '=', 'asset.id'))
            .select(['asset_exif.exifImageWidth', 'asset_exif.exifImageHeight', 'asset_exif.orientation'])
            .executeTakeFirst();
    }
    async getForEdit(id) {
        return this.db
            .selectFrom('asset')
            .select(['asset.type', 'asset.livePhotoVideoId', 'asset.originalPath', 'asset.originalFileName'])
            .where('asset.id', '=', id)
            .innerJoin('asset_exif', (join) => join.onRef('asset_exif.assetId', '=', 'asset.id'))
            .select([
            'asset_exif.exifImageWidth',
            'asset_exif.exifImageHeight',
            'asset_exif.orientation',
            'asset_exif.projectionType',
        ])
            .executeTakeFirst();
    }
    async getForMetadataExtractionTags(id) {
        return this.db
            .selectFrom('asset_exif')
            .select('asset_exif.tags')
            .where('asset_exif.assetId', '=', id)
            .executeTakeFirst();
    }
    async getForFaces(id) {
        return this.db
            .selectFrom('asset')
            .innerJoin('asset_exif', (join) => join.onRef('asset_exif.assetId', '=', 'asset.id'))
            .select(['asset_exif.exifImageHeight', 'asset_exif.exifImageWidth', 'asset_exif.orientation'])
            .select(database_1.withEdits)
            .where('asset.id', '=', id)
            .executeTakeFirstOrThrow();
    }
    async getForUpdateTags(id) {
        return this.db
            .selectFrom('asset')
            .select((eb) => (0, postgres_1.jsonArrayFrom)(eb
            .selectFrom('tag')
            .select('tag.value')
            .innerJoin('tag_asset', 'tag.id', 'tag_asset.tagId')
            .whereRef('asset.id', '=', 'tag_asset.assetId')).as('tags'))
            .where('asset.id', '=', id)
            .executeTakeFirstOrThrow();
    }
};
exports.AssetRepository = AssetRepository;
__decorate([
    (0, decorators_1.GenerateSql)({
        params: [
            {
                exif: { dateTimeOriginal: decorators_1.DummyValue.DATE, lockedProperties: ['dateTimeOriginal'] },
                lockedPropertiesBehavior: 'append',
            },
        ],
    }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "upsertExif", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID], { model: decorators_1.DummyValue.STRING }] }),
    (0, decorators_1.Chunked)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Object]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "updateAllExif", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID], decorators_1.DummyValue.NUMBER, decorators_1.DummyValue.STRING] }),
    (0, decorators_1.Chunked)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Number, String]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "updateDateTimeOriginal", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, ['description']] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Array]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "unlockProperties", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getMetadata", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, decorators_1.DummyValue.STRING] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getMetadataByKey", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, decorators_1.DummyValue.STRING] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "deleteMetadataByKey", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[{ assetId: decorators_1.DummyValue.UUID, key: decorators_1.DummyValue.STRING }]] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "deleteBulkMetadata", null);
__decorate([
    (0, decorators_1.ChunkedArray)({ chunkSize: 4000 }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "createAll", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, { year: 2000, day: 1, month: 1 }] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Object]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByDayOfYear", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID]] }),
    (0, decorators_1.ChunkedArray)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByIds", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID]] }),
    (0, decorators_1.ChunkedArray)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByIdsWithAllRelationsButStacks", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "deleteAll", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, decorators_1.DummyValue.STRING] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByLibraryIdAndOriginalPath", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getLivePhotoCount", null);
__decorate([
    (0, decorators_1.GenerateSql)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getFileSamples", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getForCopy", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getById", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID], {}] }),
    (0, decorators_1.Chunked)(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Object]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "updateAll", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [{ ownerId: decorators_1.DummyValue.UUID, libraryId: decorators_1.DummyValue.UUID, checksum: decorators_1.DummyValue.BUFFER }] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByChecksum", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, [decorators_1.DummyValue.BUFFER]] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Array]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getByChecksums", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, decorators_1.DummyValue.BUFFER] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Buffer]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getUploadAssetIdByChecksum", null);
__decorate([
    (0, decorators_1.GenerateSql)({
        params: [decorators_1.DummyValue.UUID, { from: decorators_1.DummyValue.DATE, to: decorators_1.DummyValue.DATE, type: enum_1.CalendarHeatmapType.Upload }],
    }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getCalendarHeatmap", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [{}] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getTimeBuckets", null);
__decorate([
    (0, decorators_1.GenerateSql)({
        params: [decorators_1.DummyValue.TIME_BUCKET, { withStacked: true }, { user: { id: decorators_1.DummyValue.UUID } }],
    }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object, Object]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getTimeBucket", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, { minAssetsPerField: 5, maxFields: 12 }] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Object]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getAssetIdByCity", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, 12] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Number]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getRecentlyCreatedAssetIds", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, [decorators_1.DummyValue.STRING], [decorators_1.DummyValue.STRING]] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Array, Array]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "detectOfflineExternalAssets", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, [decorators_1.DummyValue.STRING]] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Array]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "filterNewExternalAssetPaths", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, true] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, Boolean]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getForOriginal", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [[decorators_1.DummyValue.UUID], true] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Boolean]),
    __metadata("design:returntype", void 0)
], AssetRepository.prototype, "getForOriginals", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID, enum_1.AssetFileType.Preview, true] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String, String, Boolean]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForThumbnail", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForVideo", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForOcr", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForEdit", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForMetadataExtractionTags", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForFaces", null);
__decorate([
    (0, decorators_1.GenerateSql)({ params: [decorators_1.DummyValue.UUID] }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", Promise)
], AssetRepository.prototype, "getForUpdateTags", null);
exports.AssetRepository = AssetRepository = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, nestjs_kysely_1.InjectKysely)()),
    __metadata("design:paramtypes", [kysely_1.Kysely])
], AssetRepository);
//# sourceMappingURL=asset.repository.js.map