Skip to content

Commit

Permalink
feat(core): allow mapping database defaults from inline embeddables (#…
Browse files Browse the repository at this point in the history
…4384)

Closes #3887
  • Loading branch information
B4nan committed Nov 5, 2023
1 parent 26dbb82 commit 22ad61e
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/unit-of-work/ChangeSetPersister.ts
Expand Up @@ -338,7 +338,7 @@ export class ChangeSetPersister {

if (changeSets[0].type === ChangeSetType.CREATE) {
// do not reload things that already had a runtime value
meta.hydrateProps
meta.props
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw))
.filter(prop => (changeSets[0].entity[prop.name] == null && prop.defaultRaw !== 'null') || Utils.isRawSql(changeSets[0].entity[prop.name]))
.forEach(prop => reloadProps.push(prop));
Expand Down
2 changes: 1 addition & 1 deletion packages/knex/src/AbstractSqlDriver.ts
Expand Up @@ -424,7 +424,7 @@ export abstract class AbstractSqlDriver<Connection extends AbstractSqlConnection
}

if (meta && this.platform.usesReturningStatement()) {
const returningProps = meta.hydrateProps
const returningProps = meta.props
.filter(prop => prop.persist !== false && ((prop.primary && prop.autoincrement) || prop.defaultRaw || prop.autoincrement))
.filter(prop => !(prop.name in data[0]) || Utils.isRawSql(data[0][prop.name]));
const returningFields = Utils.flatten(returningProps.map(prop => prop.fieldNames));
Expand Down
60 changes: 60 additions & 0 deletions tests/features/embeddables/GH3887.mysql.test.ts
@@ -0,0 +1,60 @@
import { Embeddable, Embedded, Entity, PrimaryKey, Property, MikroORM } from '@mikro-orm/mysql';

@Embeddable()
class NestedTime {

@Property({ defaultRaw: 'current_timestamp' })
timestamp!: Date;

}

@Embeddable()
class Time {

@Property({ defaultRaw: 'current_timestamp' })
timestamp!: Date;

@Embedded(() => NestedTime)
nested!: NestedTime;

}

@Entity()
class Test {

@PrimaryKey()
id!: number;

@Embedded(() => Time)
time!: Time;

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
entities: [Test],
dbName: '3887',
port: 3308,
});
await orm.schema.refreshDatabase();
});

afterAll(async () => {
await orm.close(true);
});

test('reloading database defaults from inlined embeddables', async () => {
const test = new Test();
test.time = {} as Time;
test.time.nested = {} as Time;

await orm.em.fork().persistAndFlush(test);
expect(test.time.timestamp).toBeInstanceOf(Date);
expect(test.time.nested.timestamp).toBeInstanceOf(Date);

const fetched = await orm.em.fork().findOneOrFail(Test, test);
expect(fetched.time.timestamp).toBeInstanceOf(Date);
expect(fetched.time.nested.timestamp).toBeInstanceOf(Date);
});
59 changes: 59 additions & 0 deletions tests/features/embeddables/GH3887.sqlite.test.ts
@@ -0,0 +1,59 @@
import { Embeddable, Embedded, Entity, PrimaryKey, Property, MikroORM } from '@mikro-orm/better-sqlite';

@Embeddable()
class NestedTime {

@Property({ defaultRaw: 'current_timestamp' })
timestamp!: Date;

}

@Embeddable()
class Time {

@Property({ defaultRaw: 'current_timestamp' })
timestamp!: Date;

@Embedded(() => NestedTime)
nested!: NestedTime;

}

@Entity()
class Test {

@PrimaryKey()
id!: number;

@Embedded(() => Time)
time!: Time;

}

let orm: MikroORM;

beforeAll(async () => {
orm = await MikroORM.init({
entities: [Test],
dbName: ':memory:',
});
await orm.schema.refreshDatabase();
});

afterAll(async () => {
await orm.close(true);
});

test('reloading database defaults from inlined embeddables', async () => {
const test = new Test();
test.time = {} as Time;
test.time.nested = {} as Time;

await orm.em.fork().persistAndFlush(test);
expect(test.time.timestamp).toBeInstanceOf(Date);
expect(test.time.nested.timestamp).toBeInstanceOf(Date);

const fetched = await orm.em.fork().findOneOrFail(Test, test);
expect(fetched.time.timestamp).toBeInstanceOf(Date);
expect(fetched.time.nested.timestamp).toBeInstanceOf(Date);
});
Expand Up @@ -8,7 +8,7 @@ describe('partial loading (mysql)', () => {

let orm: MikroORM<MySqlDriver>;

beforeAll(async () => orm = await initORMMySql('mysql', {}, true));
beforeAll(async () => orm = await initORMMySql('mysql', { dbName: 'partial_loading' }, true));
beforeEach(async () => orm.schema.clearDatabase());
afterAll(async () => {
await orm.schema.dropDatabase();
Expand Down

0 comments on commit 22ad61e

Please sign in to comment.