如何创建 knex 迁移以根据其他列创建列?
how to create a knex migration for creating a column depending on other columns?
我有一个 Node.js 项目,我正在使用 knex.js 作为查询构建器。
我有一个名为长方体的模型:
import { Id, RelationMappings } from 'objection';
import { Bag } from './Bag';
import Base from './Base';
export class Cuboid extends Base {
id!: Id;
width!: number;
height!: number;
depth!: number;
bagId?: Id;
bag!: Bag;
volume!: number;
static tableName = 'cuboids';
static get relationMappings(): RelationMappings {
return {
bag: {
relation: Base.BelongsToOneRelation,
modelClass: 'Bag',
join: {
from: 'cuboids.bagId',
to: 'bags.id',
},
},
};
}
}
export default Cuboid;
我还有一个迁移,我在其中为长方体创建了一些列 table:
import { Bag, Cuboid } from '../../src/models';
import { Knex } from 'knex';
export const up = (knex: Knex): Promise<void> =>
knex.schema.createTable(Cuboid.tableName, (table: Knex.TableBuilder) => {
table.increments();
table.timestamps();
table.integer('width');
table.integer('height');
table.integer('depth');
table.integer('bagId');
table.foreign('bagId').references('id').inTable(Bag.tableName);
});
export const down = (knex: Knex): Promise<void> =>
knex.schema.dropTable(Cuboid.tableName);
我想创建一个新的迁移,我在其中定义了一个名为 'volume' 的列。体积需要是宽度、高度和深度列的乘积(体积 = 宽度 * 高度 * 深度)。
import { Knex } from 'knex';
import { Cuboid } from '../../src/models';
export const up = (knex: Knex): Promise<void> =>
knex.schema.alterTable(Cuboid.tableName, (table: Knex.TableBuilder) => {
/*
* how can I define this column, so that it's value is the product of other three(width,height,depth) columns
* plus the value should be updated on insert and update queries for a cuboid record
* e.g if I change the height or width so the volume should also change after being created
*/
table.integer('volume');
});
// ignore the down function
export const down = (knex: Knex): Promise<void> =>
knex.schema.dropTable(Cuboid.tableName);
注意:基础模型是从 objection.js 创建的模型。是这样的:
import { Model } from 'objection';
import * as path from 'path';
import knex from '../db/knex';
Model.knex(knex);
export default class Base extends Model {
static get modelPaths(): string[] {
return [path.resolve('src/models')];
}
}
创建操作类似于
bag = await Bag.query().insertGraphAndFetch({
volume: 100,
title: 'A bag',
cuboids: [{ width: 2, height: 2, depth: 2 }],
});
//Note: A cubid belongs to a bag, so a bag is created before cuboids are assigned to it.
cuboid = await Cuboid.query().insert({
width,
height,
depth,
bagId: bag.id,
});
这无法使用迁移实现,而是您可以实施 objection.js' 模型方法,即 afterInsert
和 afterUpdate
在 create/update 操作后更新长方体的体积执行。
您的长方体模型将变为:
import { Id, ModelOptions, QueryContext, RelationMappings } from 'objection';
import { Bag } from './Bag';
import Base from './Base';
export class Cuboid extends Base {
id!: Id;
width!: number;
height!: number;
depth!: number;
bagId?: Id;
bag!: Bag;
volume!: number;
static tableName = 'cuboids';
$afterInsert = async (queryContext: QueryContext) => {
await super.$afterInsert(queryContext);
console.log(' after insert working');
await this.$query().updateAndFetchById(this.id, {
volume: this.width * this.height * this.depth,
});
};
$afterUpdate = async (opt: ModelOptions, queryContext: QueryContext) => {
await super.$afterUpdate(opt, queryContext);
console.log(' after update working');
await this.$query().updateAndFetchById(this.id, {
volume: this.width * this.height * this.depth,
});
};
static get relationMappings(): RelationMappings {
return {
bag: {
relation: Base.BelongsToOneRelation,
modelClass: 'Bag',
join: {
from: 'cuboids.bagId',
to: 'bags.id',
},
},
};
}
}
export default Cuboid;
我有一个 Node.js 项目,我正在使用 knex.js 作为查询构建器。
我有一个名为长方体的模型:
import { Id, RelationMappings } from 'objection';
import { Bag } from './Bag';
import Base from './Base';
export class Cuboid extends Base {
id!: Id;
width!: number;
height!: number;
depth!: number;
bagId?: Id;
bag!: Bag;
volume!: number;
static tableName = 'cuboids';
static get relationMappings(): RelationMappings {
return {
bag: {
relation: Base.BelongsToOneRelation,
modelClass: 'Bag',
join: {
from: 'cuboids.bagId',
to: 'bags.id',
},
},
};
}
}
export default Cuboid;
我还有一个迁移,我在其中为长方体创建了一些列 table:
import { Bag, Cuboid } from '../../src/models';
import { Knex } from 'knex';
export const up = (knex: Knex): Promise<void> =>
knex.schema.createTable(Cuboid.tableName, (table: Knex.TableBuilder) => {
table.increments();
table.timestamps();
table.integer('width');
table.integer('height');
table.integer('depth');
table.integer('bagId');
table.foreign('bagId').references('id').inTable(Bag.tableName);
});
export const down = (knex: Knex): Promise<void> =>
knex.schema.dropTable(Cuboid.tableName);
我想创建一个新的迁移,我在其中定义了一个名为 'volume' 的列。体积需要是宽度、高度和深度列的乘积(体积 = 宽度 * 高度 * 深度)。
import { Knex } from 'knex';
import { Cuboid } from '../../src/models';
export const up = (knex: Knex): Promise<void> =>
knex.schema.alterTable(Cuboid.tableName, (table: Knex.TableBuilder) => {
/*
* how can I define this column, so that it's value is the product of other three(width,height,depth) columns
* plus the value should be updated on insert and update queries for a cuboid record
* e.g if I change the height or width so the volume should also change after being created
*/
table.integer('volume');
});
// ignore the down function
export const down = (knex: Knex): Promise<void> =>
knex.schema.dropTable(Cuboid.tableName);
注意:基础模型是从 objection.js 创建的模型。是这样的:
import { Model } from 'objection';
import * as path from 'path';
import knex from '../db/knex';
Model.knex(knex);
export default class Base extends Model {
static get modelPaths(): string[] {
return [path.resolve('src/models')];
}
}
创建操作类似于
bag = await Bag.query().insertGraphAndFetch({
volume: 100,
title: 'A bag',
cuboids: [{ width: 2, height: 2, depth: 2 }],
});
//Note: A cubid belongs to a bag, so a bag is created before cuboids are assigned to it.
cuboid = await Cuboid.query().insert({
width,
height,
depth,
bagId: bag.id,
});
这无法使用迁移实现,而是您可以实施 objection.js' 模型方法,即 afterInsert
和 afterUpdate
在 create/update 操作后更新长方体的体积执行。
您的长方体模型将变为:
import { Id, ModelOptions, QueryContext, RelationMappings } from 'objection';
import { Bag } from './Bag';
import Base from './Base';
export class Cuboid extends Base {
id!: Id;
width!: number;
height!: number;
depth!: number;
bagId?: Id;
bag!: Bag;
volume!: number;
static tableName = 'cuboids';
$afterInsert = async (queryContext: QueryContext) => {
await super.$afterInsert(queryContext);
console.log(' after insert working');
await this.$query().updateAndFetchById(this.id, {
volume: this.width * this.height * this.depth,
});
};
$afterUpdate = async (opt: ModelOptions, queryContext: QueryContext) => {
await super.$afterUpdate(opt, queryContext);
console.log(' after update working');
await this.$query().updateAndFetchById(this.id, {
volume: this.width * this.height * this.depth,
});
};
static get relationMappings(): RelationMappings {
return {
bag: {
relation: Base.BelongsToOneRelation,
modelClass: 'Bag',
join: {
from: 'cuboids.bagId',
to: 'bags.id',
},
},
};
}
}
export default Cuboid;