Statements `Query` and `QueryContext` methods perform scan and grouping of row result to arbitrary `destination` structure.
-`Query(db execution.DB, destination interface{}) error` - executes statements over database connection db and stores row result in destination.
-`QueryContext(db execution.DB, context context.Context, destination interface{}) error` - executes statement with a context over database connection db and stores row result in destination.
### How scan works?
The easiest way to understand how scan works is by an example.
Lets say we want to retrieve list of cities, with list of customers for each city, and address for each customer.
For simplicity we will narrow the choice to 'London' and 'York'.
`Query` uses reflection to introspect destination type structure, and result set column names(aliases), to be able to map result set data to destination object.
Note that camel case of result set column names(aliases) is the same as `model type name`.`field name`.
For instance `city.city_id` -> `City.CityID`. This is being used to find appropriate column for each destination model field.
It is not an error if there is not a column for each destination model field.
Lets see in general how `Query` works row by row:
- ROW 1:
- dest is slice of structs, so new struct object is initialized and scan proceeds to next step.
-`city.city_id` and `city.city` columns (values `312` and `"London"`) are used to initialize `CityID` and `City` fields of `model.City` object.
-`Customers` is a slice of structs, so new struct object is initialized and scan proceeds to next step.
-`customer.customer_id` and `customer.last_name` is used to initialize fields in `model.Customer` object.
-`address.address_id` and `address.address` is used to initialize fields in `Address model.Address`
- because at least one field of struct is being initialized struct is added to `Customers []struct` and cached by parent and
struct primary key fields([more about primary key fields](TODO)). Primary keys used for caching are `CityID`, `CustomerID` and `AddressID` of `model.City`, `model.Customer`
and `model.Address`
- because at least one field of struct is being initialized struct is added to `var dest []struct` and cached by
struct primary key fields. Primary keys used for caching is only `CityID` from `model.City`
- ROW 2:
- Does not initialize new struct object for `dest []struct` but pulls one from the cache, because `city` with `city_id` of `312` has
already being processed. Following steps are the same as above, new objects are created, stored in slice and cached.
- ROW 3:
- steps would be similar as for the first step. Nothing is pulled from he cache, stored in slice and cached.
Lets print `dest` as a json, to visualize `Query` result:
```
[
{
"CityID": 312,
"City": "London",
"CountryID": 0,
"LastUpdate": "0001-01-01T00:00:00Z",
"Customers": [
{
"CustomerID": 252,
"StoreID": 0,
"FirstName": "",
"LastName": "Hoffman",
"Email": null,
"AddressID": 0,
"Activebool": false,
"CreateDate": "0001-01-01T00:00:00Z",
"LastUpdate": null,
"Active": null,
"Address": {
"AddressID": 256,
"Address": "1497 Yuzhou Drive",
"Address2": null,
"District": "",
"CityID": 0,
"PostalCode": null,
"Phone": "",
"LastUpdate": "0001-01-01T00:00:00Z"
}
},
{
"CustomerID": 512,
"StoreID": 0,
"FirstName": "",
"LastName": "Vines",
"Email": null,
"AddressID": 0,
"Activebool": false,
"CreateDate": "0001-01-01T00:00:00Z",
"LastUpdate": null,
"Active": null,
"Address": {
"AddressID": 517,
"Address": "548 Uruapan Street",
"Address2": null,
"District": "",
"CityID": 0,
"PostalCode": null,
"Phone": "",
"LastUpdate": "0001-01-01T00:00:00Z"
}
}
]
},
{
"CityID": 589,
"City": "York",
"CountryID": 0,
"LastUpdate": "0001-01-01T00:00:00Z",
"Customers": [
{
"CustomerID": 497,
"StoreID": 0,
"FirstName": "",
"LastName": "Sledge",
"Email": null,
"AddressID": 0,
"Activebool": false,
"CreateDate": "0001-01-01T00:00:00Z",
"LastUpdate": null,
"Active": null,
"Address": {
"AddressID": 502,
"Address": "1515 Korla Way",
"Address2": null,
"District": "",
"CityID": 0,
"PostalCode": null,
"Phone": "",
"LastUpdate": "0001-01-01T00:00:00Z"
}
}
]
}
]
```
All the fields missing source column in result set are initialized with empty value.
City of `London` has two customers, which is the product of object reuse in `ROW 2` processing.