Skip to content

Commit 7ef5c17

Browse files
authored
DOCSP-38477: bson macros (#8)
1 parent c9d3744 commit 7ef5c17

File tree

2 files changed

+164
-1
lines changed

2 files changed

+164
-1
lines changed

source/bson.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ BSON Implementation
1414
.. toctree::
1515

1616
/bson/documents/
17+
/bson/macros/
1718

1819
The BSON library comprehensively supports `BSON
1920
<https://bsonspec.org/>`__, the data storage and network transfer format
@@ -34,7 +35,8 @@ implementation:
3435

3536
- :ref:`scala-documents`: describes the driver’s support for BSON document
3637
representations
37-
- Macros: describes the case classes you can use to represent documents in a collection
38+
- :ref:`scala-macros`: describes the case classes you can use to
39+
represent documents in a collection
3840
- Extended JSON: describes the driver’s support for MongoDB Extended
3941
JSON
4042

source/bson/macros.txt

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
.. _scala-macros:
2+
3+
======
4+
Macros
5+
======
6+
7+
.. facet::
8+
:name: genre
9+
:values: reference
10+
11+
.. meta::
12+
:keywords: representation, storage, codec
13+
14+
.. contents:: On this page
15+
:local:
16+
:backlinks: none
17+
:depth: 2
18+
:class: singlecol
19+
20+
Overview
21+
--------
22+
23+
The {+driver-short+} allows you to use case classes to represent
24+
documents in a collection by using the ``Macros`` helper. Simple case classes and
25+
nested case classes are supported. Hierarchical modeling can be achieved
26+
by using a sealed trait or class and then by having case classes implement the
27+
parent trait.
28+
29+
Many simple Scala types are supported and can be marshaled into their
30+
corresponding ``BsonValue`` type. The following list describes Scala types and their
31+
type-safe BSON representation:
32+
33+
.. list-table::
34+
:header-rows: 1
35+
:class: compatibility-large
36+
37+
* - Scala Type
38+
- BSON Type
39+
40+
* - Case class
41+
- Document
42+
43+
* - ``Iterable``
44+
- Array
45+
46+
* - ``Date``
47+
- Date
48+
49+
* - ``Boolean``
50+
- Boolean
51+
52+
* - ``Double``
53+
- Double
54+
55+
* - ``Int``
56+
- Int32
57+
58+
* - ``Long``
59+
- Int64
60+
61+
* - ``String``
62+
- String
63+
64+
* - ``Array[Byte]``
65+
- Binary
66+
67+
* - ``None``
68+
- Null
69+
70+
Creating Codecs
71+
---------------
72+
73+
To create a codec for your case class, use the ``Macros`` object helper
74+
methods. You should use the
75+
``Macros.createCodecProvider()`` method to create a ``CodecProvider``. A
76+
``CodecProvider`` passes the configured ``CodecRegistry`` to the underlying
77+
``Codec`` and provides access to all the configured codecs.
78+
79+
To create a ``CodecProvider``, set the case class type when calling
80+
``createCodecProvider()`` as shown in the following code:
81+
82+
.. code-block:: scala
83+
84+
import org.mongodb.scala.bson.codecs.Macros
85+
86+
case class Person(firstName: String, secondName: String)
87+
88+
val personCodecProvider = Macros.createCodecProvider[Person]()
89+
90+
The ``personCodecProvider`` can then be used when converted into a
91+
``CodecRegistry`` by using the ``CodecRegistries`` static helpers. The
92+
following code creates a new codec registry, combining the new ``personCodecProvider``
93+
and the default codec registry:
94+
95+
.. code-block:: scala
96+
97+
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
98+
import org.bson.codecs.configuration.CodecRegistries.{fromRegistries, fromProviders}
99+
100+
val codecRegistry = fromRegistries( fromProviders(personCodecProvider), DEFAULT_CODEC_REGISTRY )
101+
102+
The ``Macros`` helper also has an implicit ``createCodecProvider()`` method that
103+
takes the ``Class[T]`` and creates a ``CodecProvider`` from that. This method
104+
is more concise especially when defining multiple providers:
105+
106+
.. code-block:: scala
107+
108+
import org.mongodb.scala.bson.codecs.Macros._
109+
import org.mongodb.scala.bson.codecs.DEFAULT_CODEC_REGISTRY
110+
import org.bson.codecs.configuration.CodecRegistries.{fromRegistries, fromProviders}
111+
112+
case class Address(firstLine: String, secondLine: String, thirdLine: String, town: String, zipCode: String)
113+
case class ClubMember(person: Person, address: Address, paid: Boolean)
114+
115+
val codecRegistry = fromRegistries( fromProviders(classOf[ClubMember], classOf[Person], classOf[Address]), DEFAULT_CODEC_REGISTRY )
116+
117+
Sealed Classes and ADTs
118+
-----------------------
119+
120+
Hierarchical class structures are supported through sealed traits and
121+
classes. Each subclass is handled specifically by the generated codec,
122+
so you only need to create a ``CodecProvider`` for the parent sealed
123+
trait or class. Internally an extra field (``_t``) is stored alongside the data
124+
so that the correct subclass can be hydrated when decoding the data.
125+
The following code is an example of a tree-like structure containing branch and leaf
126+
nodes:
127+
128+
.. code-block:: scala
129+
130+
sealed class Tree
131+
case class Branch(b1: Tree, b2: Tree, value: Int) extends Tree
132+
case class Leaf(value: Int) extends Tree
133+
134+
val codecRegistry = fromRegistries( fromProviders(classOf[Tree]), DEFAULT_CODEC_REGISTRY )
135+
136+
Options and None Values
137+
-----------------------
138+
139+
By default, ``Option`` values are always stored. In driver v2.1.0, new
140+
helpers were added so that ``None`` values would not be stored in the
141+
database. In the following example, the driver only stores an address if
142+
if one is present:
143+
144+
.. code-block:: scala
145+
146+
import org.mongodb.scala.bson.codecs.Macros
147+
148+
case class Person(firstName: String, secondName: String, address: Option[Address])
149+
150+
val personCodecProvider = Macros.createCodecProviderIgnoreNone[Person]()
151+
152+
Alternative Field Names
153+
-----------------------
154+
155+
The ``BsonProperty`` annotation can be used to configure the BSON field
156+
key to be used for a given property. The following example uses the
157+
``BsonProperty`` annotation to change how the ``firstName`` field is stored:
158+
159+
.. code-block:: scala
160+
161+
case class Person(@BsonProperty("first_name") firstName: String, secondName: String)

0 commit comments

Comments
 (0)