<commit_before>/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.api.db.hibernate;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Person;
import org.openmrs.PersonName;
import org.openmrs.Tribe;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.DAOException;
import org.openmrs.api.db.PatientDAO;
import org.openmrs.util.OpenmrsConstants;

/**
 * Patient related database hibernate specific methods
 */
public class HibernatePatientDAO implements PatientDAO {

	protected final Log log = LogFactory.getLog(getClass());

	/**
	 * Hibernate session factory
	 */
	private SessionFactory sessionFactory;
	
	public HibernatePatientDAO() { }
	
	/**
	 * Set session factory
	 * 
	 * @param sessionFactory
	 */
	public void setSessionFactory(SessionFactory sessionFactory) { 
		this.sessionFactory = sessionFactory;
	}
	
	/**
	 * @see org.openmrs.api.db.PatientService#getPatient(java.lang.Long)
	 */
	public Patient getPatient(Integer patientId) {
		try {
			return (Patient) sessionFactory.getCurrentSession().get(Patient.class, patientId);
		} catch (ObjectNotFoundException ex) {
			return null;
		}
	}
	

	/**
	 * @see org.openmrs.api.db.PatientDAO#createPatient(org.openmrs.Patient)
	 */
	public Patient createPatient(Patient patient) throws DAOException {
		sessionFactory.getCurrentSession().saveOrUpdate(patient);
		//sessionFactory.getCurrentSession().refresh(patient);
		
		return patient;
	}


	/**
	 * @see org.openmrs.api.db.PatientDAO#updatePatient(org.openmrs.Patient)
	 */
	public Patient updatePatient(Patient patient) throws DAOException {
		if (patient.getPatientId() == null)
			// TODO this check/call should be moved up from the DB layer to the API layer
			return createPatient(patient);
		else {
			
			// Check to make sure we have a row in the patient table already.
			// If we don't have a row, create it so Hibernate doesn't bung things up
			Object obj = sessionFactory.getCurrentSession().get(Patient.class, patient.getPatientId());
			if (!(obj instanceof Patient)) {
				insertPatientStub(patient);
			}
			
			patient = (Patient)sessionFactory.getCurrentSession().merge(patient);
			//sessionFactory.getCurrentSession().update("org.openmrs.Person", (Object)patient);
			return patient;
		}
	}

	/**
	 * Inserts a row into the patient table
	 * 
	 * This avoids hibernate's bunging of our person/patient/user inheritance
	 * 
	 * @param patient
	 */
	private void insertPatientStub(Patient patient) {
		Connection connection = sessionFactory.getCurrentSession().connection();
		try {
			PreparedStatement ps = connection.prepareStatement("INSERT INTO patient (patient_id, creator, date_created) VALUES (?, ?, ?)");
			
			ps.setInt(1, patient.getPatientId());
			ps.setInt(2, patient.getCreator().getUserId());
			ps.setDate(3, new java.sql.Date(patient.getDateCreated().getTime()));
	
			ps.executeUpdate();
		}
		catch (SQLException e) {
			log.warn("SQL Exception while trying to create a patient stub", e);
		}
		
		sessionFactory.getCurrentSession().flush();
	}

	@SuppressWarnings("unchecked")
	public Set<Patient> getPatientsByIdentifier(String identifier, boolean includeVoided) throws DAOException {
		Query query;
		
		String sql = "select patient from Patient patient, PersonName name join patient.identifiers ids where ids.identifier = :id and patient.patientId = name.person.personId";
		String order = " order by name.givenName asc, name.middleName asc, name.familyName asc";
		
		if (includeVoided) {
			query = sessionFactory.getCurrentSession().createQuery(sql + order);
			query.setString("id", identifier);
		}
		else {
			query = sessionFactory.getCurrentSession().createQuery(sql + " and patient.voided = :void" + order);
			query.setString("id", identifier);
			query.setBoolean("void", includeVoided);
		}
		
		Set<Patient> returnSet = new LinkedHashSet<Patient>();
		returnSet.addAll(query.list());
		
		return returnSet;
	}
	
	

	/**
	 * @see org.openmrs.api.db.PatientDAO#getPatientsByIdentifierPattern(java.lang.String, boolean)
	 */
	@SuppressWarnings("unchecked")
	public Collection<Patient> getPatientsByIdentifierPattern(String identifier, boolean includeVoided) throws DAOException {
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(PatientIdentifier.class);
		criteria.setProjection(Projections.property("patient"));
		
		AdministrationService adminService = Context.getAdministrationService();
		String regex = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_REGEX, "");
		
		// if the regex is empty, default to a simple "like" search
		if (regex.equals("")) {
			String prefix = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_PREFIX, "");
			String suffix = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_SUFFIX, "");
			StringBuffer likeString = new StringBuffer(prefix).append(identifier).append(suffix);
			criteria.add(Expression.like("identifier", likeString.toString()));
		}
		// if the regex is present, search on that
		else {
			regex = regex.replace("@SEARCH@", identifier);<commit_msg>Fixing #739: search by patient identifier was including voided identifiers<commit_after>/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.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://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.api.db.hibernate;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.openmrs.Patient;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.Person;
import org.openmrs.PersonName;
import org.openmrs.Tribe;
import org.openmrs.api.AdministrationService;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.DAOException;
import org.openmrs.api.db.PatientDAO;
import org.openmrs.util.OpenmrsConstants;

/**
 * Patient related database hibernate specific methods
 */
public class HibernatePatientDAO implements PatientDAO {

	protected final Log log = LogFactory.getLog(getClass());

	/**
	 * Hibernate session factory
	 */
	private SessionFactory sessionFactory;
	
	public HibernatePatientDAO() { }
	
	/**
	 * Set session factory
	 * 
	 * @param sessionFactory
	 */
	public void setSessionFactory(SessionFactory sessionFactory) { 
		this.sessionFactory = sessionFactory;
	}
	
	/**
	 * @see org.openmrs.api.db.PatientService#getPatient(java.lang.Long)
	 */
	public Patient getPatient(Integer patientId) {
		try {
			return (Patient) sessionFactory.getCurrentSession().get(Patient.class, patientId);
		} catch (ObjectNotFoundException ex) {
			return null;
		}
	}
	

	/**
	 * @see org.openmrs.api.db.PatientDAO#createPatient(org.openmrs.Patient)
	 */
	public Patient createPatient(Patient patient) throws DAOException {
		sessionFactory.getCurrentSession().saveOrUpdate(patient);
		//sessionFactory.getCurrentSession().refresh(patient);
		
		return patient;
	}


	/**
	 * @see org.openmrs.api.db.PatientDAO#updatePatient(org.openmrs.Patient)
	 */
	public Patient updatePatient(Patient patient) throws DAOException {
		if (patient.getPatientId() == null)
			// TODO this check/call should be moved up from the DB layer to the API layer
			return createPatient(patient);
		else {
			
			// Check to make sure we have a row in the patient table already.
			// If we don't have a row, create it so Hibernate doesn't bung things up
			Object obj = sessionFactory.getCurrentSession().get(Patient.class, patient.getPatientId());
			if (!(obj instanceof Patient)) {
				insertPatientStub(patient);
			}
			
			patient = (Patient)sessionFactory.getCurrentSession().merge(patient);
			//sessionFactory.getCurrentSession().update("org.openmrs.Person", (Object)patient);
			return patient;
		}
	}

	/**
	 * Inserts a row into the patient table
	 * 
	 * This avoids hibernate's bunging of our person/patient/user inheritance
	 * 
	 * @param patient
	 */
	private void insertPatientStub(Patient patient) {
		Connection connection = sessionFactory.getCurrentSession().connection();
		try {
			PreparedStatement ps = connection.prepareStatement("INSERT INTO patient (patient_id, creator, date_created) VALUES (?, ?, ?)");
			
			ps.setInt(1, patient.getPatientId());
			ps.setInt(2, patient.getCreator().getUserId());
			ps.setDate(3, new java.sql.Date(patient.getDateCreated().getTime()));
	
			ps.executeUpdate();
		}
		catch (SQLException e) {
			log.warn("SQL Exception while trying to create a patient stub", e);
		}
		
		sessionFactory.getCurrentSession().flush();
	}

	@SuppressWarnings("unchecked")
	public Set<Patient> getPatientsByIdentifier(String identifier, boolean includeVoided) throws DAOException {
		Query query;
		
		String sql = "select patient from Patient patient, PersonName name join patient.identifiers ids where ids.voided = false and ids.identifier = :id and patient.patientId = name.person.personId";
		String order = " order by name.givenName asc, name.middleName asc, name.familyName asc";
		
		if (includeVoided) {
			query = sessionFactory.getCurrentSession().createQuery(sql + order);
			query.setString("id", identifier);
		}
		else {
			query = sessionFactory.getCurrentSession().createQuery(sql + " and patient.voided = :void" + order);
			query.setString("id", identifier);
			query.setBoolean("void", includeVoided);
		}
		
		Set<Patient> returnSet = new LinkedHashSet<Patient>();
		returnSet.addAll(query.list());
		
		return returnSet;
	}
	
	

	/**
	 * @see org.openmrs.api.db.PatientDAO#getPatientsByIdentifierPattern(java.lang.String, boolean)
	 */
	@SuppressWarnings("unchecked")
	public Collection<Patient> getPatientsByIdentifierPattern(String identifier, boolean includeVoided) throws DAOException {
		
		Criteria criteria = sessionFactory.getCurrentSession().createCriteria(PatientIdentifier.class);
		criteria.add(Restrictions.eq("voided", false));
		criteria.setProjection(Projections.property("patient"));
		
		AdministrationService adminService = Context.getAdministrationService();
		String regex = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_REGEX, "");
		
		// if the regex is empty, default to a simple "like" search
		if (regex.equals("")) {
			String prefix = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_PREFIX, "");
			String suffix = adminService.getGlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_IDENTIFIER_SUFFIX, "");
			StringBuffer likeString = new StringBuffer(prefix).append(identifier).append(suffix);
			criteria.add(Expression.like("identifier", likeString.toString()));
		}
		// if the regex is present, search on that
		else {
			regex = regex.replace("@SEARCH@", identifier);
{'fraction_non_alphanumeric': 0.10834597875569044, 'fraction_numerical': 0.0009863429438543246, 'mean_word_length': 4.855619724566859, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3833414', 'n_tokens_mistral': 4213, 'n_tokens_neox': 3745, 'n_words': 937}