// Path: src/main/java/org/javiermf/features/exceptions/ObjectNotFoundException.java
// public class ObjectNotFoundException extends RuntimeException {
//     public ObjectNotFoundException(String productName) {
//         super(String.format("Object with id %s has not been found", productName));
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/Feature.java
// @Entity
// public class Feature {
// 
//     @Id
//     @GeneratedValue
//     Long id;
// 
//     @Column(nullable = false)
//     String name;
// 
//     @Column
//     String description;
// 
//     @JsonIgnore
//     @ManyToOne
//     Product product;
// 
//     @JsonIgnore
//     @ManyToMany(mappedBy = "activedFeatures")
//     Set<ProductConfiguration> inConfigurations;
// 
//     public static Feature withName(Product product, String featureName) {
//         Feature feature = new Feature();
//         feature.name = featureName;
//         feature.product = product;
//         return feature;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     public String getDescription() {
//         return description;
//     }
// 
//     public void setDescription(String description) {
//         this.description = description;
//     }
// 
//     public Product getProduct() {
//         return product;
//     }
// 
//     public void setProduct(Product product) {
//         this.product = product;
//     }
// 
//     public Long getId() {
//         return id;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof Feature)) return false;
// 
//         Feature feature = (Feature) o;
// 
//         if (!name.equals(feature.name)) return false;
//         return product.equals(feature.product);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = name.hashCode();
//         result = 31 * result + product.hashCode();
//         return result;
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/Product.java
// @Entity
// public class Product {
// 
//     @Id
//     @GeneratedValue
//     Long id;
// 
//     @Column(nullable = false)
//     String name;
// 
//     @OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
//     Set<Feature> productFeatures = new HashSet<Feature>();
// 
//     @OneToMany(mappedBy = "forProduct", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
//     Set<FeatureConstraint> productFeatureConstraints = new HashSet<FeatureConstraint>();
// 
//     @JsonProperty("features")
//     public Set<Feature> getProductFeatures() {
//         return productFeatures;
//     }
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void addFeature(Feature feature) {
//         productFeatures.add(feature);
//     }
// 
//     public void removeFeature(Feature feature) {
//         productFeatures.remove(feature);
//     }
// 
//     public static Product buildWithFeatures(String... featureNames) {
//         Product product = new Product();
//         for (String featureName : featureNames) {
//             product.addFeature(Feature.withName(product, featureName));
//         }
// 
//         return product;
// 
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     @JsonProperty("constraints")
//     public Set<FeatureConstraint> getProductFeatureConstraints() {
//         return productFeatureConstraints;
//     }
// 
//     public Feature findProductFeatureByName(String featureName) {
//         for (Feature feature : getProductFeatures()) {
//             if (feature.name.equalsIgnoreCase(featureName)) {
//                 return feature;
//             }
//         }
// 
//         throw new ObjectNotFoundException(featureName);
//     }
// 
//     public boolean hasFeatureNamed(String featureName) {
//         for (Feature feature : getProductFeatures()) {
//             if (feature.name.equalsIgnoreCase(featureName)) {
//                 return true;
//             }
//         }
// 
//         return false;
//     }
// 
//     public void addFeatureConstraint(FeatureConstraint constraint) {
//         productFeatureConstraints.add(constraint);
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/constraints/FeatureConstraint.java
// @Entity
// @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
// public abstract class FeatureConstraint {
// 
//     @Id
//     @GeneratedValue(strategy = GenerationType.SEQUENCE)
//     Long id;
// 
//     @ManyToOne
//     Product forProduct;
// 
//     public abstract String getType();
// 
//     public abstract EvaluationResult evaluateConfiguration(EvaluationResult currentResult, ProductConfiguration configuration);
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void setId(Long id) {
//         this.id = id;
//     }
// 
//     public void setForProduct(Product forProduct) {
//         this.forProduct = forProduct;
//     }
// }


import com.mysema.query.jpa.impl.JPADeleteClause;
import com.mysema.query.jpa.impl.JPAQuery;
import org.javiermf.features.exceptions.ObjectNotFoundException;
import org.javiermf.features.models.Feature;
import org.javiermf.features.models.Product;
import org.javiermf.features.models.QFeature;
import org.javiermf.features.models.QProduct;
import org.javiermf.features.models.constraints.FeatureConstraint;
import org.javiermf.features.models.constraints.QFeatureConstraint;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
package org.javiermf.features.daos;



@Repository
public class ProductsDAO {

    @PersistenceContext
    private EntityManager entityManager;

    QProduct qProduct = QProduct.product;
    QFeature qFeature = QFeature.feature;
    QFeatureConstraint qFeatureConstraint = QFeatureConstraint.featureConstraint;

// Path: src/main/java/org/javiermf/features/exceptions/ObjectNotFoundException.java
// public class ObjectNotFoundException extends RuntimeException {
//     public ObjectNotFoundException(String productName) {
//         super(String.format("Object with id %s has not been found", productName));
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/Feature.java
// @Entity
// public class Feature {
// 
//     @Id
//     @GeneratedValue
//     Long id;
// 
//     @Column(nullable = false)
//     String name;
// 
//     @Column
//     String description;
// 
//     @JsonIgnore
//     @ManyToOne
//     Product product;
// 
//     @JsonIgnore
//     @ManyToMany(mappedBy = "activedFeatures")
//     Set<ProductConfiguration> inConfigurations;
// 
//     public static Feature withName(Product product, String featureName) {
//         Feature feature = new Feature();
//         feature.name = featureName;
//         feature.product = product;
//         return feature;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     public String getDescription() {
//         return description;
//     }
// 
//     public void setDescription(String description) {
//         this.description = description;
//     }
// 
//     public Product getProduct() {
//         return product;
//     }
// 
//     public void setProduct(Product product) {
//         this.product = product;
//     }
// 
//     public Long getId() {
//         return id;
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (!(o instanceof Feature)) return false;
// 
//         Feature feature = (Feature) o;
// 
//         if (!name.equals(feature.name)) return false;
//         return product.equals(feature.product);
// 
//     }
// 
//     @Override
//     public int hashCode() {
//         int result = name.hashCode();
//         result = 31 * result + product.hashCode();
//         return result;
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/Product.java
// @Entity
// public class Product {
// 
//     @Id
//     @GeneratedValue
//     Long id;
// 
//     @Column(nullable = false)
//     String name;
// 
//     @OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
//     Set<Feature> productFeatures = new HashSet<Feature>();
// 
//     @OneToMany(mappedBy = "forProduct", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
//     Set<FeatureConstraint> productFeatureConstraints = new HashSet<FeatureConstraint>();
// 
//     @JsonProperty("features")
//     public Set<Feature> getProductFeatures() {
//         return productFeatures;
//     }
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void addFeature(Feature feature) {
//         productFeatures.add(feature);
//     }
// 
//     public void removeFeature(Feature feature) {
//         productFeatures.remove(feature);
//     }
// 
//     public static Product buildWithFeatures(String... featureNames) {
//         Product product = new Product();
//         for (String featureName : featureNames) {
//             product.addFeature(Feature.withName(product, featureName));
//         }
// 
//         return product;
// 
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public void setName(String name) {
//         this.name = name;
//     }
// 
//     @JsonProperty("constraints")
//     public Set<FeatureConstraint> getProductFeatureConstraints() {
//         return productFeatureConstraints;
//     }
// 
//     public Feature findProductFeatureByName(String featureName) {
//         for (Feature feature : getProductFeatures()) {
//             if (feature.name.equalsIgnoreCase(featureName)) {
//                 return feature;
//             }
//         }
// 
//         throw new ObjectNotFoundException(featureName);
//     }
// 
//     public boolean hasFeatureNamed(String featureName) {
//         for (Feature feature : getProductFeatures()) {
//             if (feature.name.equalsIgnoreCase(featureName)) {
//                 return true;
//             }
//         }
// 
//         return false;
//     }
// 
//     public void addFeatureConstraint(FeatureConstraint constraint) {
//         productFeatureConstraints.add(constraint);
//     }
// }
// 
// Path: src/main/java/org/javiermf/features/models/constraints/FeatureConstraint.java
// @Entity
// @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
// public abstract class FeatureConstraint {
// 
//     @Id
//     @GeneratedValue(strategy = GenerationType.SEQUENCE)
//     Long id;
// 
//     @ManyToOne
//     Product forProduct;
// 
//     public abstract String getType();
// 
//     public abstract EvaluationResult evaluateConfiguration(EvaluationResult currentResult, ProductConfiguration configuration);
// 
//     public Long getId() {
//         return id;
//     }
// 
//     public void setId(Long id) {
//         this.id = id;
//     }
// 
//     public void setForProduct(Product forProduct) {
//         this.forProduct = forProduct;
//     }
// }


// Path: src/main/java/org/javiermf/features/daos/ProductsDAO.java
import com.mysema.query.jpa.impl.JPADeleteClause;
import com.mysema.query.jpa.impl.JPAQuery;
import org.javiermf.features.exceptions.ObjectNotFoundException;
import org.javiermf.features.models.Feature;
import org.javiermf.features.models.Product;
import org.javiermf.features.models.QFeature;
import org.javiermf.features.models.QProduct;
import org.javiermf.features.models.constraints.FeatureConstraint;
import org.javiermf.features.models.constraints.QFeatureConstraint;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

package org.javiermf.features.daos;



@Repository
public class ProductsDAO {

    @PersistenceContext
    private EntityManager entityManager;

    QProduct qProduct = QProduct.product;
    QFeature qFeature = QFeature.feature;
    QFeatureConstraint qFeatureConstraint = QFeatureConstraint.featureConstraint;

    public List<Product> findAll() {