Models unit; session model; generalize session classes/interfaces
This commit is contained in:
parent
878de025d8
commit
25a37cf1a2
@ -4,3 +4,4 @@ export { default as ControllerUnit } from '../../lib/src/unit/Controllers.ts'
|
|||||||
export { default as MiddlewareUnit } from '../../lib/src/unit/Middlewares.ts'
|
export { default as MiddlewareUnit } from '../../lib/src/unit/Middlewares.ts'
|
||||||
export { default as RoutesUnit } from '../../lib/src/unit/Routes.ts'
|
export { default as RoutesUnit } from '../../lib/src/unit/Routes.ts'
|
||||||
export { default as HttpKernelUnit } from '../../lib/src/unit/HttpKernel.ts'
|
export { default as HttpKernelUnit } from '../../lib/src/unit/HttpKernel.ts'
|
||||||
|
export { default as ModelsUnit } from '../../orm/src/ModelsUnit.ts'
|
||||||
|
@ -6,4 +6,9 @@ export default {
|
|||||||
enable: true,
|
enable: true,
|
||||||
text: 'Daton',
|
text: 'Daton',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
session: {
|
||||||
|
driver: 'database', // memory | database
|
||||||
|
model: 'http:Session', // required for database
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
20
app/models/http/Session.model.ts
Normal file
20
app/models/http/Session.model.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {Field} from '../../../orm/src/model/Field.ts'
|
||||||
|
import {Type} from '../../../orm/src/db/types.ts'
|
||||||
|
import {SessionModel} from '../../../lib/src/module.ts'
|
||||||
|
|
||||||
|
export default class Session extends SessionModel {
|
||||||
|
protected static table = 'sessions'
|
||||||
|
protected static key = 'session_id'
|
||||||
|
|
||||||
|
protected static readonly CREATED_AT = 'start_time'
|
||||||
|
protected static readonly UPDATED_AT = null // No updated at
|
||||||
|
|
||||||
|
@Field(Type.int)
|
||||||
|
protected session_id!: number
|
||||||
|
|
||||||
|
@Field(Type.int)
|
||||||
|
protected user_id?: number
|
||||||
|
|
||||||
|
@Field(Type.timestamp)
|
||||||
|
protected start_time!: Date
|
||||||
|
}
|
@ -1,15 +1,11 @@
|
|||||||
import {
|
import {
|
||||||
ConfigUnit,
|
ConfigUnit, DatabaseUnit, ControllerUnit, MiddlewareUnit, RoutesUnit, HttpKernelUnit, ModelsUnit
|
||||||
DatabaseUnit,
|
|
||||||
ControllerUnit,
|
|
||||||
MiddlewareUnit,
|
|
||||||
RoutesUnit,
|
|
||||||
HttpKernelUnit
|
|
||||||
} from './bundle/daton_units.ts'
|
} from './bundle/daton_units.ts'
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
ConfigUnit,
|
ConfigUnit,
|
||||||
DatabaseUnit,
|
DatabaseUnit,
|
||||||
|
ModelsUnit,
|
||||||
HttpKernelUnit,
|
HttpKernelUnit,
|
||||||
MiddlewareUnit,
|
MiddlewareUnit,
|
||||||
ControllerUnit,
|
ControllerUnit,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Instantiable from './Instantiable.ts'
|
import Instantiable from './Instantiable.ts'
|
||||||
import {StaticClass} from './StaticClass.ts'
|
import {StaticClass} from './StaticClass.ts'
|
||||||
const DEPENDENCY_KEYS_METADATA_KEY = 'daton:di:dependencyKeys.ts'
|
const DEPENDENCY_KEYS_METADATA_KEY = 'daton:di:dependencyKeys.ts'
|
||||||
type DependencyKey = Instantiable<any> | StaticClass<any> | string
|
type DependencyKey = Instantiable<any> | StaticClass<any, any> | string
|
||||||
export { DependencyKey, DEPENDENCY_KEYS_METADATA_KEY }
|
export { DependencyKey, DEPENDENCY_KEYS_METADATA_KEY }
|
||||||
|
@ -2,7 +2,7 @@ export default interface Instantiable<T> {
|
|||||||
new(...args: any[]): T
|
new(...args: any[]): T
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInstantiable = (what: any): what is Instantiable<any> => {
|
const isInstantiable = <T>(what: any): what is Instantiable<T> => {
|
||||||
return (typeof what === 'object' || typeof what === 'function') && 'constructor' in what && typeof what.constructor === 'function'
|
return (typeof what === 'object' || typeof what === 'function') && 'constructor' in what && typeof what.constructor === 'function'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export type StaticClass<T> = Function & {prototype: T}
|
export type StaticClass<T, T2> = Function & {prototype: T} & T2
|
||||||
|
|
||||||
export function isStaticClass<T>(something: any): something is StaticClass<T> {
|
export function isStaticClass<T, T2>(something: any): something is StaticClass<T, T2> {
|
||||||
return typeof something === 'function' && typeof something.prototype !== 'undefined'
|
return typeof something === 'function' && typeof something.prototype !== 'undefined'
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Session, { SessionData } from './Session.ts'
|
import Session from './Session.ts'
|
||||||
|
import SessionInterface, { SessionData } from './SessionInterface.ts'
|
||||||
|
|
||||||
export default class MemorySession extends Session {
|
export default class MemorySession extends Session implements SessionInterface {
|
||||||
private _key!: string
|
private _key!: string
|
||||||
private _data: SessionData = {}
|
private _data: SessionData = {}
|
||||||
|
|
||||||
@ -29,4 +30,5 @@ export default class MemorySession extends Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async persist() {}
|
public async persist() {}
|
||||||
|
public async init_session(): Promise<void> {}
|
||||||
}
|
}
|
||||||
|
9
lib/src/http/session/MemorySessionFactory.ts
Normal file
9
lib/src/http/session/MemorySessionFactory.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import SessionFactory from './SessionFactory.ts'
|
||||||
|
import MemorySession from './MemorySession.ts'
|
||||||
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
|
||||||
|
export default class MemorySessionFactory extends SessionFactory {
|
||||||
|
produce(dependencies: any[], parameters: any[]): SessionInterface {
|
||||||
|
return new MemorySession()
|
||||||
|
}
|
||||||
|
}
|
@ -3,8 +3,9 @@ import {Collection} from '../../collection/Collection.ts'
|
|||||||
import Session from './Session.ts'
|
import Session from './Session.ts'
|
||||||
import SessionManager, {InvalidSessionKeyError} from './SessionManager.ts'
|
import SessionManager, {InvalidSessionKeyError} from './SessionManager.ts'
|
||||||
import Utility from '../../service/utility/Utility.ts'
|
import Utility from '../../service/utility/Utility.ts'
|
||||||
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
|
||||||
export type SessionRegistrant = { key: string, session: Session }
|
export type SessionRegistrant = { key: string, session: SessionInterface }
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class MemorySessionManager extends SessionManager {
|
export default class MemorySessionManager extends SessionManager {
|
||||||
@ -14,7 +15,7 @@ export default class MemorySessionManager extends SessionManager {
|
|||||||
return !!this._sessions.firstWhere('key', '=', key)
|
return !!this._sessions.firstWhere('key', '=', key)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async get_session(key?: string): Promise<Session> {
|
public async get_session(key?: string): Promise<SessionInterface> {
|
||||||
if ( !key ) {
|
if ( !key ) {
|
||||||
const utility: Utility = this.make(Utility)
|
const utility: Utility = this.make(Utility)
|
||||||
const session_key: string = key || utility.uuid()
|
const session_key: string = key || utility.uuid()
|
||||||
|
8
lib/src/http/session/MemorySessionManagerFactory.ts
Normal file
8
lib/src/http/session/MemorySessionManagerFactory.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import SessionManagerFactory from "./SessionManagerFactory.ts";
|
||||||
|
import MemorySessionManager from "./MemorySessionManager.ts";
|
||||||
|
|
||||||
|
export default class MemorySessionManagerFactory extends SessionManagerFactory {
|
||||||
|
produce(dependencies: any[], parameters: any[]): any {
|
||||||
|
return new MemorySessionManager()
|
||||||
|
}
|
||||||
|
}
|
20
lib/src/http/session/ModelSessionFactory.ts
Normal file
20
lib/src/http/session/ModelSessionFactory.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import SessionFactory from './SessionFactory.ts'
|
||||||
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
import {Model} from '../../../../orm/src/model/Model.ts'
|
||||||
|
import {StaticClass} from '../../../../di/src/type/StaticClass.ts'
|
||||||
|
import {isInstantiable} from '../../../../di/src/type/Instantiable.ts'
|
||||||
|
|
||||||
|
export default class ModelSessionFactory extends SessionFactory {
|
||||||
|
constructor(
|
||||||
|
protected readonly ModelClass: StaticClass<SessionInterface, typeof Model>,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
produce(dependencies: any[], parameters: any[]): SessionInterface {
|
||||||
|
if ( isInstantiable<SessionInterface>(this.ModelClass) )
|
||||||
|
return new this.ModelClass() as SessionInterface
|
||||||
|
else
|
||||||
|
throw new TypeError(`Session model class ${this.ModelClass} is not instantiable.`)
|
||||||
|
}
|
||||||
|
}
|
52
lib/src/http/session/ModelSessionManager.ts
Normal file
52
lib/src/http/session/ModelSessionManager.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import SessionManager, {InvalidSessionKeyError} from './SessionManager.ts'
|
||||||
|
import {Model} from '../../../../orm/src/model/Model.ts'
|
||||||
|
import SessionInterface, {isSessionInterface} from './SessionInterface.ts'
|
||||||
|
import {StaticClass} from '../../../../di/src/type/StaticClass.ts'
|
||||||
|
|
||||||
|
export default class ModelSessionManager extends SessionManager {
|
||||||
|
constructor(
|
||||||
|
protected readonly ModelClass: StaticClass<SessionInterface, typeof Model>,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get_session(key?: string): Promise<SessionInterface> {
|
||||||
|
const ModelClass: typeof Model = this.ModelClass as typeof Model
|
||||||
|
|
||||||
|
if ( !key ) {
|
||||||
|
const session = this.make(ModelClass)
|
||||||
|
await session.init_session()
|
||||||
|
|
||||||
|
if ( isSessionInterface(session) )
|
||||||
|
return session as SessionInterface
|
||||||
|
|
||||||
|
throw new TypeError(`Session model improperly implements the required SessionInterface.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await ModelClass.find_by_key(key)
|
||||||
|
if ( !session ) throw new InvalidSessionKeyError(key)
|
||||||
|
if ( isSessionInterface(session) )
|
||||||
|
return session as SessionInterface
|
||||||
|
|
||||||
|
throw new TypeError(`Session model improperly implements the required SessionInterface.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async has_session(key: string): Promise<boolean> {
|
||||||
|
const ModelClass: typeof Model = this.ModelClass as typeof Model
|
||||||
|
|
||||||
|
return ModelClass.select(ModelClass.qualified_key_name())
|
||||||
|
.where(ModelClass.qualified_key_name(), '=', key)
|
||||||
|
.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
public async purge(key?: string): Promise<void> {
|
||||||
|
const ModelClass: typeof Model = this.ModelClass as typeof Model
|
||||||
|
const mutable = ModelClass.delete()
|
||||||
|
|
||||||
|
if ( key ) {
|
||||||
|
mutable.where(ModelClass.qualified_key_name(), '=', key)
|
||||||
|
}
|
||||||
|
|
||||||
|
await mutable.execute()
|
||||||
|
}
|
||||||
|
}
|
17
lib/src/http/session/ModelSessionManagerFactory.ts
Normal file
17
lib/src/http/session/ModelSessionManagerFactory.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import SessionManagerFactory from './SessionManagerFactory.ts'
|
||||||
|
import ModelSessionManager from './ModelSessionManager.ts'
|
||||||
|
import {Model} from '../../../../orm/src/model/Model.ts'
|
||||||
|
import {StaticClass} from '../../../../di/src/type/StaticClass.ts'
|
||||||
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
|
||||||
|
export default class MemorySessionManagerFactory extends SessionManagerFactory {
|
||||||
|
constructor(
|
||||||
|
protected readonly ModelClass: StaticClass<SessionInterface, typeof Model>,
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
produce(dependencies: any[], parameters: any[]): any {
|
||||||
|
return new ModelSessionManager(this.ModelClass)
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
import AppClass from '../../lifecycle/AppClass.ts'
|
import AppClass from '../../lifecycle/AppClass.ts'
|
||||||
|
import SessionInterface, {SessionData} from './SessionInterface.ts'
|
||||||
|
|
||||||
export type SessionData = { [key: string]: any }
|
export default abstract class Session extends AppClass implements SessionInterface {
|
||||||
|
|
||||||
export default abstract class Session extends AppClass {
|
|
||||||
public abstract get_key(): string
|
public abstract get_key(): string
|
||||||
public abstract set_key(key: string): void
|
public abstract set_key(key: string): void
|
||||||
public abstract async persist(): Promise<void>
|
public abstract async persist(): Promise<void>
|
||||||
@ -10,4 +9,5 @@ export default abstract class Session extends AppClass {
|
|||||||
public abstract set_data(data: SessionData): void
|
public abstract set_data(data: SessionData): void
|
||||||
public abstract get_attribute(key: string): any
|
public abstract get_attribute(key: string): any
|
||||||
public abstract set_attribute(key: string, value: any): void
|
public abstract set_attribute(key: string, value: any): void
|
||||||
|
public abstract async init_session(): Promise<void>
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import MemorySession from './MemorySession.ts'
|
|||||||
import Session from './Session.ts'
|
import Session from './Session.ts'
|
||||||
import {DependencyRequirement} from '../../../../di/src/type/DependencyRequirement.ts'
|
import {DependencyRequirement} from '../../../../di/src/type/DependencyRequirement.ts'
|
||||||
import {Collection} from '../../collection/Collection.ts'
|
import {Collection} from '../../collection/Collection.ts'
|
||||||
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
|
||||||
// TODO support configurable session backends
|
// TODO support configurable session backends
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ export default class SessionFactory extends AbstractFactory {
|
|||||||
super({})
|
super({})
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(dependencies: any[], parameters: any[]): any {
|
produce(dependencies: any[], parameters: any[]): SessionInterface {
|
||||||
return new MemorySession()
|
return new MemorySession()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
lib/src/http/session/SessionInterface.ts
Normal file
42
lib/src/http/session/SessionInterface.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import {logger} from "../../service/logging/global.ts";
|
||||||
|
|
||||||
|
export type SessionData = { [key: string]: any }
|
||||||
|
|
||||||
|
export default interface SessionInterface {
|
||||||
|
get_key(): string
|
||||||
|
set_key(key: string): void
|
||||||
|
persist(): Promise<void>
|
||||||
|
get_data(): SessionData
|
||||||
|
set_data(data: SessionData): void
|
||||||
|
get_attribute(key: string): any
|
||||||
|
set_attribute(key: string, value: any): void
|
||||||
|
init_session(): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSessionInterface(what: any): what is SessionInterface {
|
||||||
|
const name_length_checks = [
|
||||||
|
{ name: 'get_key', length: 0 },
|
||||||
|
{ name: 'set_key', length: 1 },
|
||||||
|
{ name: 'persist', length: 0 },
|
||||||
|
{ name: 'get_data', length: 0 },
|
||||||
|
{ name: 'set_data', length: 1 },
|
||||||
|
{ name: 'get_attribute', length: 1 },
|
||||||
|
{ name: 'set_attribute', length: 2 },
|
||||||
|
{ name: 'init_session', length: 0 },
|
||||||
|
]
|
||||||
|
|
||||||
|
for ( const check of name_length_checks ) {
|
||||||
|
const { name, length } = check
|
||||||
|
if ( !(typeof what[name] === 'function') ) {
|
||||||
|
logger.debug(`Invalid session interface: typeof ${name} is not a function.`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( what[name].length !== length ) {
|
||||||
|
logger.debug(`Invalid session interface: method ${name} should expect ${length} arguments, ${what[name].length} actual.`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import AppClass from '../../lifecycle/AppClass.ts'
|
import AppClass from '../../lifecycle/AppClass.ts'
|
||||||
import Session from './Session.ts'
|
import SessionInterface from './SessionInterface.ts'
|
||||||
|
|
||||||
export class InvalidSessionKeyError extends Error {
|
export class InvalidSessionKeyError extends Error {
|
||||||
constructor(key: any) {
|
constructor(key: any) {
|
||||||
@ -9,7 +9,7 @@ export class InvalidSessionKeyError extends Error {
|
|||||||
|
|
||||||
export default abstract class SessionManager extends AppClass {
|
export default abstract class SessionManager extends AppClass {
|
||||||
|
|
||||||
public abstract async get_session(key?: string): Promise<Session>
|
public abstract async get_session(key?: string): Promise<SessionInterface>
|
||||||
public abstract async has_session(key: string): Promise<boolean>
|
public abstract async has_session(key: string): Promise<boolean>
|
||||||
public abstract async purge(key?: string): Promise<void>
|
public abstract async purge(key?: string): Promise<void>
|
||||||
|
|
||||||
|
47
lib/src/http/session/SessionModel.ts
Normal file
47
lib/src/http/session/SessionModel.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import {Model} from '../../../../orm/src/model/Model.ts'
|
||||||
|
import SessionInterface, {SessionData} from './SessionInterface.ts'
|
||||||
|
import {Field} from '../../../../orm/src/model/Field.ts'
|
||||||
|
import {Type} from '../../../../orm/src/db/types.ts'
|
||||||
|
|
||||||
|
export default class SessionModel extends Model<SessionModel> implements SessionInterface {
|
||||||
|
|
||||||
|
@Field(Type.json)
|
||||||
|
protected data?: string
|
||||||
|
|
||||||
|
public get_key(): string {
|
||||||
|
return String(this.key())
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_key(key: string) {
|
||||||
|
// @ts-ignore
|
||||||
|
this[this.key_name()] = parseInt(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async persist(): Promise<void> {
|
||||||
|
await this.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
public get_data(): SessionData {
|
||||||
|
return this.data ? JSON.parse(this.data) : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_data(data: SessionData) {
|
||||||
|
this.data = JSON.stringify(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
public get_attribute(key: string): any {
|
||||||
|
const data = this.get_data()
|
||||||
|
if ( data ) return data[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
public set_attribute(key: string, value: any) {
|
||||||
|
const data = this.get_data()
|
||||||
|
data[key] = value
|
||||||
|
this.set_data(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async init_session(): Promise<void> {
|
||||||
|
this.data = JSON.stringify({})
|
||||||
|
await this.save()
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export { default as Scaffolding } from './unit/Scaffolding.ts'
|
export { default as Scaffolding } from './unit/Scaffolding.ts'
|
||||||
export { default as Application } from './lifecycle/Application.ts'
|
export { default as Application } from './lifecycle/Application.ts'
|
||||||
|
export { default as SessionModel } from './http/session/SessionModel.ts'
|
@ -1,17 +1,29 @@
|
|||||||
import LifecycleUnit from "../lifecycle/Unit.ts";
|
import LifecycleUnit from '../lifecycle/Unit.ts'
|
||||||
import {Unit} from "../lifecycle/decorators.ts";
|
import {Unit} from '../lifecycle/decorators.ts'
|
||||||
import Kernel from "../http/kernel/Kernel.ts";
|
import Kernel from '../http/kernel/Kernel.ts'
|
||||||
import PrepareRequest from "../http/kernel/module/PrepareRequest.ts";
|
import PrepareRequest from '../http/kernel/module/PrepareRequest.ts'
|
||||||
import SetSessionCookie from "../http/kernel/module/SetSessionCookie.ts";
|
import SetSessionCookie from '../http/kernel/module/SetSessionCookie.ts'
|
||||||
import Config from "./Config.ts";
|
import Config from './Config.ts'
|
||||||
import SetDatonHeaders from "../http/kernel/module/SetDatonHeaders.ts";
|
import SetDatonHeaders from '../http/kernel/module/SetDatonHeaders.ts'
|
||||||
|
import {Logging} from '../service/logging/Logging.ts'
|
||||||
|
import {Container} from '../../../di/src/Container.ts'
|
||||||
|
import MemorySessionFactory from '../http/session/MemorySessionFactory.ts'
|
||||||
|
import MemorySessionManagerFactory from '../http/session/MemorySessionManagerFactory.ts'
|
||||||
|
import ModelsUnit from '../../../orm/src/ModelsUnit.ts'
|
||||||
|
import {Model} from '../../../orm/src/model/Model.ts'
|
||||||
|
import {StaticClass} from '../../../di/src/type/StaticClass.ts'
|
||||||
|
import ModelSessionFactory from '../http/session/ModelSessionFactory.ts'
|
||||||
|
import ModelSessionManagerFactory from '../http/session/ModelSessionManagerFactory.ts'
|
||||||
|
import SessionInterface from '../http/session/SessionInterface.ts'
|
||||||
|
|
||||||
@Unit()
|
@Unit()
|
||||||
export default class HttpKernel extends LifecycleUnit {
|
export default class HttpKernel extends LifecycleUnit {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected readonly kernel: Kernel,
|
protected readonly kernel: Kernel,
|
||||||
protected readonly config: Config,
|
protected readonly config: Config,
|
||||||
|
protected readonly logger: Logging,
|
||||||
|
protected readonly injector: Container,
|
||||||
|
protected readonly models: ModelsUnit,
|
||||||
) {
|
) {
|
||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
@ -23,6 +35,33 @@ export default class HttpKernel extends LifecycleUnit {
|
|||||||
if ( this.config.get('server.powered_by.enable') ) {
|
if ( this.config.get('server.powered_by.enable') ) {
|
||||||
SetDatonHeaders.register(this.kernel)
|
SetDatonHeaders.register(this.kernel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.determine_session_provider()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected determine_session_provider() {
|
||||||
|
const driver = this.config.get('server.session.driver')
|
||||||
|
|
||||||
|
if ( driver === 'memory' ) {
|
||||||
|
this.logger.verbose('Adding the memory session production factories to the container...')
|
||||||
|
this.injector.register_factory(new MemorySessionFactory())
|
||||||
|
this.injector.register_factory(new MemorySessionManagerFactory())
|
||||||
|
} else if ( driver === 'database' ) {
|
||||||
|
const model_key = this.config.get('server.session.model')
|
||||||
|
if ( !model_key ) {
|
||||||
|
this.logger.error('Please specify the canonical model name to use for the HTTP session.')
|
||||||
|
throw new Error('Missing required config property: server.session.model')
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModelClass: StaticClass<SessionInterface, typeof Model> | undefined = this.models.get(model_key)
|
||||||
|
if ( !ModelClass ) {
|
||||||
|
this.logger.error(`Unable to find HTTP session model with name: ${model_key}`)
|
||||||
|
throw new Error(`Unable to find HTTP session model with name: ${model_key}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.info('Adding the model session production factories to the container...')
|
||||||
|
this.injector.register_factory(new ModelSessionFactory(ModelClass))
|
||||||
|
this.injector.register_factory(new ModelSessionManagerFactory(ModelClass))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,5 @@ export default class Scaffolding extends LifecycleUnit {
|
|||||||
public register_factories() {
|
public register_factories() {
|
||||||
this.logger.verbose('Adding the cache production factory to the container...')
|
this.logger.verbose('Adding the cache production factory to the container...')
|
||||||
this.injector.register_factory(new CacheFactory())
|
this.injector.register_factory(new CacheFactory())
|
||||||
|
|
||||||
this.logger.verbose('Adding the session production factories to the container...')
|
|
||||||
this.injector.register_factory(new SessionFactory())
|
|
||||||
this.injector.register_factory(new SessionManagerFactory())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
lib/src/unit/StaticCanonical.ts
Normal file
13
lib/src/unit/StaticCanonical.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {Canonical, CanonicalDefinition} from './Canonical.ts'
|
||||||
|
import {InvalidCanonicalExportError} from './InstantiableCanonical.ts'
|
||||||
|
import {isStaticClass, StaticClass} from '../../../di/src/type/StaticClass.ts'
|
||||||
|
|
||||||
|
export class StaticCanonical<T, T2> extends Canonical<StaticClass<T, T2>> {
|
||||||
|
public async init_canonical_item(def: CanonicalDefinition): Promise<StaticClass<T, T2>> {
|
||||||
|
if ( isStaticClass(def.imported.default) ) {
|
||||||
|
return def.imported.default
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidCanonicalExportError(def.original_name)
|
||||||
|
}
|
||||||
|
}
|
20
orm/src/ModelsUnit.ts
Normal file
20
orm/src/ModelsUnit.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {CanonicalDefinition} from '../../lib/src/unit/Canonical.ts'
|
||||||
|
import {Model} from './model/Model.ts'
|
||||||
|
import {Unit} from '../../lib/src/lifecycle/decorators.ts'
|
||||||
|
import {StaticCanonical} from '../../lib/src/unit/StaticCanonical.ts'
|
||||||
|
|
||||||
|
@Unit()
|
||||||
|
export default class ModelsUnit extends StaticCanonical<Model<any>, typeof Model> {
|
||||||
|
protected base_path = './app/models'
|
||||||
|
protected canonical_item = 'model'
|
||||||
|
protected suffix = '.model.ts'
|
||||||
|
|
||||||
|
public async init_canonical_item(def: CanonicalDefinition) {
|
||||||
|
const item = await super.init_canonical_item(def)
|
||||||
|
if ( !(item.prototype instanceof Model) ) {
|
||||||
|
throw new TypeError(`Invalid model definition: ${def.original_name}. Models must extend from Daton ORM's base Model class.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
}
|
@ -82,6 +82,10 @@ export default abstract class ConnectionExecutable<T> {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async exists(): Promise<boolean> {
|
||||||
|
return (await this.count()) > 0
|
||||||
|
}
|
||||||
|
|
||||||
async execute_in_connection(connection: string | Connection): Promise<QueryResult> {
|
async execute_in_connection(connection: string | Connection): Promise<QueryResult> {
|
||||||
const conn = typeof connection === 'string' ? make(Database).connection(connection) : connection
|
const conn = typeof connection === 'string' ? make(Database).connection(connection) : connection
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export default class PostgresConnection extends Connection {
|
|||||||
const result = await this._client.query(query)
|
const result = await this._client.query(query)
|
||||||
|
|
||||||
let base_i = 0
|
let base_i = 0
|
||||||
const cols = collect(result?.rowDescription?.columns || []).sortBy('index').map(col => {
|
const cols = collect(result?.rowDescription?.columns || []).map(col => {
|
||||||
col.index = base_i
|
col.index = base_i
|
||||||
base_i += 1
|
base_i += 1
|
||||||
return col
|
return col
|
||||||
|
@ -24,7 +24,7 @@ export abstract class Model<T extends Model<T>> extends Builder<T> {
|
|||||||
* The name of the connection this model should run through.
|
* The name of the connection this model should run through.
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
protected static connection: string
|
protected static connection: string = 'default'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the table this model is stored in.
|
* The name of the table this model is stored in.
|
||||||
@ -42,13 +42,13 @@ export abstract class Model<T extends Model<T>> extends Builder<T> {
|
|||||||
* Optionally, the timestamp field set on creation.
|
* Optionally, the timestamp field set on creation.
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
protected static readonly CREATED_AT = 'created_at'
|
protected static readonly CREATED_AT: string | null = 'created_at'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally, the timestamp field set op update.
|
* Optionally, the timestamp field set op update.
|
||||||
* @type string
|
* @type string
|
||||||
*/
|
*/
|
||||||
protected static readonly UPDATED_AT = 'updated_at'
|
protected static readonly UPDATED_AT: string | null = 'updated_at'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the CREATED_AT and UPDATED_AT columns will be automatically set.
|
* If true, the CREATED_AT and UPDATED_AT columns will be automatically set.
|
||||||
@ -569,7 +569,7 @@ export abstract class Model<T extends Model<T>> extends Builder<T> {
|
|||||||
* @param without_timestamps - if true, the UPDATED_AT/CREATED_AT timestamps will not be touched
|
* @param without_timestamps - if true, the UPDATED_AT/CREATED_AT timestamps will not be touched
|
||||||
* @return Promise<Model>
|
* @return Promise<Model>
|
||||||
*/
|
*/
|
||||||
public async save({ without_timestamps = false }): Promise<Model<T>> {
|
public async save({ without_timestamps = false } = {}): Promise<Model<T>> {
|
||||||
await this.saving$.next(this)
|
await this.saving$.next(this)
|
||||||
const constructor = (this.constructor as typeof Model)
|
const constructor = (this.constructor as typeof Model)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user