// file      : common/id/composite/test.hxx
// copyright : Copyright (c) 2009-2017 Code Synthesis Tools CC
// license   : GNU GPL v2; see accompanying LICENSE file

#ifndef TEST_HXX
#define TEST_HXX

#include <string>
#include <vector>

#include <odb/core.hxx>

#pragma db value
struct scomp
{
  scomp () {}
  scomp (const std::string& s1, const std::string& s2, const std::string& s3)
      : str1 (s1), str2 (s2), str3 (s3)
  {
  }

  std::string str1;
  std::string str2;
  std::string str3;
};

inline bool
operator== (const scomp& x, const scomp& y)
{
  return x.str1 == y.str1 && x.str2 == y.str2 && x.str3 == y.str3;
}

inline bool
operator< (const scomp& x, const scomp& y)
{
  return x.str1 < y.str1 ||
    (x.str1 == y.str1 && x.str2 < y.str2) ||
    (x.str1 == y.str1 && x.str2 == y.str2 && x.str3 < y.str3);
}

#pragma db value
struct ncomp
{
  ncomp () {}
  ncomp (unsigned short n1, unsigned short n2, unsigned short n3)
      : num1 (n1), num2 (n2), num3 (n3)
  {
  }

  unsigned short num1;
  unsigned short num2;
  unsigned short num3;
};

inline bool
operator== (const ncomp& x, const ncomp& y)
{
  return x.num1 == y.num1 && x.num2 == y.num2 && x.num3 == y.num3;
}

inline bool
operator< (const ncomp& x, const ncomp& y)
{
  return x.num1 < y.num1 ||
    (x.num1 == y.num1 && x.num2 < y.num2) ||
    (x.num1 == y.num1 && x.num2 == y.num2 && x.num3 < y.num3);
}

// Test object with composite id, container.
//
#pragma db namespace table("t1_")
namespace test1
{
  #pragma db object
  struct object
  {
    object () {}
    object (const scomp& i, unsigned long n): id (i), num (n) {}

    #pragma db id
    scomp id;

    unsigned long num;
    std::vector<scomp> vec;
  };

  inline bool
  operator== (const object& x, const object& y)
  {
    return x.id == y.id && x.num == y.num && x.vec == y.vec;
  }
}

// Test to-one and to-many relationships with composite id as well as
// queries and views.
//
#pragma db namespace table("t2_")
namespace test2
{
  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i): id (i) {}

    #pragma db id
    scomp id;
  };

  #pragma db object
  struct object2
  {
    object2 (): o1 (0) {}
    object2 (const ncomp& i): id (i), o1 (0) {}
    ~object2 () {delete o1;}

    #pragma db id
    ncomp id;

    object1* o1;
  };

  #pragma db object
  struct object3
  {
    object3 () {}
    object3 (const ncomp& i): id (i) {}

    ~object3 ()
    {
      for (std::vector<object1*>::iterator i (o1.begin ());
           i != o1.end (); ++i)
        delete *i;
    }

    #pragma db id
    ncomp id;

    std::vector<object1*> o1;
  };

  // Test second-level query pointer test as well as pointers in
  // composite types.
  //
  #pragma db value
  struct comp
  {
    comp (): o2 (0) {}
    ~comp () {delete o2;}

    object2* o2;
  };

  #pragma db object
  struct object4
  {
    object4 () {}
    object4 (const ncomp& i): id (i) {}

    #pragma db id
    ncomp id;

    comp c;
  };

  #pragma db view object(object2) object(object1)
  struct view2
  {
    #pragma db column (object2::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };

  #pragma db view object(object3) object(object1)
  struct view3
  {
    #pragma db column (object3::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };

  #pragma db view object(object4) object(object2) object(object1)
  struct view4
  {
    #pragma db column (object4::id.num3)
    unsigned short num4;

    #pragma db column (object2::id.num3)
    unsigned short num2;

    #pragma db column (object1::id.str3)
    std::string str;
  };
}

// Test one-to-one(i) relationship with composite id.
//
#pragma db namespace table("t3_")
namespace test3
{
  struct object2;

  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i): id (i) {}

    #pragma db id
    scomp id;

    #pragma db inverse(o1)
    object2* o2;
  };

  #pragma db object
  struct object2
  {
    object2 (): o1 (0) {}
    object2 (const ncomp& i): id (i), o1 (0) {}
    ~object2 () {delete o1;}

    #pragma db id
    ncomp id;

    object1* o1;
  };

  #pragma db view object(object2) object(object1)
  struct view
  {
    #pragma db column (object2::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };
}

// Test many-to-one(i) relationship with composite id.
//
#pragma db namespace table("t4_")
namespace test4
{
  struct object2;

  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i): id (i) {}

    #pragma db id
    scomp id;

    #pragma db inverse(o1)
    object2* o2;
  };

  #pragma db object
  struct object2
  {
    object2 () {}
    object2 (const ncomp& i): id (i) {}

    ~object2 ()
    {
      for (std::vector<object1*>::iterator i (o1.begin ());
           i != o1.end (); ++i)
        delete *i;
    }

    #pragma db id
    ncomp id;

    std::vector<object1*> o1;
  };

  #pragma db view object(object2) object(object1)
  struct view
  {
    #pragma db column (object2::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };
}

// Test one-to-many(i) relationship with composite id.
//
#pragma db namespace table("t5_")
namespace test5
{
  struct object2;

  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i): id (i) {}

    #pragma db id
    scomp id;

    object2* o2;
  };

  #pragma db object
  struct object2
  {
    object2 () {}
    object2 (const ncomp& i): id (i) {}

    ~object2 ()
    {
      for (std::vector<object1*>::iterator i (o1.begin ());
           i != o1.end (); ++i)
        delete *i;
    }

    #pragma db id
    ncomp id;

    #pragma db inverse(o2)
    std::vector<object1*> o1;
  };

  #pragma db view object(object2) object(object1)
  struct view
  {
    #pragma db column (object2::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };
}

// Test many-to-many(i) relationship with composite id.
//
#pragma db namespace table("t6_")
namespace test6
{
  struct object2;

  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i): id (i) {}

    #pragma db id
    scomp id;

    std::vector<object2*> o2;
  };

  #pragma db object
  struct object2
  {
    object2 () {}
    object2 (const ncomp& i): id (i) {}

    ~object2 ()
    {
      for (std::vector<object1*>::iterator i (o1.begin ());
           i != o1.end (); ++i)
        delete *i;
    }

    #pragma db id
    ncomp id;

    #pragma db inverse(o2)
    std::vector<object1*> o1;
  };

  #pragma db view object(object2) object(object1)
  struct view
  {
    #pragma db column (object2::id.num3)
    unsigned short num;

    #pragma db column (object1::id.str3)
    std::string str;
  };
}

// Test object with composite id and version (optimistic concurrency).
//
#pragma db namespace table("t7_")
namespace test7
{
  #pragma db object optimistic
  struct object
  {
    object () {}
    object (const scomp& i, unsigned long n): id (i), num (n) {}

    #pragma db id
    scomp id;

    #pragma db version
    unsigned long ver;

    unsigned long num;
  };

  inline bool
  operator== (const object& x, const object& y)
  {
    return x.id == y.id && x.ver == y.ver && x.num == y.num;
  }
}

// Test composite NULL pointers.
//
#pragma db namespace table("t8_")
namespace test8
{
  #pragma db object
  struct object1
  {
    object1 () {}
    object1 (const scomp& i, unsigned long n): id (i), num (n) {}

    #pragma db id
    scomp id;

    unsigned long num;
  };

  inline bool
  operator== (const object1& x, const object1& y)
  {
    return x.id == y.id && x.num == y.num;
  }

  #pragma db object
  struct object2
  {
    object2 (): o1 (0) {}
    ~object2 () {delete o1;}

    #pragma db id auto
    unsigned long id;

    object1* o1;
  };

  #pragma db object
  struct object3
  {
    ~object3 ()
    {
      for (std::vector<object1*>::iterator i (o1.begin ());
           i != o1.end (); ++i)
        delete *i;
    }

    #pragma db id auto
    unsigned long id;

    std::vector<object1*> o1;
  };
}

// Test composite id definition inside object.
//
#pragma db namespace table("t9_")
namespace test9
{
  #pragma db object
  struct object
  {
    object (unsigned long n = 0, const std::string& s = "")
    {
      id_.num = n;
      id_.str = s;
    }

    unsigned long num () const {return id_.num;}
    const std::string& str () const {return id_.str;}

    std::vector<int> v;

  private:
    friend class odb::access;

    #pragma db value
    struct comp
    {
      unsigned long num;
      std::string str;

      bool
      operator< (const comp& x) const
      {
        return num < x.num || (num == x.num && str < x.str);
      }
    };

    #pragma db id
    comp id_;
  };

  inline bool
  operator== (const object& x, const object& y)
  {
    return x.num () == y.num () && x.str () == y.str () && x.v == y.v;
  }
}


#endif // TEST_HXX