Opa はオブジェクトをどのように MongoDB に格納するのか？

## 環境

- Opa compiler (c) MLstate -- version 1.1.1 -- build 4308
- MongoDB v2.6.0

## 方法

簡単なコードを書いてDBにデータを格納し、mongo クライアントから
結果を確認する。

## simple

``` opa
type x =
  {
    int foo,
    string bar,
    float baz,
    bool hoge,
    void fuga
  }

database dbtest {
  x /xs[{foo}]
  /xs[_]/hoge = { false }
}

/dbtest/xs[{foo: 1}] <- {bar: "hello", baz: 3.14, hoge: true, fuga: {}}
```

```
> db.xs.find()
{
        "_id" : ObjectId("539f3e9d68a84ebe3504cd4e"),
        "foo" : NumberLong(1),
        "bar" : "hello",
        "hoge" : true,
        "baz" : 3.14
}
```

- なんか bool のフィールドにはデフォルト値を設定しないとコンパイラに怒られた。
- えっ、void は入らないの？
- それ以外はフツー。


## tuple

``` opa
type x =
  {
    int foo,
    (string, int) bar
  }

database dbtest {
  x /xs[{foo}]
}

/dbtest/xs[{foo: 1}] <- {bar: ("hello", 3)}
```

```
> db.xs.find()
{
        "_id" : ObjectId("539f3e9d68a84ebe3504cd4e"),
        "foo" : NumberLong(1),
        "bar" : {
                "f2" : NumberLong(3),
                "f1" : "hello"
        }
}
```

- タプルは自動的に "f1", "f2", ... というプロパティが作られて入る。

## variant

``` opa
type s = {Foo} or {int Bar} or {string Xyz} or {(int, string) Blah}
type x = {
  s foo,
  s bar
}

database dbtest {
  x /xs[{foo}]
}


/dbtest/xs[{foo: {Foo}}] <- {bar: {Bar: 1}}
/dbtest/xs[{foo: {Xyz: "aaa"}}] <- {bar: {Blah: (3, "hoge")}}

```

```
> db.xs.find()
{
        "_id" : ObjectId("539f524468a84ebe3504cd53"),
        "foo" : {
                "Foo" : null
        },
        "bar" : {
                "Bar" : NumberLong(1)
        }
}
{
        "_id" : ObjectId("539f524468a84ebe3504cd54"),
        "foo" : {
                "Xyz" : "aaa"
        },
        "bar" : {
                "Blah" : {
                        "f2" : "hoge",
                        "f1" : NumberLong(3)
                }
        }
}
```

- コンストラクタ名がオブジェクトのプロパティ名となる。
- https://github.com/MLstate/opalang/wiki/The-type-system に "type color = { Red } or { Green } or { Blue } defines color as a sum with three cases, each of them implicitly of type void." と書かれているので、`"Foo" : null` は納得。


## option

``` opa
type x = {
  int foo,
  option(int) bar
}


database dbtest {
  x /xs[{foo}]

}

/dbtest/xs[{foo: 1}] <- {bar: {some: 1} }
/dbtest/xs[{foo: 2}] <- {bar: {none} }

```

```
> db.xs.find()
{
        "_id" : ObjectId("53a04f9568a84ebe3504cd67"),
        "foo" : NumberLong(1),
        "bar" : {
                "some" : NumberLong(1)
        }
}
{
        "_id" : ObjectId("53a04f9568a84ebe3504cd68"),
        "foo" : NumberLong(2),
        "bar" : {
                "none" : null
        }
}
```

- option も variant として定義されてるだけなので、当然の結果ですねー。

## foreign

``` opa
type t = {
  string foo,
  int bar
}

type x = {
  t first,
  t second,
  int third
}

database dbtest {
  t /ts[{foo}]
  x /xs[{first, second}]
}

s1 = {foo: "hello", bar: 100}
s2 = {foo: "world", bar: 200}
/dbtest/ts[{foo: "hello"}] <- s1
/dbtest/ts[{foo: "world"}] <- s2
/dbtest/xs[{first: s1, second: s2}] <- {third: 111}

```

```
> db.ts.find()
{
        "_id" : ObjectId("539f563168a84ebe3504cd57"),
        "foo" : "hello",
        "bar" : NumberLong(100)
}
{
        "_id" : ObjectId("539f563168a84ebe3504cd58"),
        "foo" : "world",
        "bar" : NumberLong(200)
}

> db.xs.find()
{
        "_id" : ObjectId("539f563168a84ebe3504cd59"),
        "first" : {
                "foo" : "hello",
                "bar" : NumberLong(100)
        },
        "second" : {
                "foo" : "world",
                "bar" : NumberLong(200)
        },
        "third" : NumberLong(111)
}
```

- _id で参照する形にはならず、first にも second にも展開されたオブジェクトがそのまま入ってます。

## list

``` opa
type x = {
  int foo,
  list(int) bar
}


database dbtest {
  x /xs[{foo}]
}

/dbtest/xs[{foo: 1}] <- {bar: [1]}
/dbtest/xs[{foo: 2}] <- {bar: [1, 2, 3]}
/dbtest/xs[{foo: 3}] <- {bar: []}
```

```
> db.xs.find()
{
        "_id" : ObjectId("53a046dd68a84ebe3504cd5e"),
        "foo" : NumberLong(1),
        "bar" : [
                NumberLong(1)
        ]
}
{
        "_id" : ObjectId("53a046dd68a84ebe3504cd5f"),
        "foo" : NumberLong(2),
        "bar" : [
                NumberLong(3),
                NumberLong(2),
                NumberLong(1)
        ]
}
{
        "_id" : ObjectId("53a046dd68a84ebe3504cd60"),
        "foo" : NumberLong(3),
        "bar" : [ ]
}
```

- list は配列として入る。
- [1, 2, 3] が NumberLong(3), NumberLong(2), NumberLong(1) の順序で入っているがなんだこれは？
- 空は空配列として入る。


## map

``` opa
type x = {
  int foo,
  map(string, float) bar
}


database dbtest {
  x /xs[{foo}]
}

/dbtest/xs[{foo: 1}] <- {bar: Map.From.assoc_list([("pi", 3.14), ("e", 2.72)])}

```

```
> db.xs.find()
{
        "_id" : ObjectId("53a049e068a84ebe3504cd62"),
        "foo" : NumberLong(1),
        "bar" : {
                ""pi"" : 3.14,
                ""e"" : 2.72
        }
}
```

- map は object として入る。が、キーが文字列のときは二重にクォートされるんだな。


## set

```
type x = {
  int foo,
  intset bar
}


database dbtest {
  x /xs[{foo}]

}

/dbtest/xs[{foo: 1}] <- {bar: Set.From.list([1, 3, 1, 5])}

```

```
> db.xs.find()
{
        "_id" : ObjectId("53a0538968a84ebe3504cd6e"),
        "foo" : NumberLong(1),
        "bar" : {
                "5" : null,
                "3" : null,
                "1" : null
        }
}
```

- set は value が null の map なのだな。

## xhtml

```
type x = {
  int foo,
  xhtml bar
}

database dbtest {
  x /xs[{foo}]
}


/dbtest/xs[{foo: 1}] <- {bar: <p>Hello</p>}

```

```
$ make run
### Building executable dbtest.exe 
opa --opx-dir _build --import-package stdlib.database.mongo    --conf opa.conf --conf-opa-files  -o dbtest.exe --build-dir _build/dbtest.exe
Error: File "src/model.opa", line 7, characters 1-34, (7:1-9:1 | 39-72)
Elements of type Dom.event -> void cannot be stored in the database
make: *** [dbtest.exe] Error 1
```

- ほほーぅ。xhtml 型は DB には入れられない。というか、function 型がダメ？

## function

``` opa
type x = {
  int foo,
  (int -> int) bar
}


database dbtest {
  x /xs[{foo}]

}

/dbtest/xs[{foo: 1}] <- {bar: function (x) { x * 2 } }

```

```
$ make run
### Building executable dbtest.exe 
opa --opx-dir _build --import-package stdlib.database.mongo    --conf opa.conf --conf-opa-files  -o dbtest.exe --build-dir _build/dbtest.exe
Error: File "src/model.opa", line 7, characters 1-35, (7:1-10:1 | 46-80)
Elements of type int -> int cannot be stored in the database
make: *** [dbtest.exe] Error 1
```

- やはり関数はダメ、と。


以上、だいたいこんなもんですかね。