@sqb/connect
Version:
Multi-dialect database connection framework written with TypeScript
138 lines (137 loc) • 5.23 kB
JavaScript
import { camelCase } from 'putil-varhelpers';
import { resolveEntityMeta } from '../util/orm.helper.js';
export class Association {
_resolved;
_source; // cached value
_target; // cached value
_sourceKey; // cached value
_targetKey; // cached value
_sourceProperty;
_targetProperty;
name;
source;
target;
sourceKey;
targetKey;
many;
constructor(name, args) {
this.name = name;
this.source = args.source;
this.target = args.target;
this.sourceKey = args.sourceKey;
this.targetKey = args.targetKey;
this.many = !!args.many;
}
async resolveSource() {
this._source = await resolveEntityMeta(this.source);
if (!this._source)
throw new Error(`Can't resolve source entity of association "${this.name}"`);
return this._source;
}
async resolveTarget() {
this._target = await resolveEntityMeta(this.target);
if (!this._target)
throw new Error(`Can't resolve target entity of association "${this.name}"`);
return this._target;
}
async resolveSourceKey() {
await this._resolveKeys();
// @ts-ignore
return this._sourceKey;
}
async resolveSourceProperty() {
await this._resolveKeys();
// @ts-ignore
return this._sourceProperty;
}
async resolveTargetKey() {
await this._resolveKeys();
// @ts-ignore
return this._targetKey;
}
async resolveTargetProperty() {
await this._resolveKeys();
// @ts-ignore
return this._targetProperty;
}
returnsMany() {
return this.many;
}
async _resolveKeys() {
const { EntityMetadata } = await import('../model/entity-metadata.js');
if (this._resolved)
return;
const source = await this.resolveSource();
const target = await this.resolveTarget();
let sourceKey = this.sourceKey || '';
let targetKey = this.targetKey || '';
if (!(sourceKey && targetKey)) {
// Try to determine key fields from foreign key from source to target
let foreign = await EntityMetadata.getForeignKeyFor(source, target);
if (foreign && foreign !== this) {
await foreign._resolveKeys();
this._sourceKey = foreign._sourceKey;
this._sourceProperty = foreign._sourceProperty;
this._targetKey = foreign._targetKey;
this._targetProperty = foreign._targetProperty;
return;
}
// Try to determine key fields from foreign key from target to source
foreign = await EntityMetadata.getForeignKeyFor(target, source);
if (foreign && foreign !== this) {
await foreign._resolveKeys();
this._sourceKey = foreign._targetKey;
this._sourceProperty = foreign._targetProperty;
this._targetKey = foreign._sourceKey;
this._targetProperty = foreign._sourceProperty;
return;
}
if (this.many) {
if (!sourceKey) {
const primaryIndexColumns = EntityMetadata.getPrimaryIndexColumns(source);
sourceKey =
primaryIndexColumns && primaryIndexColumns.length === 1
? primaryIndexColumns[0].name
: 'id';
}
if (!targetKey && sourceKey) {
// snake-case
let s = source.name[0].toLowerCase() +
source.name.substring(1) +
'_' +
sourceKey;
if (!EntityMetadata.getColumnField(target, s))
s = camelCase(s);
targetKey = s;
}
}
else {
if (!targetKey) {
const primaryIndexColumns = EntityMetadata.getPrimaryIndexColumns(target);
targetKey =
primaryIndexColumns && primaryIndexColumns.length === 1
? primaryIndexColumns[0].name
: 'id';
}
if (!sourceKey && targetKey) {
// snake-case
let s = target.name[0].toLowerCase() +
target.name.substring(1) +
'_' +
targetKey;
if (!EntityMetadata.getColumnField(source, s))
s = camelCase(s);
sourceKey = s;
}
}
}
this._targetProperty = EntityMetadata.getColumnField(target, targetKey);
if (!this._targetProperty)
throw new Error(`Can't determine target key of ${this.name}`);
this._sourceProperty = EntityMetadata.getColumnField(source, sourceKey);
if (!this._sourceProperty)
throw new Error(`Can't determine source key of ${this.name}`);
this._targetKey = targetKey;
this._sourceKey = sourceKey;
}
}