2021-06-03 03:36:25 +00:00
|
|
|
import {Model} from './Model'
|
|
|
|
import {AbstractResultIterable} from '../builder/result/AbstractResultIterable'
|
|
|
|
import {Connection} from '../connection/Connection'
|
|
|
|
import {ModelBuilder} from './ModelBuilder'
|
|
|
|
import {Container, Instantiable} from '../../di'
|
|
|
|
import {QueryRow} from '../types'
|
2021-11-11 22:42:37 +00:00
|
|
|
import {collect, Collection} from '../../util'
|
2021-06-02 01:59:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Implementation of the result iterable that returns query results as instances of the defined model.
|
|
|
|
*/
|
|
|
|
export class ModelResultIterable<T extends Model<T>> extends AbstractResultIterable<T> {
|
|
|
|
constructor(
|
|
|
|
public readonly builder: ModelBuilder<T>,
|
|
|
|
public readonly connection: Connection,
|
|
|
|
/** The model that should be instantiated for each row. */
|
2021-06-03 03:36:25 +00:00
|
|
|
protected readonly ModelClass: Instantiable<T>,
|
|
|
|
) {
|
|
|
|
super(builder, connection)
|
|
|
|
}
|
2021-06-02 01:59:40 +00:00
|
|
|
|
2021-06-03 03:36:25 +00:00
|
|
|
public get selectSQL(): string {
|
2021-06-02 01:59:40 +00:00
|
|
|
return this.connection.dialect().renderSelect(this.builder)
|
|
|
|
}
|
|
|
|
|
2021-06-03 03:36:25 +00:00
|
|
|
async at(i: number): Promise<T | undefined> {
|
2021-06-02 01:59:40 +00:00
|
|
|
const query = this.connection.dialect().renderRangedSelect(this.selectSQL, i, i + 1)
|
|
|
|
const row = (await this.connection.query(query)).rows.first()
|
|
|
|
|
|
|
|
if ( row ) {
|
2021-11-11 22:42:37 +00:00
|
|
|
const inflated = await this.inflateRow(row)
|
|
|
|
await this.processEagerLoads(collect([inflated]))
|
|
|
|
return inflated
|
2021-06-02 01:59:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async range(start: number, end: number): Promise<Collection<T>> {
|
|
|
|
const query = this.connection.dialect().renderRangedSelect(this.selectSQL, start, end)
|
2021-11-11 22:42:37 +00:00
|
|
|
const inflated = await (await this.connection.query(query)).rows.promiseMap<T>(row => this.inflateRow(row))
|
|
|
|
await this.processEagerLoads(inflated)
|
|
|
|
return inflated
|
2021-06-02 01:59:40 +00:00
|
|
|
}
|
|
|
|
|
2021-06-03 03:36:25 +00:00
|
|
|
async count(): Promise<number> {
|
2021-06-02 01:59:40 +00:00
|
|
|
const query = this.connection.dialect().renderCount(this.selectSQL)
|
|
|
|
const result = (await this.connection.query(query)).rows.first()
|
|
|
|
return result?.extollo_render_count ?? 0
|
|
|
|
}
|
|
|
|
|
|
|
|
async all(): Promise<Collection<T>> {
|
|
|
|
const result = await this.connection.query(this.selectSQL)
|
2021-11-11 22:42:37 +00:00
|
|
|
const inflated = await result.rows.promiseMap<T>(row => this.inflateRow(row))
|
|
|
|
await this.processEagerLoads(inflated)
|
|
|
|
return inflated
|
2021-06-02 01:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a query row, create an instance of the configured model class from it.
|
|
|
|
* @param row
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
protected async inflateRow(row: QueryRow): Promise<T> {
|
2021-06-03 03:36:25 +00:00
|
|
|
return Container.getContainer().make<T>(this.ModelClass)
|
|
|
|
.assumeFromSource(row)
|
2021-06-02 01:59:40 +00:00
|
|
|
}
|
|
|
|
|
2021-11-11 22:42:37 +00:00
|
|
|
/**
|
|
|
|
* Eager-load eager-loaded relations for the models in the query result.
|
|
|
|
* @param results
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
protected async processEagerLoads(results: Collection<T>): Promise<void> {
|
|
|
|
const eagers = this.builder.getEagerLoadedRelations()
|
|
|
|
const model = this.make<T>(this.ModelClass)
|
|
|
|
|
|
|
|
for ( const name of eagers ) {
|
|
|
|
// TODO support nested eager loads?
|
|
|
|
|
|
|
|
const relation = model.getRelation(name)
|
|
|
|
const select = relation.buildEagerQuery(this.builder, results)
|
|
|
|
|
|
|
|
const allRelated = await select.get().collect()
|
|
|
|
allRelated.each(result => {
|
|
|
|
const resultRelation = result.getRelation(name as any)
|
|
|
|
const resultRelated = resultRelation.matchResults(allRelated as any)
|
|
|
|
resultRelation.setValue(resultRelated as any)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 03:36:25 +00:00
|
|
|
clone(): ModelResultIterable<T> {
|
2021-06-02 01:59:40 +00:00
|
|
|
return new ModelResultIterable(this.builder, this.connection, this.ModelClass)
|
|
|
|
}
|
|
|
|
}
|