/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.persistence.dao.impl;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.orcid.jaxb.model.common_v2.Visibility;
import org.orcid.persistence.dao.WorkDao;
import org.orcid.persistence.jpa.entities.MinimizedWorkEntity;
import org.orcid.persistence.jpa.entities.WorkBaseEntity;
import org.orcid.persistence.jpa.entities.WorkEntity;
import org.orcid.persistence.jpa.entities.WorkLastModifiedEntity;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
public class WorkDaoImpl extends GenericDaoImpl<WorkEntity, Long> implements WorkDao {
public WorkDaoImpl() {
super(WorkEntity.class);
}
/**
* Add a new work to the work table
*
* @param work
* The work that will be persisted
* @return the work already persisted on database
* */
@Override
@Transactional
public WorkEntity addWork(WorkEntity work) {
this.persist(work);
this.flush();
return work;
}
@Override
@Transactional
public WorkEntity editWork(WorkEntity updatedWork) {
WorkEntity workToUpdate = this.find(updatedWork.getId());
mergeWork(workToUpdate, updatedWork);
workToUpdate = this.merge(workToUpdate);
return workToUpdate;
}
private void mergeWork(WorkEntity workToUpdate, WorkEntity workWithNewData) {
workToUpdate.setTitle(workWithNewData.getTitle());
workToUpdate.setTranslatedTitle(workWithNewData.getTranslatedTitle());
workToUpdate.setSubtitle(workWithNewData.getSubtitle());
workToUpdate.setDescription(workWithNewData.getDescription());
workToUpdate.setWorkUrl(workWithNewData.getWorkUrl());
workToUpdate.setCitation(workWithNewData.getCitation());
workToUpdate.setJournalTitle(workWithNewData.getJournalTitle());
workToUpdate.setLanguageCode(workWithNewData.getLanguageCode());
workToUpdate.setTranslatedTitleLanguageCode(workWithNewData.getTranslatedTitleLanguageCode());
workToUpdate.setIso2Country(workWithNewData.getIso2Country());
workToUpdate.setCitationType(workWithNewData.getCitationType());
workToUpdate.setWorkType(workWithNewData.getWorkType());
workToUpdate.setPublicationDate(workWithNewData.getPublicationDate());
workToUpdate.setContributorsJson(workWithNewData.getContributorsJson());
workToUpdate.setExternalIdentifiersJson(workWithNewData.getExternalIdentifiersJson());
workToUpdate.setVisibility(workWithNewData.getVisibility());
workToUpdate.setDisplayIndex(workWithNewData.getDisplayIndex());
workToUpdate.setSourceId(workWithNewData.getSourceId());
workToUpdate.setClientSourceId(workWithNewData.getClientSourceId());
workToUpdate.setLastModified(new Date());
if(workWithNewData.getAddedToProfileDate() != null) {
workToUpdate.setAddedToProfileDate(workWithNewData.getAddedToProfileDate());
}
workToUpdate.setProfile(workWithNewData.getProfile());
}
/**
* @deprecated Use {@link org.orcid.core.manager.WorkEntityCacheManager#retrieveMinimizedWorks(String, long) } instead
*
* Find works for a specific user
*
* @param orcid
* the Id of the user
* @return the list of works associated to the specific user
* */
@SuppressWarnings("unchecked")
@Cacheable(value = "dao-works", key = "#orcid.concat('-').concat(#lastModified)")
@Deprecated
public List<MinimizedWorkEntity> findWorks(String orcid, long lastModified) {
Query query = entityManager
.createQuery("from MinimizedWorkEntity w "
+ "where w.orcid=:orcid "
+ "order by w.displayIndex desc, w.dateCreated asc");
query.setParameter("orcid", orcid);
return query.getResultList();
}
/**
* @deprepcated Use {@link org.orcid.core.manager.WorkEntityCacheManager#retrievePublicMinimizedWorks(String, long)} instead
*
* Find the public works for a specific user
*
* @param orcid
* the Id of the user
* @return the list of works associated to the specific user
* */
@SuppressWarnings("unchecked")
@Cacheable(value = "dao-public-works", key = "#orcid.concat('-').concat(#lastModified)")
@Deprecated
public List<MinimizedWorkEntity> findPublicWorks(String orcid, long lastModified) {
Query query = entityManager
.createQuery("from MinimizedWorkEntity w "
+ "where w.visibility='PUBLIC' and w.orcid=:orcid "
+ "order by w.displayIndex desc, w.dateCreated asc");
query.setParameter("orcid", orcid);
return query.getResultList();
}
@Override
public MinimizedWorkEntity getMinimizedWorkEntity(Long id) {
TypedQuery<MinimizedWorkEntity> query = entityManager
.createQuery("from MinimizedWorkEntity where id = :id", MinimizedWorkEntity.class);
query.setParameter("id", id);
return query.getSingleResult();
}
@Override
public List<MinimizedWorkEntity> getMinimizedWorkEntities(List<Long> ids) {
// batch up list into sets of 50;
List<MinimizedWorkEntity> list = new ArrayList<>();
for (List<Long> partition : Lists.partition(ids, 50)) {
TypedQuery<MinimizedWorkEntity> query = entityManager.createQuery("SELECT x FROM MinimizedWorkEntity x WHERE x.id IN :ids", MinimizedWorkEntity.class);
query.setParameter("ids", partition);
list.addAll(query.getResultList());
}
return list;
}
@Override
public List<WorkEntity> getWorkEntities(List<Long> ids) {
// batch up list into sets of 50;
List<WorkEntity> list = new ArrayList<>();
for (List<Long> partition : Lists.partition(ids, 50)) {
TypedQuery<WorkEntity> query = entityManager.createQuery("SELECT x FROM WorkEntity x WHERE x.id IN :ids", WorkEntity.class);
query.setParameter("ids", partition);
list.addAll(query.getResultList());
}
return list;
}
@Override
public void detach(WorkBaseEntity workBaseEntity) {
entityManager.detach(workBaseEntity);
}
/**
* Updates the visibility of an existing work
*
* @param workId
* The id of the work that will be updated
* @param visibility
* The new visibility value for the profile work relationship
* @return true if the relationship was updated
* */
@Override
@Transactional
public boolean updateVisibilities(String orcid, List<Long> workIds, Visibility visibility) {
Query query = entityManager.createNativeQuery("UPDATE work SET visibility=:visibility, last_modified=now() WHERE work_id in (:workIds)");
query.setParameter("visibility", visibility.name());
query.setParameter("workIds", workIds);
return query.executeUpdate() > 0;
}
/**
* Removes a work.
*
* @param workId
* The id of the work that will be removed from the client
* profile
* @param clientOrcid
* The client orcid
* @return true if the work was deleted
* */
@Override
@Transactional
public boolean removeWorks(String clientOrcid, List<Long> workIds) {
Query query = entityManager.createNativeQuery("DELETE FROM work WHERE work_id in (:workIds)");
query.setParameter("workIds", workIds);
return query.executeUpdate() > 0;
}
/**
* Remove a single work
*
* @param workId
* The id of the work that should be deleted
* */
@Override
@Transactional
public boolean removeWork(String orcid, Long workId) {
Query query = entityManager.createNativeQuery("DELETE FROM work WHERE work_id = :workId and orcid = :orcid");
query.setParameter("workId", workId);
query.setParameter("orcid", orcid);
return query.executeUpdate() > 0;
}
@Override
@Transactional
public void removeWorks(String orcid) {
Query query = entityManager.createQuery("delete from WorkEntity where orcid = :orcid");
query.setParameter("orcid", orcid);
query.executeUpdate();
}
/**
* Sets the display index of the new work
* @param workId
* The work id
* @param orcid
* The work owner
* @return true if the work index was correctly set
* */
@Override
@Transactional
public boolean updateToMaxDisplay(String orcid, Long workId) {
Query query = entityManager.createNativeQuery("UPDATE work SET display_index=(select coalesce(MAX(display_index) + 1, 0) from work where orcid=:orcid and work_id != :workId ), last_modified=now() WHERE work_id=:workId");
query.setParameter("workId", workId);
query.setParameter("orcid", orcid);
return query.executeUpdate() > 0;
}
/**
* Returns a list of work ids of works that still have old external identifiers
* @param limit
* The batch number to fetch
* @return a list of work ids with old ext ids
* */
@Override
@SuppressWarnings("unchecked")
public List<BigInteger> getWorksWithOldExtIds(long workId, long limit) {
Query query = entityManager.createNativeQuery("SELECT distinct(work_id) FROM (SELECT work_id, json_array_elements(json_extract_path(external_ids_json, 'workExternalIdentifier')) AS j FROM work where work_id > :workId and external_ids_json is not null order by work_id limit :limit) AS a WHERE (j->'relationship') is null");
query.setParameter("limit", limit);
query.setParameter("workId", workId);
return query.getResultList();
}
/**
* Returns a list of work ids where the ext id relationship is null
* @param limit
* The batch number to fetch
* @param workId
* The id of the latest work processed
* @return a list of work ids
* */
@Override
@SuppressWarnings("unchecked")
public List<BigInteger> getWorksWithNullRelationship() {
Query query = entityManager.createNativeQuery("SELECT distinct(work_id) FROM (SELECT work_id, json_array_elements(json_extract_path(external_ids_json, 'workExternalIdentifier')) AS j FROM work where external_ids_json is not null) AS a WHERE (j->>'relationship') is null");
return query.getResultList();
}
/**
* Returns a list of work ids where the work matches the work type and ext ids type
* @param workType
* The work type
* @param extIdType
* The ext id type
* @param limit
* The batch number to fetch
* @param workId
* The id of the latest work processed
* @return a list of work ids
* */
@Override
@SuppressWarnings("unchecked")
public List<BigInteger> getWorksByWorkTypeAndExtIdType(String workType, String extIdType) {
Query query = entityManager.createNativeQuery("SELECT distinct(work_id) FROM (SELECT work_id, json_array_elements(json_extract_path(external_ids_json, 'workExternalIdentifier')) AS j FROM work where work_type=:workType and external_ids_json is not null) AS a WHERE (j->>'workExternalIdentifierType') = :extIdType");
query.setParameter("extIdType", extIdType);
query.setParameter("workType", workType);
return query.getResultList();
}
/**
* Retrieve a work from database
* @param orcid
* @param id
* @return the WorkEntity associated with the parameter id
* */
@Override
public WorkEntity getWork(String orcid, Long id) {
TypedQuery<WorkEntity> query = entityManager.createQuery("FROM WorkEntity WHERE id = :workId and profile.id = :orcid", WorkEntity.class);
query.setParameter("workId", id);
query.setParameter("orcid", orcid);
return query.getSingleResult();
}
@SuppressWarnings("unchecked")
@Override
public List<WorkLastModifiedEntity> getWorkLastModifiedList(String orcid) {
Query query = entityManager.createQuery("from WorkLastModifiedEntity w where w.orcid=:orcid order by w.displayIndex desc, w.dateCreated asc");
query.setParameter("orcid", orcid);
return query.getResultList();
}
@SuppressWarnings("unchecked")
@Override
public List<WorkLastModifiedEntity> getPublicWorkLastModifiedList(String orcid) {
Query query = entityManager.createQuery("from WorkLastModifiedEntity w where w.visibility='PUBLIC' and w.orcid=:orcid order by w.displayIndex desc, w.dateCreated asc");
query.setParameter("orcid", orcid);
return query.getResultList();
}
@Override
@Transactional
public boolean increaseDisplayIndexOnAllElements(String orcid) {
Query query = entityManager.createNativeQuery("update work set display_index=(display_index + 1), last_modified=now() where orcid=:orcid");
query.setParameter("orcid", orcid);
return query.executeUpdate() > 0;
}
}