Algebra clause issue, possible bug?


#1

Hi all!

After 4 days scratching my head i found an issue with algebra and compound id’s. I will explain it with example. Assuming i have a model list like this:

[
	{
		"invoice_number": 5,
		"customer_id": 2,
		"date": "2017-07-05",
		"total": 120,
		"invoice_detail": [
			{
				"invoice_number": 5,
				"product_code": 23,
				"quantity": 1,
				"prize": 62,
				"subtotal": 62
			},
			{
				"invoice_number": 5,
				"product_code": 13,
				"quantity": 1,
				"prize": 58,
				"subtotal": 58
			}
		]

	},
	{
		"invoice_number": 6,
		"customer_id": 2,
		"date": "2017-07-05",
		"total": 80,
		"invoice_detail": [
			{
				"invoice_number": 6,
				"product_code": 47,
				"quantity": 2,
				"prize": 40,
				"subtotal": 80
			}
		]
	}
]

I have two tables: invoice and invoice_detail. Here the maps (Im using the superMap) :

invoice_detail

const InvoiceDetail = DefineMap.extend({
	seal: false
}, {
	invoice_number: 'number',
	product_code: 'number',
	...
});

const algebra = new set.Algebra(
	set.props.id('invoice_number'),
	set.props.id('product_code')
);

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

Invoice

import InvoiceDetail from 'baker/models/invoice_detail';
const Invoice = DefineMap.extend({
	seal: false
}, {
	invoice_number: 'number',
	...
	invoice_detail: {
		Type: InvoiceDetail.List,
		set: function(newVal) {
			if (newVal) {
				InvoiceDetail.Connection.addListReference(newVal,{
					invoice_number: this.invoice_number
				});
            }
			
			return newVal;
		}
	}
});

const algebra = new set.Algebra(
	set.props.id('invoice_number')
);

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

As you can see, invoice’s id is invoice_number and invoice_detail’s id is invoice_number and product_code (natural compound id).

So, when i retrieve an invoice with getList({}) the API returns all invoices, with all they details. For each invoice_detail im adding a list reference using the current invoice_number as set.

invoice_detail: {
		Type: InvoiceDetail.List,
		set: function(newVal) {
			if (newVal) {
				InvoiceDetail.Connection.addListReference(newVal,{
					invoice_number: this.invoice_number
				});
            }
			
			return newVal;
		}
	}

So far no problem. But when im creating a new invoice detail and persisting it to API, the callback is adding this invoice_detail to all invoices list!! I tracked the problem and i think i found it. The update function from the real-time behavior goes through each list and sees if the list should be updated with the new created instance. Basically what it does is checking if the algebra has the set in they properties:

Line 398
if(canSet.has(set, props, self.algebra)) {

The has function is in the set-core, and starts in the line 494

Inside the function, in the line 516

result = this.evaluateOperator(compare.subset, props, set, {isProperties: true}, undefined);

That brings us to the getClausePorperties called inside evaluateOperator function:

var aClauseProps = this.getClauseProperties(a, aOptions),
			bClauseProps = this.getClauseProperties(b, bOptions),
			set = {},
			useSet;

Lets look closer to getClauseProperties. It loops trough all non-where clauses first (order, paginate, id) and looks for a property match in the set. If its founded, its assigned to the clause properties and DELETED from the cloned set. All other properties are assigned to the where clause.

The problem is that the set looks like { invoice_number: 5 } and as it loops first trough all non-where clauses, assigned to the id clauses and deleted, the where clause is empty. That is the reason why the created invoice_detail is added to all invoices list, because the where clause is empty.

I can understand the logic. Usually if the set property is the id property it can’t be the where clause. Following this logic, if a set property belongs to the id, order or paginate it cannot be part of the where clause. And thats absolutely logic if all id’s are just a single property. But in this case the id is compound: invoice_number, product_code. So, when i pass the invoice_number as a set in the invoice detail list, it should be added to the where clause and not to the id clause.

I think this is a bug, because getClauseProperties should evaluate if the id is really set, in this case invoice_number, product_code. Both must be in the set to assign it in the id clause. If not all id properties are set, they should be assign to the where clause.

Is this really a bug or did i misunderstood something? THANKS in advance!!


#2

Almost certainly a bug. Good catch! Can you create an issue? Thanks!


#3

Sure! Never before opened an issue, hope this is ok:

Sorry for the short description and content in the opened issue. Im going to sleep :sleeping: