Save instance with natural compound id


#1

Hi,

I have the following model:

import DefineMap from 'can-define/map/';
import DefineList from 'can-define/list/';
import set from 'can-set';
import superMap from 'can-connect/can/super-map/';
import loader from '@loader';

const QuickbriefDetail = DefineMap.extend({
	seal: false
}, {
	quickbrief_number: 'number',
	product_id: 'number'
});

const algebra = new set.Algebra(
	set.props.id('quickbrief_number'),
	set.props.id('product_id')
);

QuickbriefDetail.List = DefineList.extend({
	'#': QuickbriefDetail
});

QuickbriefDetail.Connection = superMap({

	url: loader.serviceBaseURL + '/quickbrief_detail',  
	Map: QuickbriefDetail,
	List: QuickbriefDetail.List,
	name: 'quickbrief_detail',
	algebra
});

export default QuickbriefDetail;

The quickbrief_detail table has a composite primary key or compound id: quickbrief_number and product_id. Please note the models algebra. I can see in the inspector that all retrieved instances have an id {quickbrief_number}@|@{product_id}. So, algebra is working as expected, its assuming the compound id, GREAT!

But, when i need to persist a new instance calling save(), the connection’s updateData function is called. But what i want is that the createData function is called. I want to POST to the API, not PUT.

var modelInstance = new QuickbriefDetail({
	quickbrief_number: 1,
	product_id: 5,
	prize: 100,
	description: 'Some description'
});

modelInstance.save();

I understand that save(), evaluates if the instance has the id property defined. In this case, the id is defined by the algebra and both properties are set with a value (quickbrief_number, product_id). The values are setted by the app, not generated by the API like a sequence.

What is the best or less hackish approach to resolve this scenario? I was considering add a property called _new (boolean) acting as a flag and overwrite the save method. When the instance is retrieved from database the property _new will not exist, but when the instance is no yet persisted i would add the _new prop with the value true. And in the save() function i would evaluate this flag.

But im sure someone else had the same scenario and is somehow resolved. I just cant figure it out how.

Any comments and help is really appreciated! THANKS


#2

@Gregorio_Godoy, the following might work:

  • Add a new boolean prop “_ new” to your type.
  • Provide your own “id” method to the type’s connection (see docs can-connect/base/base.js#id). Your id’s implementation returns “undefined” when instance._new is true. This way constructor.js#save will fall into the createData flow instead of updateData.
  • To set instance._new to false provide a custom “hydrateInstance” method in a custom behavior that still calls the baseConnection#hydrateInstance (because you’re using the superMap I’m not sure where your custom method should be declared in order to be picked up…).