Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

orma

Package Overview
Dependencies
Maintainers
2
Versions
236
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

orma - npm Package Compare versions

Comparing version 1.0.77 to 1.0.78

2

build/helpers/schema_helpers.d.ts

@@ -49,3 +49,3 @@ /**

export declare const get_direct_edges: (from_entity: string, to_entity: string, orma_schema: OrmaSchema) => Edge[];
export declare const get_direct_edge: (from_entity: string, to_entity: string, orma_schema: OrmaSchema) => Edge;
export declare const get_direct_edge: (from_entity: string, to_entity: string, orma_schema: OrmaSchema, foreign_key_override?: string[]) => Edge;
/**

@@ -52,0 +52,0 @@ * returns a list of edges which, when traversed one after the other, connect the first given entity to the last.

@@ -127,4 +127,12 @@ "use strict";

*/
const get_direct_edge = (from_entity, to_entity, orma_schema) => {
const edges = (0, exports.get_direct_edges)(from_entity, to_entity, orma_schema);
const get_direct_edge = (from_entity, to_entity, orma_schema, foreign_key_override = undefined) => {
const parent_edges = (0, exports.get_parent_edges)(from_entity, orma_schema).filter(el => el.to_entity === to_entity);
const child_edges = (0, exports.get_child_edges)(from_entity, orma_schema).filter(el => el.to_entity === to_entity);
const filtered_parent_edges = foreign_key_override
? parent_edges.filter(edge => edge.from_field === foreign_key_override[0])
: parent_edges;
const filtered_child_edges = foreign_key_override
? child_edges.filter(edge => edge.to_field === foreign_key_override[0])
: child_edges;
const edges = [...filtered_parent_edges, ...filtered_child_edges];
if (edges.length !== 1) {

@@ -131,0 +139,0 @@ throw Error(`Did not find exactly one edge from ${from_entity} to ${to_entity}`);

@@ -28,4 +28,4 @@ "use strict";

if (ancestor_result === undefined || ancestor_result[1].length === 0) {
// this case where there are no ancestor results can happen if, for example, this is a nested lower entitiy but
// nothing was returned from the higher entitiy. In this case, we want nothing of this entity to be queried
// this case where there are no ancestor results can happen if, for example, this is a nested lower entitiy but
// nothing was returned from the higher entitiy. In this case, we want nothing of this entity to be queried
// so we use an impossible where clause that returns nothing.

@@ -38,3 +38,3 @@ return {

const ancestor_to_entity_path = subquery_path.slice(nesting_ancestor_index + 1, Infinity);
const ancestor_where_clause = get_ancestor_where_clause(ancestor_rows, ancestor_path, ancestor_to_entity_path, query, orma_schema);
const ancestor_where_clause = get_ancestor_where_clause(ancestor_rows, subquery_path, nesting_ancestor_index, query, orma_schema);
return ancestor_where_clause;

@@ -69,26 +69,36 @@ };

*/
const get_ancestor_where_clause = (ancestor_rows, ancestor_path, ancestor_to_entity_path, query, orma_schema) => {
const ancestor_name = (0, query_1.get_real_entity_name)(ancestor_path, query);
const under_ancestor_path = [...ancestor_path, ancestor_to_entity_path[0]];
const entity_under_ancestor = (0, query_1.get_real_entity_name)(under_ancestor_path, query);
const edge_under_ancestor = (0, schema_helpers_1.get_direct_edge)(entity_under_ancestor, ancestor_name, orma_schema);
const get_ancestor_where_clause = (ancestor_rows, entity_path, ancestor_index, query, orma_schema) => {
const ancestor_to_entity_edge_path = get_query_edge_path(query, entity_path, ancestor_index, orma_schema);
const edge_under_ancestor = ancestor_to_entity_edge_path[0];
if (ancestor_rows === undefined || ancestor_rows.length === 0) {
const ancestor_name = ancestor_to_entity_edge_path[0].from_entity;
throw Error(`No ancestor rows provided for ${ancestor_name}`);
}
const ancestor_foreign_key_values = ancestor_rows.map(row => row[edge_under_ancestor.to_field]);
const entity_to_ancestor_path = ancestor_to_entity_path.slice().reverse();
const any_path = entity_to_ancestor_path.slice(1, entity_to_ancestor_path.length);
const entity_name = entity_to_ancestor_path[0];
const ancestor_query = (0, any_path_macro_1.process_any_clause)({
$any_path: [
any_path,
{
$in: [
edge_under_ancestor.from_field,
ancestor_foreign_key_values,
],
},
],
}, entity_name, '$where', orma_schema);
const ancestor_foreign_key_values = ancestor_rows.map(row => row[edge_under_ancestor.from_field]);
// reverse the path since we are making the where clause in the entity and want to search based on ancestor
const entity_to_ancestor_edge_path = ancestor_to_entity_edge_path
// exclude the entity closest to the ancestor, since this entity is already accounted for in the final $in clause
.slice(1, Infinity)
// to reverse the path, we have to reverse the order of the edges but also reverse each
// individual edge
.reverse()
.map(edge => (0, schema_helpers_1.reverse_edge)(edge));
const ancestor_query = (0, any_path_macro_1.edge_path_to_where_ins)(entity_to_ancestor_edge_path, '$where', {
$in: [edge_under_ancestor.to_field, ancestor_foreign_key_values],
});
return ancestor_query;
};
const get_query_edge_path = (query, path_to_last_subquery, start_path_index, orma_schema) => {
let edge_path = [];
// dont run the for loop on the last element, since each for loop iteration makes an edge to the
for (let i = start_path_index; i < path_to_last_subquery.length - 1; i++) {
const subquery_path = path_to_last_subquery.slice(0, i + 1);
const subquery = (0, helpers_1.deep_get)(subquery_path, query);
const subquery_entity = (0, query_1.get_real_entity_name)(path_to_last_subquery[i], subquery);
const next_subquery = subquery[path_to_last_subquery[i + 1]];
const next_subquery_entity = (0, query_1.get_real_entity_name)(path_to_last_subquery[i + 1], next_subquery);
const edge = (0, schema_helpers_1.get_direct_edge)(subquery_entity, next_subquery_entity, orma_schema, next_subquery.$foreign_key);
edge_path.push(edge);
}
return edge_path;
};

@@ -21,2 +21,29 @@ "use strict";

},
payments: {
id: {},
from_vendor_id: {
references: {
vendors: {
id: {},
},
},
},
to_vendor_id: {
references: {
vendors: {
id: {},
},
},
},
},
receipts: {
id: {},
payment_id: {
references: {
payments: {
id: {},
},
},
},
},
images: {

@@ -216,7 +243,8 @@ id: {},

const query = {
products: {
images: {
$where: undefined,
$having: undefined,
image_urls: {},
vendors: {
payments: {
$foreign_key: ['from_vendor_id'],
receipts: {
id: true
},
},

@@ -226,20 +254,19 @@ },

const previous_results = [
[['products'], [{ id: 1 }, { id: 2 }]],
// [['products', 'images'], [{ id: 3 }]],
[['vendors'], [{ id: 1 }, { id: 2 }]],
];
(0, nesting_macro_1.apply_nesting_macro)(query, ['products', 'images', 'image_urls'], previous_results, orma_schema);
(0, nesting_macro_1.apply_nesting_macro)(query, ['vendors', 'payments', 'receipts'], previous_results, orma_schema);
const goal = {
products: {
images: {
$where: undefined,
$having: undefined,
image_urls: {
vendors: {
payments: {
$foreign_key: ['from_vendor_id'],
receipts: {
id: true,
$where: {
$in: [
'image_id',
'payment_id',
{
$select: ['id'],
$from: 'images',
$from: 'payments',
$where: {
$in: ['product_id', [1, 2]],
$in: ['from_vendor_id', [1, 2]],
},

@@ -246,0 +273,0 @@ },

@@ -6,2 +6,4 @@ import { OrmaSchema } from '../../introspector/introspector';

export declare const apply_select_macro: (query: any, orma_schema: OrmaSchema) => void;
export declare const get_select: (subquery: any, subquery_path: string[], orma_schema: OrmaSchema) => any[];
export declare const get_select: (subquery: any, subquery_path: string[], orma_schema: OrmaSchema) => (string | {
$as: any[];
})[];

@@ -23,3 +23,5 @@ "use strict";

}
const new_select_names = new_select.map(el => (el === null || el === void 0 ? void 0 : el.$as) ? el.$as[1] : el);
const new_select_names = new_select.map(el =>
// @ts-ignore
(el === null || el === void 0 ? void 0 : el.$as) ? el.$as[1] : el);
for (const select of new_select_names) {

@@ -50,4 +52,4 @@ delete value[select];

const lower_subquery_entity = (_a = lower_subquery.$from) !== null && _a !== void 0 ? _a : key;
const edge_to_lower_table = (0, schema_helpers_1.get_direct_edge)(entity_name, lower_subquery_entity, orma_schema);
return edge_to_lower_table.from_field;
const edges_to_lower_table = (0, schema_helpers_1.get_direct_edges)(entity_name, lower_subquery_entity, orma_schema);
return edges_to_lower_table.map(el => el.from_field);
}

@@ -58,4 +60,4 @@ return []; // subqueries are not handled here

const higher_entity = subquery_path[subquery_path.length - 2];
const edge_to_higher_entity = (0, schema_helpers_1.get_direct_edge)(entity_name, higher_entity, orma_schema);
$select.push(edge_to_higher_entity.from_field);
const edges_to_higher_entity = (0, schema_helpers_1.get_direct_edges)(entity_name, higher_entity, orma_schema);
$select.push(...edges_to_higher_entity.map(el => el.from_field));
}

@@ -62,0 +64,0 @@ return [...new Set($select)]; // unique values

@@ -66,21 +66,21 @@ "use strict";

let where_clause_locations = [];
(0, query_helpers_1.query_for_each)(query, (subquery, path) => {
(0, query_helpers_1.query_for_each)(query, (subquery, subquery_path) => {
if (subquery.$where) {
(0, helpers_1.deep_for_each)(subquery.$where, (value, path) => {
if (value === null || value === void 0 ? void 0 : value.$from) {
where_clause_locations.push({ value, path });
(0, helpers_1.deep_for_each)(subquery.$where, (where_clause, where_clause_path) => {
if (where_clause === null || where_clause === void 0 ? void 0 : where_clause.$from) {
where_clause_locations.push({ where_clause, where_clause_path });
}
});
}
subquery_locations.push({ value: subquery, path });
subquery_locations.push({ subquery, subquery_path });
});
// generate where clauses for all the paths that we found
where_clause_locations.forEach(({ value, path }) => {
const entity_name = value.$from;
apply_where_connected_to_subquery(connection_edges, query.$where_connected, value, entity_name, undefined);
where_clause_locations.forEach(({ where_clause, where_clause_path }) => {
const entity_name = where_clause.$from;
apply_where_connected_to_subquery(connection_edges, query.$where_connected, where_clause, entity_name, undefined);
});
subquery_locations.forEach(({ value, path }) => {
const entity_name = (0, query_1.get_real_entity_name)(path, value);
const higher_entity = (0, query_1.get_real_higher_entity_name)(path, value);
apply_where_connected_to_subquery(connection_edges, query.$where_connected, value, entity_name, higher_entity);
subquery_locations.forEach(({ subquery, subquery_path }) => {
const entity_name = (0, query_1.get_real_entity_name)((0, helpers_1.last)(subquery_path), subquery);
const higher_entity = (0, query_1.get_real_higher_entity_name)(subquery_path, subquery);
apply_where_connected_to_subquery(connection_edges, query.$where_connected, subquery, entity_name, higher_entity);
});

@@ -87,0 +87,0 @@ return query;

@@ -7,3 +7,3 @@ import { error_type } from '../helpers/error_handling';

export declare const get_real_higher_entity_name: (path: (string | number)[], query: any) => any;
export declare const get_real_entity_name: (path: (string | number)[], query: any) => any;
export declare const get_real_entity_name: (last_path_item: string, subquery: Record<string, any>) => any;
export declare const having_to_json_sql: (query: any, subquery_path: string[], orma_schema: OrmaSchema) => any;

@@ -10,0 +10,0 @@ export declare const orma_nester: (results: [string[], Record<string, unknown>[]][], query: any, orma_schema: OrmaSchema) => {};

@@ -23,4 +23,5 @@ "use strict";

// This function will default to the from clause
const get_real_entity_name = (path, query) => {
return (0, helpers_1.deep_get)([...path, '$from'], query, null) || (0, helpers_1.last)(path);
const get_real_entity_name = (last_path_item, subquery) => {
var _a;
return (_a = subquery.$from) !== null && _a !== void 0 ? _a : last_path_item;
};

@@ -83,5 +84,8 @@ exports.get_real_entity_name = get_real_entity_name;

}
const entity = (0, exports.get_real_entity_name)(path, query);
const higher_entity = (0, exports.get_real_entity_name)(path.slice(0, -1), query);
const edge = (0, schema_helpers_1.get_direct_edge)(higher_entity, entity, orma_schema);
const higher_entity_path = path.slice(0, -1);
const higher_entity = (0, helpers_1.deep_get)(higher_entity_path, query);
const entity = higher_entity[(0, helpers_1.last)(path)];
const entity_name = (0, exports.get_real_entity_name)((0, helpers_1.last)(path), entity);
const higher_entity_name = (0, exports.get_real_entity_name)((0, helpers_1.last)(higher_entity_path), higher_entity);
const edge = (0, schema_helpers_1.get_direct_edge)(higher_entity_name, entity_name, orma_schema, entity.$foreign_key);
return [edge.from_field, edge.to_field];

@@ -88,0 +92,0 @@ });

@@ -1,261 +0,261 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const mocha_1 = require("mocha");
const validate_query_manual_1 = require("./validate_query_manual");
const schema = {
grand_parent: {
id: {},
grand_parent_column: {},
},
parent: {
id: {},
parent_column: {},
grand_parent_id: {
references: {
grand_parent: {
id: {},
},
},
},
},
child: {
id: {},
child_column: {},
parent_id: {
references: {
parent: {
id: {},
},
},
},
},
};
/*
{
qty: {
$sum: 'quantity'
},
inventory_adjustments: {
variants: {
sku: true
}
},
inventory_adjustments: {
quantity: true
}
}
*/
(0, mocha_1.describe)('validate_query.ts', () => {
(0, mocha_1.describe)('boolean resolver', () => {
(0, mocha_1.test)('validates boolean resolver column names', () => {
const query = {
grand_parent: {
id: true,
grand_parent_column: true,
parent: {
parent_column: true,
child: {
id: true,
child_column_oops: true,
},
},
},
};
const errors = (0, validate_query_manual_1.validator)(query, schema);
(0, chai_1.expect)(errors.length).to.deep.equal(1);
(0, chai_1.expect)(errors[0].path).to.deep.equal([
'grand_parent',
'parent',
'child',
'child_column_oops',
]);
});
});
(0, mocha_1.describe)('virtual columns', () => {
(0, mocha_1.test)('validates $field virtual column', () => {
const query = {
parent: {
custom_name: { $field: 'parent_column' },
custom_name2: { $field: 'oops' },
},
};
const errors = (0, validate_query_manual_1.validator)(query, schema);
(0, chai_1.expect)(errors[0].path).to.deep.equal(['parent', 'custom_name2']);
(0, chai_1.expect)(errors.length).to.deep.equal(1);
});
});
(0, mocha_1.describe)('subqueries', () => {
(0, mocha_1.test)('validates the from clause', () => {
const data = {
parent: {
good: {
$from: 'child',
id: true,
},
bad: {
$from: 'oops',
id: true,
},
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
const from_clause_errors = errors.filter(err => JSON.stringify(err.path) ===
JSON.stringify(['parent', 'bad', 'id']));
(0, chai_1.expect)(from_clause_errors.length).to.equal(1);
});
(0, mocha_1.test)('validates subquery connections', () => {
const data = {
grand_parent: {
john: {
$from: 'parent',
child: {
id: true,
grand_parent: {
id: true,
},
},
},
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(1);
(0, chai_1.expect)(errors[0].path).to.deep.equal([
'grand_parent',
'john',
'child',
'grand_parent',
]);
});
});
mocha_1.describe.skip('clauses', () => {
(0, mocha_1.test)('Requires $eq to have valid field name', () => {
const data = {
parent: {
$where: {
$eq: ['my_id', 5],
},
my_id: {
$field: 'id',
},
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(1);
(0, chai_1.expect)(errors[0].path).to.deep.equal(['parent', '$where']);
});
(0, mocha_1.test)('Lets $having have aliased fields', () => {
const data = {
parent: {
$having: {
$eq: ['my_id', 5],
},
my_id: {
$field: 'id',
},
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(0);
});
(0, mocha_1.test)('Lets operators have functions', () => {
const data = {
parent: {
$where: {
$eq: ['name', { $field: 'id' }],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(0);
});
(0, mocha_1.test)('Lets operators have functions', () => {
const data = {
parent: {
$where: {
$lte: ['name', { $field: 'id' }],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(0);
});
(0, mocha_1.test)('Lets $and', () => {
const data = {
parent: {
$where: {
$and: [
{
$eq: ['id', '5'],
},
],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(0);
});
(0, mocha_1.test)('Changes scope for subqueries', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['parent_id'],
$from: 'child',
$where: {
$eq: ['name', 3], // invalid because 'name' is a field of parent, not child
},
},
],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(1);
});
(0, mocha_1.test)('Requires subqueries to have valid fields', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['invalid_field'],
$from: 'child',
},
],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(1);
});
(0, mocha_1.test)('Requires subqueries to have valid fields', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['name'],
$from: 'fake_table',
},
],
},
id: 'id',
},
};
const errors = (0, validate_query_manual_1.validator)(data, schema);
(0, chai_1.expect)(errors.length).to.equal(1);
});
});
});
// import { expect } from 'chai'
// import { describe, test } from 'mocha'
// import { OrmaSchema } from '../introspector/introspector'
// import { validator } from './validate_query_manual'
// const schema: OrmaSchema = {
// grand_parent: {
// id: {},
// grand_parent_column: {},
// },
// parent: {
// id: {},
// parent_column: {},
// grand_parent_id: {
// references: {
// grand_parent: {
// id: {},
// },
// },
// },
// },
// child: {
// id: {},
// child_column: {},
// parent_id: {
// references: {
// parent: {
// id: {},
// },
// },
// },
// },
// }
// /*
// {
// qty: {
// $sum: 'quantity'
// },
// inventory_adjustments: {
// variants: {
// sku: true
// }
// },
// inventory_adjustments: {
// quantity: true
// }
// }
// */
// describe('validate_query.ts', () => {
// describe('boolean resolver', () => {
// test('validates boolean resolver column names', () => {
// const query = {
// grand_parent: {
// id: true,
// grand_parent_column: true,
// parent: {
// parent_column: true,
// child: {
// id: true,
// child_column_oops: true,
// },
// },
// },
// }
// const errors = validator(query, schema)
// expect(errors.length).to.deep.equal(1)
// expect(errors[0].path).to.deep.equal([
// 'grand_parent',
// 'parent',
// 'child',
// 'child_column_oops',
// ])
// })
// })
// describe('virtual columns', () => {
// test('validates $field virtual column', () => {
// const query = {
// parent: {
// custom_name: { $field: 'parent_column' },
// custom_name2: { $field: 'oops' },
// },
// }
// const errors = validator(query, schema)
// expect(errors[0].path).to.deep.equal(['parent', 'custom_name2'])
// expect(errors.length).to.deep.equal(1)
// })
// })
// describe('subqueries', () => {
// test('validates the from clause', () => {
// const data = {
// parent: {
// good: {
// $from: 'child',
// id: true,
// },
// bad: {
// $from: 'oops',
// id: true,
// },
// },
// }
// const errors = validator(data, schema)
// const from_clause_errors = errors.filter(
// err =>
// JSON.stringify(err.path) ===
// JSON.stringify(['parent', 'bad', 'id'])
// )
// expect(from_clause_errors.length).to.equal(1)
// })
// test('validates subquery connections', () => {
// const data = {
// grand_parent: {
// john: {
// $from: 'parent',
// child: {
// id: true,
// grand_parent: {
// id: true,
// },
// },
// },
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(1)
// expect(errors[0].path).to.deep.equal([
// 'grand_parent',
// 'john',
// 'child',
// 'grand_parent',
// ])
// })
// })
// describe.skip('clauses', () => {
// test('Requires $eq to have valid field name', () => {
// const data = {
// parent: {
// $where: {
// $eq: ['my_id', 5],
// },
// my_id: {
// $field: 'id',
// },
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(1)
// expect(errors[0].path).to.deep.equal(['parent', '$where'])
// })
// test('Lets $having have aliased fields', () => {
// const data = {
// parent: {
// $having: {
// $eq: ['my_id', 5],
// },
// my_id: {
// $field: 'id',
// },
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(0)
// })
// test('Lets operators have functions', () => {
// const data = {
// parent: {
// $where: {
// $eq: ['name', { $field: 'id' }],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(0)
// })
// test('Lets operators have functions', () => {
// const data = {
// parent: {
// $where: {
// $lte: ['name', { $field: 'id' }],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(0)
// })
// test('Lets $and', () => {
// const data = {
// parent: {
// $where: {
// $and: [
// {
// $eq: ['id', '5'],
// },
// ],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(0)
// })
// test('Changes scope for subqueries', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['parent_id'],
// $from: 'child',
// $where: {
// $eq: ['name', 3], // invalid because 'name' is a field of parent, not child
// },
// },
// ],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(1)
// })
// test('Requires subqueries to have valid fields', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['invalid_field'],
// $from: 'child',
// },
// ],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(1)
// })
// test('Requires subqueries to have valid fields', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['name'],
// $from: 'fake_table',
// },
// ],
// },
// id: 'id',
// },
// }
// const errors = validator(data, schema)
// expect(errors.length).to.equal(1)
// })
// })
// })
{
"name": "orma",
"version": "1.0.77",
"version": "1.0.78",
"description": "A declarative relational syncronous orm",

@@ -5,0 +5,0 @@ "main": "build/index.js",

@@ -166,6 +166,26 @@ /**

to_entity: string,
orma_schema: OrmaSchema
orma_schema: OrmaSchema,
foreign_key_override: string[] = undefined
) => {
const edges = get_direct_edges(from_entity, to_entity, orma_schema)
const parent_edges = get_parent_edges(from_entity, orma_schema).filter(
el => el.to_entity === to_entity
)
const child_edges = get_child_edges(from_entity, orma_schema).filter(
el => el.to_entity === to_entity
)
const filtered_parent_edges = foreign_key_override
? parent_edges.filter(
edge => edge.from_field === foreign_key_override[0]
)
: parent_edges
const filtered_child_edges = foreign_key_override
? child_edges.filter(
edge => edge.to_field === foreign_key_override[0]
)
: child_edges
const edges = [...filtered_parent_edges, ...filtered_child_edges]
if (edges.length !== 1) {

@@ -172,0 +192,0 @@ throw Error(

@@ -21,2 +21,29 @@ import { describe, test } from 'mocha'

},
payments: {
id: {},
from_vendor_id: {
references: {
vendors: {
id: {},
},
},
},
to_vendor_id: {
references: {
vendors: {
id: {},
},
},
},
},
receipts: {
id: {},
payment_id: {
references: {
payments: {
id: {},
},
},
},
},
images: {

@@ -31,3 +58,3 @@ id: {},

},
}, //TODO: make a table connected with 2 foreign keys
},
image_urls: {

@@ -266,7 +293,8 @@ image_id: {

const query = {
products: {
images: {
$where: undefined,
$having: undefined,
image_urls: {},
vendors: {
payments: {
$foreign_key: ['from_vendor_id'],
receipts: {
id: true
},
},

@@ -277,8 +305,7 @@ },

const previous_results = [
[['products'], [{ id: 1 }, { id: 2 }]],
// [['products', 'images'], [{ id: 3 }]],
[['vendors'], [{ id: 1 }, { id: 2 }]],
]
apply_nesting_macro(
query,
['products', 'images', 'image_urls'],
['vendors', 'payments', 'receipts'],
previous_results,

@@ -289,15 +316,15 @@ orma_schema

const goal = {
products: {
images: {
$where: undefined,
$having: undefined,
image_urls: {
vendors: {
payments: {
$foreign_key: ['from_vendor_id'],
receipts: {
id: true,
$where: {
$in: [
'image_id',
'payment_id',
{
$select: ['id'],
$from: 'images',
$from: 'payments',
$where: {
$in: ['product_id', [1, 2]],
$in: ['from_vendor_id', [1, 2]],
},

@@ -304,0 +331,0 @@ },

@@ -1,7 +0,11 @@

import { deep_get } from '../../helpers/helpers'
import { get_direct_edge } from '../../helpers/schema_helpers'
import { deep_get, last } from '../../helpers/helpers'
import {
Edge,
get_direct_edge,
reverse_edge,
} from '../../helpers/schema_helpers'
import { OrmaSchema } from '../../introspector/introspector'
import { get_real_entity_name } from '../query'
import { combine_wheres } from '../query_helpers'
import { process_any_clause } from './any_path_macro'
import { edge_path_to_where_ins, process_any_clause } from './any_path_macro'

@@ -55,4 +59,4 @@ /**

if (ancestor_result === undefined || ancestor_result[1].length === 0) {
// this case where there are no ancestor results can happen if, for example, this is a nested lower entitiy but
// nothing was returned from the higher entitiy. In this case, we want nothing of this entity to be queried
// this case where there are no ancestor results can happen if, for example, this is a nested lower entitiy but
// nothing was returned from the higher entitiy. In this case, we want nothing of this entity to be queried
// so we use an impossible where clause that returns nothing.

@@ -73,4 +77,4 @@ return {

ancestor_rows,
ancestor_path,
ancestor_to_entity_path,
subquery_path,
nesting_ancestor_index,
query,

@@ -113,22 +117,18 @@ orma_schema

ancestor_rows: Record<string, unknown>[],
ancestor_path: string[],
ancestor_to_entity_path: string[],
entity_path: string[],
ancestor_index: number,
query,
orma_schema: OrmaSchema
) => {
const ancestor_name = get_real_entity_name(ancestor_path, query)
const under_ancestor_path = [...ancestor_path, ancestor_to_entity_path[0]]
const entity_under_ancestor = get_real_entity_name(
under_ancestor_path,
query
)
const edge_under_ancestor = get_direct_edge(
entity_under_ancestor,
ancestor_name,
const ancestor_to_entity_edge_path = get_query_edge_path(
query,
entity_path,
ancestor_index,
orma_schema
)
const edge_under_ancestor = ancestor_to_entity_edge_path[0]
if (ancestor_rows === undefined || ancestor_rows.length === 0) {
const ancestor_name = ancestor_to_entity_edge_path[0].from_entity
throw Error(`No ancestor rows provided for ${ancestor_name}`)

@@ -138,26 +138,19 @@ }

const ancestor_foreign_key_values = ancestor_rows.map(
row => row[edge_under_ancestor.to_field]
row => row[edge_under_ancestor.from_field]
)
const entity_to_ancestor_path = ancestor_to_entity_path.slice().reverse()
const any_path = entity_to_ancestor_path.slice(
1,
entity_to_ancestor_path.length
)
const entity_name = entity_to_ancestor_path[0]
const ancestor_query = process_any_clause(
// reverse the path since we are making the where clause in the entity and want to search based on ancestor
const entity_to_ancestor_edge_path = ancestor_to_entity_edge_path
// exclude the entity closest to the ancestor, since this entity is already accounted for in the final $in clause
.slice(1, Infinity)
// to reverse the path, we have to reverse the order of the edges but also reverse each
// individual edge
.reverse()
.map(edge => reverse_edge(edge))
const ancestor_query = edge_path_to_where_ins(
entity_to_ancestor_edge_path,
'$where',
{
$any_path: [
any_path,
{
$in: [
edge_under_ancestor.from_field,
ancestor_foreign_key_values,
],
},
],
},
entity_name,
'$where',
orma_schema
$in: [edge_under_ancestor.to_field, ancestor_foreign_key_values],
}
)

@@ -167,1 +160,35 @@

}
const get_query_edge_path = (
query: any,
path_to_last_subquery: string[],
start_path_index: number,
orma_schema: OrmaSchema
) => {
let edge_path: Edge[] = []
// dont run the for loop on the last element, since each for loop iteration makes an edge to the
for (let i = start_path_index; i < path_to_last_subquery.length - 1; i++) {
const subquery_path = path_to_last_subquery.slice(0, i + 1)
const subquery = deep_get(subquery_path, query)
const subquery_entity = get_real_entity_name(
path_to_last_subquery[i],
subquery
)
const next_subquery = subquery[path_to_last_subquery[i + 1]]
const next_subquery_entity = get_real_entity_name(
path_to_last_subquery[i + 1],
next_subquery
)
const edge = get_direct_edge(
subquery_entity,
next_subquery_entity,
orma_schema,
next_subquery.$foreign_key
)
edge_path.push(edge)
}
return edge_path
}
import { is_simple_object, last } from '../../helpers/helpers'
import {
get_direct_edge,
get_direct_edges,
is_reserved_keyword,

@@ -28,2 +29,3 @@ } from '../../helpers/schema_helpers'

const new_select_names = new_select.map(el =>
// @ts-ignore
el?.$as ? el.$as[1] : el

@@ -64,3 +66,3 @@ )

const lower_subquery_entity = lower_subquery.$from ?? key
const edge_to_lower_table = get_direct_edge(
const edges_to_lower_table = get_direct_edges(
entity_name,

@@ -71,3 +73,3 @@ lower_subquery_entity,

return edge_to_lower_table.from_field
return edges_to_lower_table.map(el => el.from_field)
}

@@ -80,3 +82,3 @@

const higher_entity = subquery_path[subquery_path.length - 2]
const edge_to_higher_entity = get_direct_edge(
const edges_to_higher_entity = get_direct_edges(
entity_name,

@@ -86,3 +88,3 @@ higher_entity,

)
$select.push(edge_to_higher_entity.from_field)
$select.push(...edges_to_higher_entity.map(el => el.from_field))
}

@@ -89,0 +91,0 @@

@@ -113,9 +113,9 @@ import { orma_escape } from '../../helpers/escape'

// where clauses for
let subquery_locations: { value; path }[] = []
let where_clause_locations: { value; path }[] = []
query_for_each(query, (subquery, path) => {
let subquery_locations: { subquery; subquery_path }[] = []
let where_clause_locations: { where_clause; where_clause_path }[] = []
query_for_each(query, (subquery, subquery_path) => {
if (subquery.$where) {
deep_for_each(subquery.$where, (value, path) => {
if (value?.$from) {
where_clause_locations.push({ value, path })
deep_for_each(subquery.$where, (where_clause, where_clause_path) => {
if (where_clause?.$from) {
where_clause_locations.push({ where_clause, where_clause_path })
}

@@ -125,12 +125,12 @@ })

subquery_locations.push({ value: subquery, path })
subquery_locations.push({ subquery, subquery_path })
})
// generate where clauses for all the paths that we found
where_clause_locations.forEach(({ value, path }) => {
const entity_name = value.$from
where_clause_locations.forEach(({ where_clause, where_clause_path }) => {
const entity_name = where_clause.$from
apply_where_connected_to_subquery(
connection_edges,
query.$where_connected,
value,
where_clause,
entity_name,

@@ -141,9 +141,9 @@ undefined

subquery_locations.forEach(({ value, path }) => {
const entity_name = get_real_entity_name(path, value)
const higher_entity = get_real_higher_entity_name(path, value)
subquery_locations.forEach(({ subquery, subquery_path }) => {
const entity_name = get_real_entity_name(last(subquery_path), subquery)
const higher_entity = get_real_higher_entity_name(subquery_path, subquery)
apply_where_connected_to_subquery(
connection_edges,
query.$where_connected,
value,
subquery,
entity_name,

@@ -150,0 +150,0 @@ higher_entity

@@ -22,3 +22,6 @@ import { error_type } from '../helpers/error_handling'

// This function will default to the from clause
export const get_real_higher_entity_name = (path: (string | number)[], query) => {
export const get_real_higher_entity_name = (
path: (string | number)[],
query
) => {
if (path.length < 2) return null

@@ -33,4 +36,7 @@

// This function will default to the from clause
export const get_real_entity_name = (path: (string | number)[], query) => {
return deep_get([...path, '$from'], query, null) || last(path)
export const get_real_entity_name = (
last_path_item: string,
subquery: Record<string, any>
) => {
return subquery.$from ?? last_path_item
}

@@ -109,5 +115,16 @@

}
const entity = get_real_entity_name(path, query)
const higher_entity = get_real_entity_name(path.slice(0, -1), query)
const edge = get_direct_edge(higher_entity, entity, orma_schema)
const higher_entity_path = path.slice(0, -1)
const higher_entity = deep_get(higher_entity_path, query)
const entity = higher_entity[last(path)]
const entity_name = get_real_entity_name(last(path), entity)
const higher_entity_name = get_real_entity_name(
last(higher_entity_path),
higher_entity
)
const edge = get_direct_edge(
higher_entity_name,
entity_name,
orma_schema,
entity.$foreign_key
)
return [edge.from_field, edge.to_field]

@@ -114,0 +131,0 @@ })

@@ -1,293 +0,293 @@

import { expect } from 'chai'
import { describe, test } from 'mocha'
import { OrmaSchema } from '../introspector/introspector'
import { validator } from './validate_query_manual'
// import { expect } from 'chai'
// import { describe, test } from 'mocha'
// import { OrmaSchema } from '../introspector/introspector'
// import { validator } from './validate_query_manual'
const schema: OrmaSchema = {
grand_parent: {
id: {},
grand_parent_column: {},
},
parent: {
id: {},
parent_column: {},
grand_parent_id: {
references: {
grand_parent: {
id: {},
},
},
},
},
child: {
id: {},
child_column: {},
parent_id: {
references: {
parent: {
id: {},
},
},
},
},
}
// const schema: OrmaSchema = {
// grand_parent: {
// id: {},
// grand_parent_column: {},
// },
// parent: {
// id: {},
// parent_column: {},
// grand_parent_id: {
// references: {
// grand_parent: {
// id: {},
// },
// },
// },
// },
// child: {
// id: {},
// child_column: {},
// parent_id: {
// references: {
// parent: {
// id: {},
// },
// },
// },
// },
// }
/*
// /*
{
qty: {
$sum: 'quantity'
},
inventory_adjustments: {
variants: {
sku: true
}
},
inventory_adjustments: {
quantity: true
}
}
// {
// qty: {
// $sum: 'quantity'
// },
// inventory_adjustments: {
// variants: {
// sku: true
// }
// },
// inventory_adjustments: {
// quantity: true
// }
// }
*/
// */
describe('validate_query.ts', () => {
describe('boolean resolver', () => {
test('validates boolean resolver column names', () => {
const query = {
grand_parent: {
id: true,
grand_parent_column: true,
parent: {
parent_column: true,
child: {
id: true,
child_column_oops: true,
},
},
},
}
// describe('validate_query.ts', () => {
// describe('boolean resolver', () => {
// test('validates boolean resolver column names', () => {
// const query = {
// grand_parent: {
// id: true,
// grand_parent_column: true,
// parent: {
// parent_column: true,
// child: {
// id: true,
// child_column_oops: true,
// },
// },
// },
// }
const errors = validator(query, schema)
// const errors = validator(query, schema)
expect(errors.length).to.deep.equal(1)
expect(errors[0].path).to.deep.equal([
'grand_parent',
'parent',
'child',
'child_column_oops',
])
})
})
// expect(errors.length).to.deep.equal(1)
// expect(errors[0].path).to.deep.equal([
// 'grand_parent',
// 'parent',
// 'child',
// 'child_column_oops',
// ])
// })
// })
describe('virtual columns', () => {
test('validates $field virtual column', () => {
const query = {
parent: {
custom_name: { $field: 'parent_column' },
custom_name2: { $field: 'oops' },
},
}
// describe('virtual columns', () => {
// test('validates $field virtual column', () => {
// const query = {
// parent: {
// custom_name: { $field: 'parent_column' },
// custom_name2: { $field: 'oops' },
// },
// }
const errors = validator(query, schema)
// const errors = validator(query, schema)
expect(errors[0].path).to.deep.equal(['parent', 'custom_name2'])
expect(errors.length).to.deep.equal(1)
})
})
// expect(errors[0].path).to.deep.equal(['parent', 'custom_name2'])
// expect(errors.length).to.deep.equal(1)
// })
// })
describe('subqueries', () => {
test('validates the from clause', () => {
const data = {
parent: {
good: {
$from: 'child',
id: true,
},
bad: {
$from: 'oops',
id: true,
},
},
}
// describe('subqueries', () => {
// test('validates the from clause', () => {
// const data = {
// parent: {
// good: {
// $from: 'child',
// id: true,
// },
// bad: {
// $from: 'oops',
// id: true,
// },
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
const from_clause_errors = errors.filter(
err =>
JSON.stringify(err.path) ===
JSON.stringify(['parent', 'bad', 'id'])
)
expect(from_clause_errors.length).to.equal(1)
})
test('validates subquery connections', () => {
const data = {
grand_parent: {
john: {
$from: 'parent',
child: {
id: true,
grand_parent: {
id: true,
},
},
},
},
}
// const from_clause_errors = errors.filter(
// err =>
// JSON.stringify(err.path) ===
// JSON.stringify(['parent', 'bad', 'id'])
// )
// expect(from_clause_errors.length).to.equal(1)
// })
// test('validates subquery connections', () => {
// const data = {
// grand_parent: {
// john: {
// $from: 'parent',
// child: {
// id: true,
// grand_parent: {
// id: true,
// },
// },
// },
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(1)
expect(errors[0].path).to.deep.equal([
'grand_parent',
'john',
'child',
'grand_parent',
])
})
})
// expect(errors.length).to.equal(1)
// expect(errors[0].path).to.deep.equal([
// 'grand_parent',
// 'john',
// 'child',
// 'grand_parent',
// ])
// })
// })
describe.skip('clauses', () => {
test('Requires $eq to have valid field name', () => {
const data = {
parent: {
$where: {
$eq: ['my_id', 5],
},
my_id: {
$field: 'id',
},
},
}
// describe.skip('clauses', () => {
// test('Requires $eq to have valid field name', () => {
// const data = {
// parent: {
// $where: {
// $eq: ['my_id', 5],
// },
// my_id: {
// $field: 'id',
// },
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(1)
expect(errors[0].path).to.deep.equal(['parent', '$where'])
})
test('Lets $having have aliased fields', () => {
const data = {
parent: {
$having: {
$eq: ['my_id', 5],
},
my_id: {
$field: 'id',
},
},
}
// expect(errors.length).to.equal(1)
// expect(errors[0].path).to.deep.equal(['parent', '$where'])
// })
// test('Lets $having have aliased fields', () => {
// const data = {
// parent: {
// $having: {
// $eq: ['my_id', 5],
// },
// my_id: {
// $field: 'id',
// },
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(0)
})
test('Lets operators have functions', () => {
const data = {
parent: {
$where: {
$eq: ['name', { $field: 'id' }],
},
id: 'id',
},
}
// expect(errors.length).to.equal(0)
// })
// test('Lets operators have functions', () => {
// const data = {
// parent: {
// $where: {
// $eq: ['name', { $field: 'id' }],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(0)
})
test('Lets operators have functions', () => {
const data = {
parent: {
$where: {
$lte: ['name', { $field: 'id' }],
},
id: 'id',
},
}
// expect(errors.length).to.equal(0)
// })
// test('Lets operators have functions', () => {
// const data = {
// parent: {
// $where: {
// $lte: ['name', { $field: 'id' }],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(0)
})
test('Lets $and', () => {
const data = {
parent: {
$where: {
$and: [
{
$eq: ['id', '5'],
},
],
},
id: 'id',
},
}
// expect(errors.length).to.equal(0)
// })
// test('Lets $and', () => {
// const data = {
// parent: {
// $where: {
// $and: [
// {
// $eq: ['id', '5'],
// },
// ],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(0)
})
test('Changes scope for subqueries', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['parent_id'],
$from: 'child',
$where: {
$eq: ['name', 3], // invalid because 'name' is a field of parent, not child
},
},
],
},
id: 'id',
},
}
// expect(errors.length).to.equal(0)
// })
// test('Changes scope for subqueries', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['parent_id'],
// $from: 'child',
// $where: {
// $eq: ['name', 3], // invalid because 'name' is a field of parent, not child
// },
// },
// ],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(1)
})
test('Requires subqueries to have valid fields', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['invalid_field'],
$from: 'child',
},
],
},
id: 'id',
},
}
// expect(errors.length).to.equal(1)
// })
// test('Requires subqueries to have valid fields', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['invalid_field'],
// $from: 'child',
// },
// ],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(1)
})
test('Requires subqueries to have valid fields', () => {
const data = {
parent: {
$where: {
$in: [
'id',
{
$select: ['name'],
$from: 'fake_table',
},
],
},
id: 'id',
},
}
// expect(errors.length).to.equal(1)
// })
// test('Requires subqueries to have valid fields', () => {
// const data = {
// parent: {
// $where: {
// $in: [
// 'id',
// {
// $select: ['name'],
// $from: 'fake_table',
// },
// ],
// },
// id: 'id',
// },
// }
const errors = validator(data, schema)
// const errors = validator(data, schema)
expect(errors.length).to.equal(1)
})
})
})
// expect(errors.length).to.equal(1)
// })
// })
// })
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc