Skip to content

Integración con Effect Schema ​

QuickModel y Effect Schema (@effect/schema) son herramientas complementarias. Effect Schema proporciona schemas declarativos con integración de primera clase en Effect, parseo, encoding y transformación. QuickModel añade coerción basada en decoradores, serialización y validación de reglas de negocio encima. Úsalos juntos en backends basados en Effect, o exporta schemas de QuickModel en formato Effect Schema para interoperabilidad.

Concepto clave: salida de Effect Schema → instancia de QModel ​

Tras que Effect Schema decodifica un valor, pasa el resultado al constructor de QModel:

typescript
import { Schema, ParseResult } from '@effect/schema';
import { Effect } from 'effect';
import { QModel, Quick } from 'quickmodel';

// 1. Effect Schema para parseo / decodificación
const UserEffectSchema = Schema.Struct({
	name: Schema.String,
	birth: Schema.String, // string ISO de la red
	score: Schema.String, // puede llegar como string de un formulario
});

type IUserRaw = Schema.Schema.Type<typeof UserEffectSchema>;

// 2. Clase QModel para coerción + serialización
interface IUser {
	name: string;
	birth: Date;
	score: number;
}

@Quick({ birth: Date, score: Number })
class User extends QModel<IUser> {
	declare name: string;
	declare birth: Date;
	declare score: number;
}

// 3. Decodificar con Effect Schema, luego coercionar con QModel
const rawData = { name: 'Ana', birth: '1990-05-20T00:00:00Z', score: '42' };

const program = Effect.gen(function* () {
	const validated = yield* Schema.decode(UserEffectSchema)(rawData);
	const user = new User(validated); // coerciona los tipos
	return user;
});

// user.birth es Date, user.score es number

Para contextos fuera de Effect, usa el decodificador síncrono:

typescript
import { Schema } from '@effect/schema';

const validated = Schema.decodeSync(UserEffectSchema)(rawData);
const user = new User(validated);

Exportar un schema QModel en formato Effect Schema ​

Usa getSchema('effect-schema') para obtener el código del schema Effect Schema de cualquier clase QModel:

typescript
import 'quickmodel/schema'; // registrar los generadores de schema primero

const effectCode = User.getSchema('effect-schema');
// → string con código fuente Effect Schema:
// import { Schema } from '@effect/schema';
// export const UserSchema = Schema.Struct({ name: Schema.String, birth: Schema.String, ... });

// Guardar en disco e importar donde se use Effect nativamente:
// fs.writeFileSync('src/schemas/user.schema.ts', effectCode);

El código generado es un string de código fuente, no un objeto schema activo. Está pensado para scaffolding e interoperabilidad.

Patrón: pipeline Effect con QModel ​

El $qSerialize() de QModel se integra limpiamente en pipelines Effect:

typescript
const processUser = (raw: unknown) =>
	Effect.gen(function* () {
		const validated = yield* Schema.decode(UserEffectSchema)(raw);
		const user = new User(validated);

		// Aplicar lógica de negocio con reglas QModel
		const isValid = yield* Effect.promise(() => user.$qCheckRules());
		if (!isValid.passed) {
			yield* Effect.fail(new Error(isValid.errors.join(', ')));
		}

		return user.$qSerialize();
	});

Cuándo usar cada enfoque ​

EscenarioHerramienta
Parseo / encoding declarativo con EffectSchema.decode() / Schema.encode()
Coercionar strings→Date, strings→number, etc.new User(data) con @Quick({...})
Validación de reglas de negociouser.$qCheckRules()
Serializar un modelo a objeto plano / JSONuser.$qSerialize()
Exportar un Effect Schema desde una clase QModelUser.getSchema('effect-schema')

Comparativa ​

FeatureEffect SchemaQuickModel
Parseo + encoding declarativo✅Vía @Quick({...})
Integración nativa con Effect✅Se puede envolver en Effect
Coerción de tipos (string→Date, etc.)✅✅ nativo
Validación de reglas de negocioVía refinements✅ @QRule
Serialización / round-tripVía encoding✅ $qSerialize()
Exportación OpenAPI / JSON Schema❌✅ getSchema()
Modelos basados en clases con decoradores❌✅

fromSchema: generando una clase QModel desde un Effect Schema ​

QModel.fromSchema('effect-schema', ...) acepta un string fuente de Schema.Struct({...}) y genera código TypeScript para una clase QModel:

typescript
import 'quickmodel/schema';

const effectSrc = `
import * as Schema from 'effect/schema';
const ReportSchema = Schema.Struct({
  score: Schema.Number,
  title: Schema.String,
  passed: Schema.Boolean,
  date: Schema.Date,
  amount: Schema.BigIntFromSelf,
});
`;

const code = QModel.fromSchema('effect-schema', effectSrc, 'Report');
// → string TypeScript con la clase Report extends QModel<IReport>

// fs.writeFileSync('src/models/report.model.ts', code);

Schema.BigIntFromSelf se mapea al transformer BigInt.

Round-trip: QModel → Effect Schema → clase QModel ​

typescript
import 'quickmodel/schema';

const effectSrc = User.getSchema('effect-schema');
const code = QModel.fromSchema('effect-schema', effectSrc, 'User');
// code es TypeScript válido que define class User extends QModel<IUser>

Ver también ​