Centralize Aurelia validation logic - aurelia

I would like to centralize validation logic in #ensure but I am not sure how to do it.
This is an example from documentation:
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
export class Person {
static inject() { return [Validation];}
//I want to inject validation logic here instead of using function(it){...}
#ensure(function(it){ it.isNotEmpty().hasLengthBetween(3,10) })
firstName = 'John';
constructor(validation) {
this.validation = validation.on(this);
}
}
And I would to change the code above to like below:
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
import {UserValidation} from 'user/userValidation'; //custom validation logic here
export class Person {
static inject() { return [Validation];}
//can I do something like this instead of using function(it){...}?
#ensure(UserValidation.firstName)
firstName = 'John';
constructor(validation) {
this.validation = validation.on(this);
}
}
If we need to collect first name only on 1 page then we don't have to do this at all but since we might have to have user to enter their first name on multiple different pages, we would like to centralize the validation logic somewhere so that we don't have to copy & paste it everywhere. We don't want to create "first name component" either because UI will be different on each page, so we just want to reuse the validation logic.
UPDATE:
I asked this question in Aurelia discussion and was asked to try the following.
//userValidation.js
export function firstName(it){ it.isNotEmpty().hasLengthBetween(3,10)};
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
import * as userValidation from 'user/userValidation';
export class Person {
static inject() { return [Validation];}
#ensure(userValidation.firstName)
firstName = 'John';
constructor(validation) {
this.validation = validation.on(this);
}
}
But I am getting this error: Unhandled promise rejection Error: Error instantiating Person. Any idea how I can fix this?

Actually, the following code worked!
//userValidation.js
export function firstName(it){ it.isNotEmpty().hasLengthBetween(3,10)};
//person.js
import {Validation} from 'aurelia-validation';
import {ensure} from 'aurelia-validation';
import * as userValidation from 'user/userValidation';
export class Person {
static inject() { return [Validation];}
#ensure(userValidation.firstName)
firstName = 'John';
constructor(validation) {
this.validation = validation.on(this);
}
}

Related

How do I provide my own DateTimeProvider with Spring Data

I am trying to provide a transactionally consistent set of datetimes
import org.springframework.beans.factory.ObjectFactory
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Scope
import org.springframework.data.auditing.DateTimeProvider
import org.springframework.transaction.support.SimpleTransactionScope
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.util.Optional
#Configuration
open class TransactionScopeTimeConfiguration {
#Bean
open fun transactionBFPP(): BeanFactoryPostProcessor =
BeanFactoryPostProcessor { it.registerScope("transaction", SimpleTransactionScope()) }
#Bean
#Scope("transaction")
open fun nowInstant(): Instant = Instant.now()
#Bean
#Scope("transaction")
open fun nowOffsetDateTime(nowInstant: Instant): OffsetDateTime = nowInstant.atOffset(ZoneOffset.UTC)
#Bean
open fun transactionDateTimeProvider(factory: ObjectFactory<OffsetDateTime>): DateTimeProvider =
DateTimeProvider { Optional.of(factory.`object`) }
}
However, when debugging my test I note that the function inside of transactionDateTimeProvider is never called (the creation of the Bean is)
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
#DataJpaTest
#Import(TransactionScopeTimeConfiguration)
internal open class ExceptionDaoTest {
#Test
fun save(#Autowired exceptionDao: ExceptionJpaDao) {
val toCreate = ExceptionEntity("someid")
val saved = exceptionDao.save(toCreate)
assertThat(saved).isInstanceOf(ExceptionEntity::class.java)
.extracting({ it.id }, { it.businessDivisionId })
.containsExactly(toCreate.id, "someid")
.doesNotContainNull()
assertThat(saved.lastModifiedOn).isSameAs(saved.createdOn)
}
}
The test actually passes, but I haven't actually exercised this functionality in this test. It's important that any other datetimes are transactionally consistent with the audit traits.

Ktor with Koin DI can't inject, missing clazz

I am setting up Koin DI on Ktor in this way:
https://insert-koin.io/docs/reference/koin-ktor/ktor/
But I am getting an error: No value passed for parameter 'clazz'
My implementation looks like this:
import io.ktor.application.*
import io.ktor.routing.*
import org.koin.java.KoinJavaComponent.inject
import services.SomeService
fun Application.registerPropertyRoutes() {
routing {
bodySectionRoute() // add more routes for Property page here
}
}
fun Route.bodySectionRoute() {
val someService by inject<SomeService>()
get("/bodySection") {
// business logic can be connected here
}
}
Any ideas what I am missing?
Update:
You need to import org.koin.ktor.ext.inject

How to pass current ClassLoader to KotlinToJVMBytecodeCompiler for dynamic (runtime) compilation kotlin code programmatically?

I created simple utility for runtime compilation kotlin code:
package com.example
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.com.intellij.openapi.Disposable
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import java.io.File
import kotlin.script.experimental.jvm.util.KotlinJars
class KotlinDynamicCompiler {
fun compileScript(moduleName: String,
sourcePath: String,
saveClassesDir: File
): GenerationState {
val stubDisposable = StubDisposable();
val configuration = CompilerConfiguration()
configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, PrintingMessageCollector(System.out, MessageRenderer.PLAIN_FULL_PATHS, true))
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir)
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
configuration.addKotlinSourceRoot(sourcePath)
configuration.addJvmClasspathRoots(listOf(KotlinJars.stdlib))
val env = KotlinCoreEnvironment.createForProduction(stubDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
return KotlinToJVMBytecodeCompiler.analyzeAndGenerate(env)!!;
}
inner class StubDisposable : Disposable {
#Volatile
var isDisposed: Boolean = false
private set
override fun dispose() {
isDisposed = true
}
};
}
And it works for code as
package com.example.kt
class SimpleClass(val str:String){
fun test(){
}
}
class UsedSimpleClass(val simpleClass: SimpleClass, val file: java.io.File) {
}
But it not works if I want to use no-base package classes as:
package com.example.kt
import com.example.pojo.TestPojo //class have in project that call runtime compilation
class SimpleClass(val str:TestPojo){
}
or:
package com.example.kt
import com.fasterxml.jackson.databind.ObjectMapper //class have in project classpath where called runtime compilation
class SimpleClass(val str:ObjectMapper){
}
How to pass current ClassLoader to KotlinToJVMBytecodeCompiler for dynamic (runtime) compilation kotlin code programmatically?
More details:
Test project on github with crashed test: https://github.com/nekkiy/dynamic-kotlin
Cause:
We need use codegeneration and would like to test generated code. But I don't understand how to pass current classes environment.
Thanks for attention.
Solution:
I have used method fun classpathFromClassloader(currentClassLoader: ClassLoader, unpackJarCollections: Boolean = false): List<File>? from kotlin.script.experimental.jvm.util.jvmClasspathUtil.kt and it works.
Result dynamic compiller:
package com.example
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.com.intellij.openapi.Disposable
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.JvmTarget
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import kotlin.script.experimental.jvm.util.KotlinJars
import kotlin.script.experimental.jvm.util.classpathFromClassloader
class KotlinDynamicCompiler {
fun compileModule(moduleName: String,
sourcePath: List<String>,
saveClassesDir: File,
classLoader: ClassLoader? = null,
forcedAddKotlinStd: Boolean = true
): GenerationState {
val stubDisposable = StubDisposable();
val configuration = CompilerConfiguration()
configuration.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
val baos = ByteArrayOutputStream()
val ps: PrintStream = PrintStream(baos)
configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, PrintingMessageCollector(ps, MessageRenderer.PLAIN_FULL_PATHS, true))
configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir)
// configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true)
configuration.put(JVMConfigurationKeys.JVM_TARGET, JvmTarget.JVM_1_8)
val classPath = mutableSetOf<File>()
if (classLoader != null) {
classPath.addAll(classpathFromClassloader(classLoader)!!);
}
if (forcedAddKotlinStd) {
classPath.add(KotlinJars.stdlib)
}
configuration.addJvmClasspathRoots(classPath.toList())
configuration.addKotlinSourceRoots(sourcePath)
val env = KotlinCoreEnvironment.createForProduction(stubDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val result = KotlinToJVMBytecodeCompiler.analyzeAndGenerate(env);
ps.flush();
if (result != null) {
return result
} else {
throw IllegalStateException("Compilation error. Details:\n$baos")
}
}
inner class StubDisposable : Disposable {
#Volatile
var isDisposed: Boolean = false
private set
override fun dispose() {
isDisposed = true
}
};
}
Note: This function is contained in experimental package.
P.S. I also updated github-project.

Aurelia: Dep. Injection on derived classes not possible? (or what am I doing wrong?!)

The scenario: I have two derived classes that both extend the ActionBase class as follows. I want to use DI for both derived classes. But both classes have different dependencies. That should be possible, right? So what am I doing wrong? In both cases the injected instances/modules are 'undefined'. Any help/hint appreciated.
/*
* Base class for Actions
*/
export class ActionBase {
type;
constructor(type) {
this.type = type;
}
}
/*
* Derived Class: InsertAction
*/
import {inject} from 'aurelia-framework';
import {ActionBase} from './ActionBase';
import {PomManager} from '../manager/PomManager';
#inject(PomManager)
export class InsertAction extends ActionBase {
pomManager;
constructor(pomManager) {
super("insert");
this.pomManager = pomManager;
console.log("[InsertAction:constructor] pomManager: ", this.pomManager); // undefined
}
}
/*
* Derived Class: RenderAction
*/
import {inject} from 'aurelia-framework';
import {ActionBase} from './ActionBase';
import {AnotherManager} from '../manager/AnotherManager';
#inject(AnotherManager)
export class RenderAction extends ActionBase {
anotherManager;
constructor(anotherManager) {
super("render");
this.anotherManager = anotherManager;
console.log("[RenderAction:constructor] anotherManager: ", this.anotherManager); // undefined
}
}
It is supported. Look at this working example where Action1 and Action2 extend BaseAction and each take different dependencies.
Here's an example: https://gist.run?id=0efabf77c649f41981dcde753fdc542c
app.js
import {inject} from 'aurelia-dependency-injection'
import {Action1, Action2} from './classes'
#inject(Action1, Action2)
export class App {
constructor(a1, a2){
this.message = "look at console output";
console.log("a1", a1.dep.constructor.name);
console.log("a2", a2.dep.constructor.name);
}
}
classes.js
import {inject} from 'aurelia-dependency-injection'
export class Action1Dependency {}
export class Action2Dependency {}
export class ActionBase{
}
#inject(Action1Dependency)
export class Action1 extends ActionBase{
constructor(dep){
super();
this.dep = dep;
}
}
#inject(Action2Dependency)
export class Action2 extends ActionBase{
constructor(dep){
super();
this.dep = dep;
}
}

Default imports with TypeScript

Using tsc 1.8.9... why are these imports not working? I thought TypeScript implemented ES6 module syntax?
"classes/person.ts"
export default class Person {
protected _name: string;
protected _language: string;
constructor(name: string) {
this._name = name;
this.hello();
}
public hello() {
console.log("Hello, " + this._name);
console.log("Lang: " + this._language);
}
}
"classes/englishman.ts"
import Person from "person"
export default class Englishman extends Person {
constructor(name: string){
this._language = "en_GB";
super(name);
}
}
"main.ts"
import * as $ from "jquery";
import Englishman from "classes/englishman";
let tom: Person = new Englishman("Tom");
console.log(tom);
$("body").html(`<h1>TEST</h1>`);
Errors:
source/main.ts(2,24): error TS2307: Cannot find module
'classes/englishman'. source/main.ts(4,10): error TS2304: Cannot find
name 'Person'. [13:53:43]
TypeScript: 2 semantic errors
After some changes, it worked for me, tested in ES5 and ES6. I hope to help you:
Original
import Person from "classes/person";
import Englishman from "classes/englishman";
Change for test
import Person from './person';
import Englishman from './classes/englishman';
maybe you need to check your directory tree.
Add
import Person from './classes/person';
.
import Person from './person'; //<-- change
export default class Englishman extends Person {
constructor(name: string){
this._language = "en_GB";
super(name);
}
}
export default class Person {
protected _name: string;
protected _language: string;
constructor(name: string) {
this._name = name;
this.hello();
}
public hello() {
console.log("Hello, " + this._name);
console.log("Lang: " + this._language);
}
}
import Englishman from './classes/englishman'; //<-- change
import Person from './classes/person'; //<-- add
class HelloWorld{
public static main(){
let tom: Person = new Englishman("Tom");
console.log(tom);
}
}
HelloWorld.main();
Hello, Tom
Lang: en_GB
Englishman { _language: 'en_GB', _name: 'Tom' }
tsc Version 1.8.2
node v5.4.1
Make sure you are compiling with ES6 target, if I'm not mistaken, ES5 is still the default target.