Skip to content

Commit 3a26f86

Browse files
committed
fix: enable passing id for post in case id has generated set to false
Signed-off-by: Muhammad Aaqil <[email protected]>
1 parent 0c7708d commit 3a26f86

File tree

10 files changed

+127
-13
lines changed

10 files changed

+127
-13
lines changed

examples/access-control-migration/src/models/user-credentials.model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class UserCredentials extends Entity {
1010
@property({
1111
type: 'number',
1212
id: true,
13+
generated: true,
1314
})
1415
id: number;
1516

examples/express-composition/src/models/note.model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class Note extends Entity {
1010
@property({
1111
type: 'number',
1212
id: true,
13+
generated: true,
1314
})
1415
id?: number;
1516

examples/passport-login/src/models/user-credentials.model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class UserCredentials extends Entity {
1111
@property({
1212
type: 'string',
1313
id: true,
14+
generated: false,
1415
})
1516
id: string;
1617

examples/passport-login/src/models/user-identity.model.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class UserIdentity extends Entity {
1111
@property({
1212
type: 'string',
1313
id: true,
14+
generated: false,
1415
})
1516
id: string;
1617

examples/rest-crud/src/models/todo.model.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class Todo extends Entity {
1010
@property({
1111
type: 'number',
1212
id: true,
13-
generated: false,
13+
generated: true,
1414
})
1515
id?: number;
1616

examples/todo/src/models/todo.model.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class Todo extends Entity {
1010
@property({
1111
type: 'number',
1212
id: true,
13-
generated: false,
13+
generated: true,
1414
})
1515
id?: number;
1616

packages/repository/src/__tests__/unit/model/define-model-class.unit.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ describe('defineModelClass', () => {
5353

5454
it('creates an Entity class', () => {
5555
const definition = new ModelDefinition('Product')
56-
.addProperty('id', {type: 'number', id: true})
56+
.addProperty('id', {
57+
type: 'number',
58+
id: true,
59+
generated: true,
60+
})
5761
.addProperty('name', {
5862
type: 'string',
5963
});
@@ -70,6 +74,7 @@ describe('defineModelClass', () => {
7074

7175
// Verify that typedefs allows us to access static Entity properties
7276
expect(Product.getIdProperties()).to.deepEqual(['id']);
77+
expect(Product.getExcludeProperties()).to.deepEqual(['id']);
7378

7479
// Verify that typedefs allows us to create new model instances
7580
const instance = new Product({id: 1, name: 'a name'});
@@ -83,7 +88,11 @@ describe('defineModelClass', () => {
8388

8489
it('creates a free-form Entity', () => {
8590
const definition = new ModelDefinition('FreeForm')
86-
.addProperty('id', {type: 'number', id: true})
91+
.addProperty('id', {
92+
type: 'number',
93+
id: true,
94+
generated: true,
95+
})
8796
.addSetting('strict', false);
8897

8998
const FreeForm = defineModelClass<typeof Entity, AnyObject>(
@@ -98,6 +107,7 @@ describe('defineModelClass', () => {
98107

99108
// Verify that typedefs allows us to access static Entity properties
100109
expect(FreeForm.getIdProperties()).to.deepEqual(['id']);
110+
expect(FreeForm.getExcludeProperties()).to.deepEqual(['id']);
101111

102112
// Verify that typedefs allows us to create new model instances
103113
const instance = new FreeForm({id: 1, name: 'a name'});

packages/repository/src/model.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,15 @@ export class Entity extends Model implements Persistable {
444444
static getIdProperties(): string[] {
445445
return this.definition.idProperties();
446446
}
447-
447+
static getExcludeProperties(): string[] {
448+
const {properties} = this.definition;
449+
const idProps = Object.keys(properties).filter(prop => {
450+
if (properties[prop].id && properties[prop].generated) {
451+
return properties[prop].id;
452+
}
453+
});
454+
return idProps;
455+
}
448456
/**
449457
* Get the identity value for a given entity instance or entity data object.
450458
*

packages/rest-crud/src/__tests__/acceptance/default-model-crud-rest.acceptance.ts

+94-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {defineCrudRestController} from '../..';
3030
describe('CrudRestController for a simple Product model', () => {
3131
@model()
3232
class Product extends Entity {
33-
@property({id: true})
33+
@property({id: true, generated: 1})
3434
id: number;
3535

3636
@property({required: true})
@@ -44,8 +44,47 @@ describe('CrudRestController for a simple Product model', () => {
4444
}
4545
}
4646

47+
@model()
48+
class User extends Entity {
49+
@property({id: true, generated: 0, defaultFn: 'uuid'})
50+
id: string;
51+
52+
@property({required: true})
53+
username: string;
54+
55+
@property()
56+
email?: string;
57+
58+
constructor(data: Partial<User>) {
59+
super(data);
60+
}
61+
}
62+
63+
@model()
64+
class Customer extends Entity {
65+
@property({id: true, generated: 0})
66+
id: number;
67+
68+
@property({required: true})
69+
name: string;
70+
71+
@property()
72+
email?: string;
73+
74+
constructor(data: Partial<Customer>) {
75+
super(data);
76+
}
77+
}
78+
4779
let app: RestApplication;
4880
let repo: EntityCrudRepository<Product, typeof Product.prototype.id>;
81+
let customerRepo: EntityCrudRepository<
82+
Customer,
83+
typeof Customer.prototype.id
84+
>;
85+
86+
let userRepo: EntityCrudRepository<User, typeof User.prototype.id>;
87+
4988
let client: Client;
5089

5190
// sample data - call `seedData` to populate these items
@@ -76,7 +115,7 @@ describe('CrudRestController for a simple Product model', () => {
76115
expect(toJSON(found)).to.deepEqual(created);
77116
});
78117

79-
it('rejects request with `id` value', async () => {
118+
it('rejects request with `id` value when generated is set to 1', async () => {
80119
const {body} = await client
81120
.post('/products')
82121
.send({id: 1, name: 'a name'})
@@ -94,6 +133,29 @@ describe('CrudRestController for a simple Product model', () => {
94133
],
95134
});
96135
});
136+
137+
it('creates records when `id` has generated set to 0 with defaultFn', async () => {
138+
const user = {username: 'johndoe'};
139+
const {body: userCreated} = await client
140+
.post('/users')
141+
.send(user)
142+
.expect(200);
143+
expect(userCreated).to.have.property('id').of.type('string');
144+
const userFound = (await userRepo.find())[0];
145+
expect(toJSON(userFound)).to.deepEqual(userCreated);
146+
});
147+
148+
it('accepts request with `id` value when generated is set to 0', async () => {
149+
const customer = {id: 1, name: 'a name'};
150+
const {body: customerCreated} = await client
151+
.post('/customers')
152+
.send(customer)
153+
.expect(200);
154+
expect(customerCreated).to.containEql(customer);
155+
expect(customerCreated).to.have.property('id').of.type('number');
156+
const customerFound = (await customerRepo.find())[0];
157+
expect(toJSON(customerFound)).to.deepEqual(customerCreated);
158+
});
97159
});
98160

99161
describe('find', () => {
@@ -289,23 +351,53 @@ describe('CrudRestController for a simple Product model', () => {
289351
const db = new juggler.DataSource({connector: 'memory'});
290352

291353
const ProductRepository = defineCrudRepositoryClass(Product);
354+
const CustomerRepository = defineCrudRepositoryClass(Customer);
355+
const UserRepository = defineCrudRepositoryClass(User);
292356

293357
repo = new ProductRepository(db);
358+
customerRepo = new CustomerRepository(db);
359+
userRepo = new UserRepository(db);
294360

295361
const CrudRestController = defineCrudRestController<
296362
Product,
297363
typeof Product.prototype.id,
298364
'id'
299365
>(Product, {basePath: '/products'});
300366

367+
const CrudRestControllerForCustomer = defineCrudRestController<
368+
Customer,
369+
typeof Customer.prototype.id,
370+
'id'
371+
>(Customer, {basePath: '/customers'});
372+
373+
const CrudRestControllerForUser = defineCrudRestController<
374+
User,
375+
typeof User.prototype.id,
376+
'id'
377+
>(User, {basePath: '/users'});
378+
301379
class ProductController extends CrudRestController {
302380
constructor() {
303381
super(repo);
304382
}
305383
}
306384

385+
class CustomerController extends CrudRestControllerForCustomer {
386+
constructor() {
387+
super(customerRepo);
388+
}
389+
}
390+
391+
class UserController extends CrudRestControllerForUser {
392+
constructor() {
393+
super(userRepo);
394+
}
395+
}
396+
307397
app = new RestApplication({rest: givenHttpServerConfig()});
308398
app.controller(ProductController);
399+
app.controller(CustomerController);
400+
app.controller(UserController);
309401

310402
await app.start();
311403
client = createRestAppClient(app);

packages/rest-crud/src/crud-rest.controller.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ import {
1414
Where,
1515
} from '@loopback/repository';
1616
import {
17+
JsonSchemaOptions,
18+
MediaTypeObject,
19+
ParameterObject,
20+
ResponsesObject,
21+
SchemaObject,
1722
api,
1823
del,
1924
get,
2025
getFilterSchemaFor,
2126
getJsonSchema,
2227
getModelSchemaRef,
23-
JsonSchemaOptions,
2428
jsonToSchemaObject,
25-
MediaTypeObject,
2629
param,
27-
ParameterObject,
2830
patch,
2931
post,
3032
put,
3133
requestBody,
32-
ResponsesObject,
33-
SchemaObject,
3434
} from '@loopback/rest';
3535
import assert from 'assert';
3636

@@ -208,7 +208,7 @@ export function defineCrudRestController<
208208
async create(
209209
@body(modelCtor, {
210210
title: `New${modelName}`,
211-
exclude: modelCtor.getIdProperties() as (keyof T)[],
211+
exclude: modelCtor.getExcludeProperties() as (keyof T)[],
212212
})
213213
data: Omit<T, IdName>,
214214
): Promise<T> {

0 commit comments

Comments
 (0)