public interface

WorkSpecDao

 androidx.work.impl.model.WorkSpecDao

Overview

The Data Access Object for WorkSpecs.

Summary

Methods
public voiddelete(java.lang.String id)

Deletes WorkSpecs from the database.

public java.util.List<WorkSpec>getAllEligibleWorkSpecsForScheduling(int maxLimit)

public java.util.List<java.lang.String>getAllUnfinishedWork()

Retrieves work ids for all unfinished work.

public java.util.List<java.lang.String>getAllWorkSpecIds()

public LiveData<java.util.List>getAllWorkSpecIdsLiveData()

public java.util.List<WorkSpec>getEligibleWorkForScheduling(int schedulerLimit)

public java.util.List<Data>getInputsFromPrerequisites(java.lang.String id)

Gets all inputs coming from prerequisites for a particular WorkSpec.

public java.util.List<WorkSpec>getRecentlyCompletedWork(long startingAt)

public java.util.List<WorkSpec>getRunningWork()

public java.util.List<WorkSpec>getScheduledWork()

public LiveData<java.lang.Long>getScheduleRequestedAtLiveData(java.lang.String id)

public WorkInfo.StategetState(java.lang.String id)

Retrieves the state of a WorkSpec.

public java.util.List<java.lang.String>getUnfinishedWorkWithName(java.lang.String name)

Retrieves work ids for unfinished work with a given name.

public java.util.List<java.lang.String>getUnfinishedWorkWithTag(java.lang.String tag)

Retrieves work ids for unfinished work with a given tag.

public WorkSpecgetWorkSpec(java.lang.String id)

public java.util.List<WorkSpec.IdAndState>getWorkSpecIdAndStatesForName(java.lang.String name)

public WorkSpecgetWorkSpecs(java.util.List<java.lang.String> ids)

Retrieves WorkSpecs with the identifiers.

public WorkSpec.WorkInfoPojogetWorkStatusPojoForId(java.lang.String id)

For a WorkSpec identifier, retrieves its WorkSpec.WorkInfoPojo.

public java.util.List<WorkSpec.WorkInfoPojo>getWorkStatusPojoForIds(java.util.List<java.lang.String> ids)

For a list of WorkSpec identifiers, retrieves a java.util.List of their WorkSpec.WorkInfoPojo.

public java.util.List<WorkSpec.WorkInfoPojo>getWorkStatusPojoForName(java.lang.String name)

Retrieves a list of WorkSpec.WorkInfoPojo for all work with a given name.

public java.util.List<WorkSpec.WorkInfoPojo>getWorkStatusPojoForTag(java.lang.String tag)

Retrieves a list of WorkSpec.WorkInfoPojo for all work with a given tag.

public LiveData<java.util.List>getWorkStatusPojoLiveDataForIds(java.util.List<java.lang.String> ids)

For a list of WorkSpec identifiers, retrieves a LiveData list of their WorkSpec.WorkInfoPojo.

public LiveData<java.util.List>getWorkStatusPojoLiveDataForName(java.lang.String name)

Retrieves a LiveData list of WorkSpec.WorkInfoPojo for all work with a given name.

public LiveData<java.util.List>getWorkStatusPojoLiveDataForTag(java.lang.String tag)

Retrieves a LiveData list of WorkSpec.WorkInfoPojo for all work with a given tag.

public intincrementWorkSpecRunAttemptCount(java.lang.String id)

Increment run attempt count of a WorkSpec.

public voidinsertWorkSpec(WorkSpec workSpec)

Attempts to insert a WorkSpec into the database.

public intmarkWorkSpecScheduled(java.lang.String id, long startTime)

Marks a WorkSpec as scheduled.

public voidpruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast()

Immediately prunes eligible work from the database meeting the following criteria: - Is finished (succeeded, failed, or cancelled) - Has zero unfinished dependents

public intresetScheduledState()

Resets the scheduled state on the WorkSpecs that are not in a a completed state.

public intresetWorkSpecRunAttemptCount(java.lang.String id)

Reset run attempt count of a WorkSpec.

public voidsetOutput(java.lang.String id, Data output)

Updates the output of a WorkSpec.

public voidsetPeriodStartTime(java.lang.String id, long periodStartTime)

Updates the period start time of a WorkSpec.

public intsetState(WorkInfo.State state, java.lang.String ids[])

Updates the state of at least one WorkSpec by ID.

Methods

public void insertWorkSpec(WorkSpec workSpec)

Attempts to insert a WorkSpec into the database.

Parameters:

workSpec: The WorkSpec to insert.

public void delete(java.lang.String id)

Deletes WorkSpecs from the database.

Parameters:

id: The WorkSpec id to delete.

public WorkSpec getWorkSpec(java.lang.String id)

Parameters:

id: The identifier

Returns:

The WorkSpec associated with that id

public WorkSpec getWorkSpecs(java.util.List<java.lang.String> ids)

Retrieves WorkSpecs with the identifiers.

Parameters:

ids: The identifiers of desired WorkSpecs

Returns:

The WorkSpecs with the requested IDs

public java.util.List<WorkSpec.IdAndState> getWorkSpecIdAndStatesForName(java.lang.String name)

Parameters:

name: The work graph name

Returns:

The WorkSpecs labelled with the given name

public java.util.List<java.lang.String> getAllWorkSpecIds()

Returns:

All WorkSpec ids in the database.

public LiveData<java.util.List> getAllWorkSpecIdsLiveData()

Returns:

A LiveData list of all WorkSpec ids in the database.

public int setState(WorkInfo.State state, java.lang.String ids[])

Updates the state of at least one WorkSpec by ID.

Parameters:

state: The new state
ids: The IDs for the WorkSpecs to update

Returns:

The number of rows that were updated

public void setOutput(java.lang.String id, Data output)

Updates the output of a WorkSpec.

Parameters:

id: The WorkSpec identifier to update
output: The Data to set as the output

public void setPeriodStartTime(java.lang.String id, long periodStartTime)

Updates the period start time of a WorkSpec.

Parameters:

id: The WorkSpec identifier to update
periodStartTime: The time when the period started.

public int incrementWorkSpecRunAttemptCount(java.lang.String id)

Increment run attempt count of a WorkSpec.

Parameters:

id: The identifier for the WorkSpec

Returns:

The number of rows that were updated (should be 0 or 1)

public int resetWorkSpecRunAttemptCount(java.lang.String id)

Reset run attempt count of a WorkSpec.

Parameters:

id: The identifier for the WorkSpec

Returns:

The number of rows that were updated (should be 0 or 1)

public WorkInfo.State getState(java.lang.String id)

Retrieves the state of a WorkSpec.

Parameters:

id: The identifier for the WorkSpec

Returns:

The state of the WorkSpec

public WorkSpec.WorkInfoPojo getWorkStatusPojoForId(java.lang.String id)

For a WorkSpec identifier, retrieves its WorkSpec.WorkInfoPojo.

Parameters:

id: The identifier of the WorkSpec

Returns:

A list of WorkSpec.WorkInfoPojo

public java.util.List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForIds(java.util.List<java.lang.String> ids)

For a list of WorkSpec identifiers, retrieves a java.util.List of their WorkSpec.WorkInfoPojo.

Parameters:

ids: The identifier of the WorkSpecs

Returns:

A java.util.List of WorkSpec.WorkInfoPojo

public LiveData<java.util.List> getWorkStatusPojoLiveDataForIds(java.util.List<java.lang.String> ids)

For a list of WorkSpec identifiers, retrieves a LiveData list of their WorkSpec.WorkInfoPojo.

Parameters:

ids: The identifier of the WorkSpecs

Returns:

A LiveData list of WorkSpec.WorkInfoPojo

public java.util.List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForTag(java.lang.String tag)

Retrieves a list of WorkSpec.WorkInfoPojo for all work with a given tag.

Parameters:

tag: The tag for the WorkSpecs

Returns:

A list of WorkSpec.WorkInfoPojo

public LiveData<java.util.List> getWorkStatusPojoLiveDataForTag(java.lang.String tag)

Retrieves a LiveData list of WorkSpec.WorkInfoPojo for all work with a given tag.

Parameters:

tag: The tag for the WorkSpecs

Returns:

A LiveData list of WorkSpec.WorkInfoPojo

public java.util.List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForName(java.lang.String name)

Retrieves a list of WorkSpec.WorkInfoPojo for all work with a given name.

Parameters:

name: The name of the WorkSpecs

Returns:

A list of WorkSpec.WorkInfoPojo

public LiveData<java.util.List> getWorkStatusPojoLiveDataForName(java.lang.String name)

Retrieves a LiveData list of WorkSpec.WorkInfoPojo for all work with a given name.

Parameters:

name: The name for the WorkSpecs

Returns:

A LiveData list of WorkSpec.WorkInfoPojo

public java.util.List<Data> getInputsFromPrerequisites(java.lang.String id)

Gets all inputs coming from prerequisites for a particular WorkSpec. These are Data set via Worker#setOutputData().

Parameters:

id: The WorkSpec identifier

Returns:

A list of all inputs coming from prerequisites for id

public java.util.List<java.lang.String> getUnfinishedWorkWithTag(java.lang.String tag)

Retrieves work ids for unfinished work with a given tag.

Parameters:

tag: The tag used to identify the work

Returns:

A list of work ids

public java.util.List<java.lang.String> getUnfinishedWorkWithName(java.lang.String name)

Retrieves work ids for unfinished work with a given name.

Parameters:

name: THe tag used to identify the work

Returns:

A list of work ids

public java.util.List<java.lang.String> getAllUnfinishedWork()

Retrieves work ids for all unfinished work.

Returns:

A list of work ids

public int markWorkSpecScheduled(java.lang.String id, long startTime)

Marks a WorkSpec as scheduled.

Parameters:

id: The identifier for the WorkSpec
startTime: The time at which the WorkSpec was scheduled.

Returns:

The number of rows that were updated (should be 0 or 1)

public LiveData<java.lang.Long> getScheduleRequestedAtLiveData(java.lang.String id)

Returns:

The time at which the WorkSpec was scheduled.

public int resetScheduledState()

Resets the scheduled state on the WorkSpecs that are not in a a completed state.

Returns:

The number of rows that were updated

public java.util.List<WorkSpec> getEligibleWorkForScheduling(int schedulerLimit)

Returns:

The List of WorkSpecs that are eligible to be scheduled.

public java.util.List<WorkSpec> getAllEligibleWorkSpecsForScheduling(int maxLimit)

Returns:

The List of WorkSpecs that can be scheduled irrespective of scheduling limits.

public java.util.List<WorkSpec> getScheduledWork()

Returns:

The List of WorkSpecs that are unfinished and scheduled.

public java.util.List<WorkSpec> getRunningWork()

Returns:

The List of WorkSpecs that are running.

public java.util.List<WorkSpec> getRecentlyCompletedWork(long startingAt)

Returns:

The List of WorkSpec which completed recently.

public void pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast()

Immediately prunes eligible work from the database meeting the following criteria: - Is finished (succeeded, failed, or cancelled) - Has zero unfinished dependents

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.work.impl.model;

import static androidx.room.OnConflictStrategy.IGNORE;
import static androidx.work.impl.model.WorkTypeConverters.StateIds.COMPLETED_STATES;

import android.annotation.SuppressLint;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Transaction;
import androidx.work.Data;
import androidx.work.WorkInfo;

import java.util.List;

/**
 * The Data Access Object for {@link WorkSpec}s.
 */
@Dao
@SuppressLint("UnknownNullness")
public interface WorkSpecDao {
    /**
     * Attempts to insert a {@link WorkSpec} into the database.
     *
     * @param workSpec The WorkSpec to insert.
     */
    @Insert(onConflict = IGNORE)
    void insertWorkSpec(WorkSpec workSpec);

    /**
     * Deletes {@link WorkSpec}s from the database.
     *
     * @param id The WorkSpec id to delete.
     */
    @Query("DELETE FROM workspec WHERE id=:id")
    void delete(String id);

    /**
     * @param id The identifier
     * @return The WorkSpec associated with that id
     */
    @Query("SELECT * FROM workspec WHERE id=:id")
    WorkSpec getWorkSpec(String id);

    /**
     * Retrieves {@link WorkSpec}s with the identifiers.
     *
     * @param ids The identifiers of desired {@link WorkSpec}s
     * @return The {@link WorkSpec}s with the requested IDs
     */
    @Query("SELECT * FROM workspec WHERE id IN (:ids)")
    WorkSpec[] getWorkSpecs(List<String> ids);

    /**
     *
     * @param name The work graph name
     * @return The {@link WorkSpec}s labelled with the given name
     */
    @Query("SELECT id, state FROM workspec WHERE id IN "
            + "(SELECT work_spec_id FROM workname WHERE name=:name)")
    List<WorkSpec.IdAndState> getWorkSpecIdAndStatesForName(String name);

    /**
     * @return All WorkSpec ids in the database.
     */
    @Query("SELECT id FROM workspec")
    List<String> getAllWorkSpecIds();

    /**
     * @return A {@link LiveData} list of all WorkSpec ids in the database.
     */
    @Transaction
    @Query("SELECT id FROM workspec")
    LiveData<List<String>> getAllWorkSpecIdsLiveData();

    /**
     * Updates the state of at least one {@link WorkSpec} by ID.
     *
     * @param state The new state
     * @param ids The IDs for the {@link WorkSpec}s to update
     * @return The number of rows that were updated
     */
    @Query("UPDATE workspec SET state=:state WHERE id IN (:ids)")
    int setState(WorkInfo.State state, String... ids);

    /**
     * Updates the output of a {@link WorkSpec}.
     *
     * @param id The {@link WorkSpec} identifier to update
     * @param output The {@link Data} to set as the output
     */
    @Query("UPDATE workspec SET output=:output WHERE id=:id")
    void setOutput(String id, Data output);

    /**
     * Updates the period start time of a {@link WorkSpec}.
     *
     * @param id The {@link WorkSpec} identifier to update
     * @param periodStartTime The time when the period started.
     */
    @Query("UPDATE workspec SET period_start_time=:periodStartTime WHERE id=:id")
    void setPeriodStartTime(String id, long periodStartTime);

    /**
     * Increment run attempt count of a {@link WorkSpec}.
     *
     * @param id The identifier for the {@link WorkSpec}
     * @return The number of rows that were updated (should be 0 or 1)
     */
    @Query("UPDATE workspec SET run_attempt_count=run_attempt_count+1 WHERE id=:id")
    int incrementWorkSpecRunAttemptCount(String id);

    /**
     * Reset run attempt count of a {@link WorkSpec}.
     *
     * @param id The identifier for the {@link WorkSpec}
     * @return The number of rows that were updated (should be 0 or 1)
     */
    @Query("UPDATE workspec SET run_attempt_count=0 WHERE id=:id")
    int resetWorkSpecRunAttemptCount(String id);

    /**
     * Retrieves the state of a {@link WorkSpec}.
     *
     * @param id The identifier for the {@link WorkSpec}
     * @return The state of the {@link WorkSpec}
     */
    @Query("SELECT state FROM workspec WHERE id=:id")
    WorkInfo.State getState(String id);

    /**
     * For a {@link WorkSpec} identifier, retrieves its {@link WorkSpec.WorkInfoPojo}.
     *
     * @param id The identifier of the {@link WorkSpec}
     * @return A list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id=:id")
    WorkSpec.WorkInfoPojo getWorkStatusPojoForId(String id);

    /**
     * For a list of {@link WorkSpec} identifiers, retrieves a {@link List} of their
     * {@link WorkSpec.WorkInfoPojo}.
     *
     * @param ids The identifier of the {@link WorkSpec}s
     * @return A {@link List} of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN (:ids)")
    List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForIds(List<String> ids);

    /**
     * For a list of {@link WorkSpec} identifiers, retrieves a {@link LiveData} list of their
     * {@link WorkSpec.WorkInfoPojo}.
     *
     * @param ids The identifier of the {@link WorkSpec}s
     * @return A {@link LiveData} list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN (:ids)")
    LiveData<List<WorkSpec.WorkInfoPojo>> getWorkStatusPojoLiveDataForIds(List<String> ids);

    /**
     * Retrieves a list of {@link WorkSpec.WorkInfoPojo} for all work with a given tag.
     *
     * @param tag The tag for the {@link WorkSpec}s
     * @return A list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN "
            + "(SELECT work_spec_id FROM worktag WHERE tag=:tag)")
    List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForTag(String tag);

    /**
     * Retrieves a {@link LiveData} list of {@link WorkSpec.WorkInfoPojo} for all work with a
     * given tag.
     *
     * @param tag The tag for the {@link WorkSpec}s
     * @return A {@link LiveData} list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN "
            + "(SELECT work_spec_id FROM worktag WHERE tag=:tag)")
    LiveData<List<WorkSpec.WorkInfoPojo>> getWorkStatusPojoLiveDataForTag(String tag);

    /**
     * Retrieves a list of {@link WorkSpec.WorkInfoPojo} for all work with a given name.
     *
     * @param name The name of the {@link WorkSpec}s
     * @return A list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN "
            + "(SELECT work_spec_id FROM workname WHERE name=:name)")
    List<WorkSpec.WorkInfoPojo> getWorkStatusPojoForName(String name);

    /**
     * Retrieves a {@link LiveData} list of {@link WorkSpec.WorkInfoPojo} for all work with a
     * given name.
     *
     * @param name The name for the {@link WorkSpec}s
     * @return A {@link LiveData} list of {@link WorkSpec.WorkInfoPojo}
     */
    @Transaction
    @Query("SELECT id, state, output, run_attempt_count FROM workspec WHERE id IN "
            + "(SELECT work_spec_id FROM workname WHERE name=:name)")
    LiveData<List<WorkSpec.WorkInfoPojo>> getWorkStatusPojoLiveDataForName(String name);

    /**
     * Gets all inputs coming from prerequisites for a particular {@link WorkSpec}.  These are
     * {@link Data} set via {@code Worker#setOutputData()}.
     *
     * @param id The {@link WorkSpec} identifier
     * @return A list of all inputs coming from prerequisites for {@code id}
     */
    @Query("SELECT output FROM workspec WHERE id IN "
            + "(SELECT prerequisite_id FROM dependency WHERE work_spec_id=:id)")
    List<Data> getInputsFromPrerequisites(String id);

    /**
     * Retrieves work ids for unfinished work with a given tag.
     *
     * @param tag The tag used to identify the work
     * @return A list of work ids
     */
    @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES
            + " AND id IN (SELECT work_spec_id FROM worktag WHERE tag=:tag)")
    List<String> getUnfinishedWorkWithTag(@NonNull String tag);

    /**
     * Retrieves work ids for unfinished work with a given name.
     *
     * @param name THe tag used to identify the work
     * @return A list of work ids
     */
    @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES
            + " AND id IN (SELECT work_spec_id FROM workname WHERE name=:name)")
    List<String> getUnfinishedWorkWithName(@NonNull String name);

    /**
     * Retrieves work ids for all unfinished work.
     *
     * @return A list of work ids
     */
    @Query("SELECT id FROM workspec WHERE state NOT IN " + COMPLETED_STATES)
    List<String> getAllUnfinishedWork();

    /**
     * Marks a {@link WorkSpec} as scheduled.
     *
     * @param id        The identifier for the {@link WorkSpec}
     * @param startTime The time at which the {@link WorkSpec} was scheduled.
     * @return The number of rows that were updated (should be 0 or 1)
     */
    @Query("UPDATE workspec SET schedule_requested_at=:startTime WHERE id=:id")
    int markWorkSpecScheduled(@NonNull String id, long startTime);

    /**
     * @return The time at which the {@link WorkSpec} was scheduled.
     */
    @Query("SELECT schedule_requested_at FROM workspec WHERE id=:id")
    LiveData<Long> getScheduleRequestedAtLiveData(@NonNull String id);

    /**
     * Resets the scheduled state on the {@link WorkSpec}s that are not in a a completed state.
     * @return The number of rows that were updated
     */
    @Query("UPDATE workspec SET schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET
            + " WHERE state NOT IN " + COMPLETED_STATES)
    int resetScheduledState();

    /**
     * @return The List of {@link WorkSpec}s that are eligible to be scheduled.
     */
    @Query("SELECT * FROM workspec WHERE "
            + "state=" + WorkTypeConverters.StateIds.ENQUEUED
            // We only want WorkSpecs which have not been previously scheduled.
            + " AND schedule_requested_at=" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET
            // Order by period start time so we execute scheduled WorkSpecs in FIFO order
            + " ORDER BY period_start_time"
            + " LIMIT "
                + "(SELECT MAX(:schedulerLimit" + "-COUNT(*), 0) FROM workspec WHERE"
                    + " schedule_requested_at<>" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET
                    + " AND state NOT IN " + COMPLETED_STATES
                + ")"
    )
    List<WorkSpec> getEligibleWorkForScheduling(int schedulerLimit);

    /**
     * @return The List of {@link WorkSpec}s that can be scheduled irrespective of scheduling
     * limits.
     */
    @Query("SELECT * FROM workspec WHERE "
            + "state=" + WorkTypeConverters.StateIds.ENQUEUED
            // Order by period start time so we execute scheduled WorkSpecs in FIFO order
            + " ORDER BY period_start_time"
            + " LIMIT :maxLimit"
    )
    List<WorkSpec> getAllEligibleWorkSpecsForScheduling(int maxLimit);

    /**
     * @return The List of {@link WorkSpec}s that are unfinished and scheduled.
     */
    @Query("SELECT * FROM workspec WHERE "
            // Unfinished work
            + "state=" + WorkTypeConverters.StateIds.ENQUEUED
            // We only want WorkSpecs which have been scheduled.
            + " AND schedule_requested_at<>" + WorkSpec.SCHEDULE_NOT_REQUESTED_YET
    )
    List<WorkSpec> getScheduledWork();

    /**
     * @return The List of {@link WorkSpec}s that are running.
     */
    @Query("SELECT * FROM workspec WHERE "
            // Unfinished work
            + "state=" + WorkTypeConverters.StateIds.RUNNING
    )
    List<WorkSpec> getRunningWork();

    /**
     * @return The List of {@link WorkSpec} which completed recently.
     */
    @Query("SELECT * FROM workspec WHERE "
            + "period_start_time >= :startingAt"
            + " AND state IN " + COMPLETED_STATES
            + " ORDER BY period_start_time DESC"
    )
    List<WorkSpec> getRecentlyCompletedWork(long startingAt);

    /**
     * Immediately prunes eligible work from the database meeting the following criteria:
     * - Is finished (succeeded, failed, or cancelled)
     * - Has zero unfinished dependents
     */
    @Query("DELETE FROM workspec WHERE "
            + "state IN " + COMPLETED_STATES
            + " AND (SELECT COUNT(*)=0 FROM dependency WHERE "
            + "    prerequisite_id=id AND "
            + "    work_spec_id NOT IN "
            + "        (SELECT id FROM workspec WHERE state IN " + COMPLETED_STATES + "))")
    void pruneFinishedWorkWithZeroDependentsIgnoringKeepForAtLeast();
}