Socket
Socket
Sign inDemoInstall

orma

Package Overview
Dependencies
Maintainers
2
Versions
233
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.238 to 1.0.239

13

build/helpers/nester.d.ts
import { Path } from '../types';
export declare const nester: (data: NesterData, edges: NesterEdges) => Record<string, any>;
export declare const nester: (data: NesterData, edges: NesterEdges, nester_modifications: NesterModification[]) => Record<string, any>;
export type NesterData = [Path, Record<string, any>[] | undefined][];
export type NesterEdges = (null | string[])[];
export type NesterModification = {
additions: NesterAddition[];
deletions: NesterDeletion[];
};
export type NesterDeletion = {
field: string;
};
export type NesterAddition = {
field: string;
value: any;
};

79

build/helpers/nester.js

@@ -6,7 +6,7 @@ "use strict";

const helpers_1 = require("./helpers");
const nester = (data, edges) => {
const nester = (data, edges, nester_modifications) => {
// indexes are used to quickly get references to records deep in the result json. Using an index
// allows accessing these records directly, which is faster than using deep_get or deep_set.
const indexes = initialize_indexes(data, edges);
const result = get_results(data, edges, indexes);
const result = get_results(data, edges, indexes, nester_modifications);
return result;

@@ -39,6 +39,21 @@ };

};
const get_results = (data, edges, indexes) => {
/**
* Adds and deletes according to the nester modifications. Mutates input records
*/
const apply_nester_modifications = (nester_modification, record) => {
if (!nester_modification) {
return;
}
nester_modification.additions.forEach(({ field, value }) => {
record[field] = value;
});
nester_modification.deletions.forEach(({ field }) => {
delete record[field];
});
};
const get_results = (data, edges, indexes, nester_modifications) => {
let result = {};
data.forEach(([path_template, records], datum_index) => {
const index = indexes[datum_index];
const nester_modification = nester_modifications[datum_index];
const array_mode = (0, helpers_1.last)(path_template) === 0;

@@ -56,3 +71,6 @@ const edge = edges[datum_index];

// add this record to the index so we can nest other stuff on it
records === null || records === void 0 ? void 0 : records.forEach(record => add_to_index(index, record));
records === null || records === void 0 ? void 0 : records.forEach(record => {
add_to_index(index, record);
apply_nester_modifications(nester_modification, record);
});
return;

@@ -79,2 +97,3 @@ }

nester_set(higher_record, record_to_nest, set_field, array_mode);
apply_nester_modifications(nester_modification, record);
});

@@ -106,53 +125,1 @@ });

};
// // old nester code ------------------------
// /**
// * @param data Takes a list of nest path and nest data pairs ordered by acceptable insert order
// * @param edges Takes a list of edges corresponding to the points between the data
// */
// export const nester = (data, edges) => {
// // Requires that data is sorted so that later elements are equal or deeper in json tree
// let result = {}
// for (let i = 0; i < data.length; i++) {
// const [pth, list]: any = data[i]
// const array_mode = last(pth) === 0
// const path = array_mode ? drop_last(1, pth) : pth
// if (!edges[i]) deep_set(path, list, result)
// else {
// const left_list = extract_subpaths(drop_last(1, path), result)
// const { left, inner, right } = lir_join(
// left_list,
// result,
// list,
// el => deep_get([...el, edges[i][0]], result),
// (l, acc, r) => {
// r.forEach((right_adjacent, r_index) => {
// l.forEach((left_adjacent, l_index) => {
// // When the same item appears in multiple spots
// // we want to make a copy of it
// const item_to_nest =
// l_index === 0
// ? right_adjacent
// : clone(right_adjacent)
// if (array_mode) {
// push_path(
// [...left_adjacent, last(path)],
// item_to_nest,
// acc
// )
// } else {
// deep_set(
// [...left_adjacent, last(path)],
// item_to_nest,
// acc
// )
// }
// })
// })
// return acc
// },
// el => el[edges[i][1]]
// )
// }
// }
// return result
// }

@@ -44,3 +44,3 @@ "use strict";

};
let result = (0, nester_1.nester)(data, edges);
let result = (0, nester_1.nester)(data, edges, []);
(0, chai_1.expect)(result).to.deep.equal(goal);

@@ -83,3 +83,3 @@ });

};
let result = (0, nester_1.nester)(data, edges);
let result = (0, nester_1.nester)(data, edges, []);
(0, chai_1.expect)(result).to.deep.equal(goal);

@@ -139,3 +139,3 @@ });

};
let result = (0, nester_1.nester)(data, edges);
let result = (0, nester_1.nester)(data, edges, []);
(0, chai_1.expect)(result).to.deep.equal(goal);

@@ -166,3 +166,3 @@ });

};
let result = (0, nester_1.nester)(data, edges);
let result = (0, nester_1.nester)(data, edges, []);
(0, chai_1.expect)(result).to.deep.equal(goal);

@@ -204,3 +204,3 @@ });

};
let result = (0, nester_1.nester)(data, edges);
let result = (0, nester_1.nester)(data, edges, []);
(0, chai_1.expect)(result).to.deep.equal(goal);

@@ -272,3 +272,3 @@ });

// for (let i = 0; i < 10000; i++) {
result = (0, nester_1.nester)(data, edges);
result = (0, nester_1.nester)(data, edges, []);
// }

@@ -295,3 +295,3 @@ console.timeEnd('t');

const edges = [null, ['variant_id', 'id'], ['product_id', 'id']];
const result = (0, nester_1.nester)(data, edges);
const result = (0, nester_1.nester)(data, edges, []);
const len = result.order_items[0].variants[0].products.length;

@@ -298,0 +298,0 @@ (0, chai_1.expect)(len).to.equal(1);

@@ -1,2 +0,2 @@

import { GlobalTestMutation, GlobalTestSchema } from '../test_data/global_test_schema';
import { GlobalTestAliases, GlobalTestMutation, GlobalTestSchema } from '../test_data/global_test_schema';
import { OrmaQueryResult } from '../types/query/query_result_types';

@@ -6,2 +6,2 @@ import { WhereConnected } from '../types/query/query_types';

export declare const test_mutate: (mutation: GlobalTestMutation, where_connecteds?: WhereConnected<GlobalTestSchema>) => Promise<void>;
export declare const test_query: <T extends Record<string, any>>(query: T) => Promise<OrmaQueryResult<GlobalTestSchema, T, never>>;
export declare const test_query: <T extends Record<string, any>>(query: T) => Promise<OrmaQueryResult<GlobalTestSchema, GlobalTestAliases, T>>;

@@ -82,2 +82,3 @@ "use strict";

views: true,
user_id: true,
$where: {

@@ -195,3 +196,2 @@ $or: [

last_name: 'Anderson',
id: 1,
likes: [

@@ -202,3 +202,3 @@ {

post_id: 1,
posts: [{ title: 'First post!', id: 1 }],
posts: [{ title: 'First post!' }],
},

@@ -507,2 +507,51 @@ ],

});
(0, mocha_1.test)('handles selecting escaped object', async () => {
const res = await (0, integration_setup_test_1.test_query)({
posts: {
id: {
$escape: { $guid: 'a' },
},
my_title: {
$escape: ['hi'],
},
total_views: {
$escape: 1,
},
users: {
id: true,
},
$limit: 1,
},
});
(0, chai_1.expect)(res).to.deep.equal({
posts: [
{
id: { $guid: 'a' },
my_title: ['hi'],
total_views: 1,
users: [
{
id: 1,
},
],
},
],
});
});
(0, mocha_1.test)('removes intermediate foriegn keys', async () => {
var _a, _b, _c;
const res = await (0, integration_setup_test_1.test_query)({
users: {
posts: {
title: true,
$limit: 1,
},
$limit: 1,
},
});
//@ts-ignore
(0, chai_1.expect)((_a = res.users) === null || _a === void 0 ? void 0 : _a[0].id).to.equal(undefined);
//@ts-ignore
(0, chai_1.expect)((_c = (_b = res.users) === null || _b === void 0 ? void 0 : _b[0].posts) === null || _c === void 0 ? void 0 : _c[0].user_id).to.equal(undefined);
});
mocha_1.test.skip('allows $identifying_fields override');

@@ -509,0 +558,0 @@ mocha_1.test.skip('handles manual guid + raw value linking');

@@ -0,3 +1,4 @@

import { NesterAddition } from '../../helpers/nester';
import { OrmaSchema } from '../../types/schema/schema_types';
export declare const apply_escape_macro: (query: any, orma_schema: OrmaSchema) => void;
export declare const apply_escape_macro_to_query_part: (orma_schema: OrmaSchema, root_entity: string | undefined, query: any) => void;
export declare const apply_escape_macro: (query: any, orma_schema: OrmaSchema) => NesterAddition[];
export declare const apply_escape_macro_to_query_part: (orma_schema: OrmaSchema, root_entity: string | undefined, query: any) => NesterAddition[];

@@ -8,3 +8,3 @@ "use strict";

const apply_escape_macro = (query, orma_schema) => {
(0, exports.apply_escape_macro_to_query_part)(orma_schema, undefined, query);
return (0, exports.apply_escape_macro_to_query_part)(orma_schema, undefined, query);
};

@@ -15,4 +15,35 @@ exports.apply_escape_macro = apply_escape_macro;

let raw_paths = [];
let nester_additions = [];
(0, helpers_1.deep_for_each)(query, (value, path) => {
if ((value === null || value === void 0 ? void 0 : value.$escape) !== undefined) {
// We can select an escaped value, to simply return that value. For strings and numbers,
// we can send something like SELECT 1 AS my_column to our database and have it return
// 1 for every row. This also lets us do computed values or having clauses using my_column.
// however this wont work for ararys and objects, so we need to remove these from the query
// - they will be added back to the query results later.
if ((0, helpers_1.last)(path) === '$select') {
const select = value;
const delete_indices = select
.flatMap((select_el, i) => {
var _a, _b;
const escape_value = (_b = (_a = select_el === null || select_el === void 0 ? void 0 : select_el.$as) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.$escape;
const is_object_or_array = Array.isArray(escape_value) ||
(0, helpers_1.is_simple_object)(escape_value);
return is_object_or_array ? [i] : [];
})
// deletions need to start from the end to not mess up the indices
.reverse();
delete_indices.forEach(i => {
// make sure the escaped select is added back in later by the nester
nester_additions.push({
value: select[i].$as[0].$escape,
field: select[i].$as[1],
});
select.splice(i, 1);
});
}
// handle regular escapes
const escape_value = value === null || value === void 0 ? void 0 : value.$escape;
const is_object_or_array = Array.isArray(escape_value) || (0, helpers_1.is_simple_object)(escape_value);
const is_deleted = path.includes('select') && is_object_or_array;
if (escape_value !== undefined && !is_deleted) {
raw_paths.push([path, value]);

@@ -34,3 +65,4 @@ }

});
return nester_additions;
};
exports.apply_escape_macro_to_query_part = apply_escape_macro_to_query_part;

@@ -0,1 +1,2 @@

import { NesterDeletion } from '../../helpers/nester';
import { OrmaSchema } from '../../types/schema/schema_types';

@@ -5,5 +6,8 @@ /**

*/
export declare const apply_select_macro: (query: any, orma_schema: OrmaSchema) => void;
export declare const get_select: (subquery: any, subquery_path: string[], query: any, orma_schema: OrmaSchema) => (string | {
export declare const apply_select_macro: (query: any, orma_schema: OrmaSchema) => {
[stringified_path: string]: NesterDeletion[];
};
export declare const get_converted_select: (subquery: any) => (string | {
$as: any[];
})[];
export declare const get_new_select: (subquery: any, subquery_path: string[], query: any, orma_schema: OrmaSchema) => string[];
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.get_select = exports.apply_select_macro = void 0;
exports.get_new_select = exports.get_converted_select = exports.apply_select_macro = void 0;
const helpers_1 = require("../../helpers/helpers");

@@ -12,7 +12,22 @@ const schema_helpers_1 = require("../../helpers/schema_helpers");

const apply_select_macro = (query, orma_schema) => {
let nester_deletions = {};
(0, query_helpers_1.query_for_each)(query, (value, path) => {
var _a, _b;
const new_select = (0, exports.get_select)(value, path, query, orma_schema);
const existing_select = (_a = value.$select) !== null && _a !== void 0 ? _a : [];
const $select = [...existing_select, ...new_select];
const converted_select = (0, exports.get_converted_select)(value);
const new_select = (0, exports.get_new_select)(value, path, query, orma_schema);
// any selects we added should be removed by the nester so the user doesnt get them
const selects_to_delete_in_nester = new_select.filter(new_el => !existing_select.includes(new_el) &&
!converted_select.includes(new_el));
nester_deletions[JSON.stringify(path)] =
selects_to_delete_in_nester.map(field => ({
field,
}));
const $select = [
...new Set([
...existing_select,
...converted_select,
...new_select,
]),
];
const $from = (_b = value.$from) !== null && _b !== void 0 ? _b : (0, helpers_1.last)(path);

@@ -25,15 +40,14 @@ if ($select) {

}
const new_select_names = new_select.map(el =>
const converted_select_fields = converted_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) {
for (const select of converted_select_fields) {
delete value[select];
}
});
return nester_deletions;
};
exports.apply_select_macro = apply_select_macro;
const get_select = (subquery, subquery_path, query, orma_schema) => {
const entity_name = (0, query_1.get_real_entity_name)((0, helpers_1.last)(subquery_path), subquery);
const get_converted_select = subquery => {
const $select = Object.keys(subquery).flatMap(key => {
var _a;
if ((0, schema_helpers_1.is_reserved_keyword)(key)) {

@@ -50,2 +64,14 @@ return [];

}
return []; // subqueries are not handled here
});
return $select;
};
exports.get_converted_select = get_converted_select;
const get_new_select = (subquery, subquery_path, query, orma_schema) => {
const entity_name = (0, query_1.get_real_entity_name)((0, helpers_1.last)(subquery_path), subquery);
const $select = Object.keys(subquery).flatMap(key => {
var _a;
if ((0, schema_helpers_1.is_reserved_keyword)(key)) {
return [];
}
if ((0, helpers_1.is_simple_object)(subquery[key]) && (0, query_helpers_1.is_subquery)(subquery[key])) {

@@ -57,3 +83,3 @@ const lower_subquery = subquery[key];

}
return []; // subqueries are not handled here
return [];
});

@@ -65,4 +91,4 @@ if (subquery_path.length > 1) {

}
return [...new Set($select)]; // unique values
return [...new Set($select)];
};
exports.get_select = get_select;
exports.get_new_select = get_new_select;

@@ -0,1 +1,2 @@

import { NesterModification } from '../helpers/nester';
import { MysqlFunction } from '../mutate/mutate';

@@ -9,5 +10,5 @@ import { OrmaQueryResult } from '../types/query/query_result_types';

export declare const get_real_entity_name: (last_path_item: string, subquery: Record<string, any>) => string;
export declare const orma_nester: (results: [string[], Record<string, unknown>[]][], query: any, orma_schema: OrmaSchema) => Record<string, any>;
export declare const orma_query: <Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Query extends OrmaQuery<Schema, Aliases>>(raw_query: Query, orma_schema_input: Schema, query_function: MysqlFunction, connection_edges?: ConnectionEdges) => Promise<OrmaQueryResult<Schema, Query, never>>;
export declare const orma_nester: (orma_schema: OrmaSchema, query: any, nester_modifications: NesterModification[], results: [string[], Record<string, unknown>[]][]) => Record<string, any>;
export declare const orma_query: <Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Query extends OrmaQuery<Schema, Aliases>>(raw_query: Query, orma_schema_input: Schema, query_function: MysqlFunction, connection_edges?: ConnectionEdges) => Promise<OrmaQueryResult<Schema, Aliases, Query>>;
export declare const as_orma_schema: <Schema extends OrmaSchema>(schema: Schema) => Schema;
export declare const as_orma_query: <Schema extends OrmaSchema, T extends DeepReadonly<OrmaQuery<Schema, {}>>>(schema: Schema, query: T) => T;

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

exports.get_real_entity_name = get_real_entity_name;
const orma_nester = (results, query, orma_schema) => {
const orma_nester = (orma_schema, query, nester_modifications, results) => {
// get data in the right format for the nester

@@ -52,3 +52,3 @@ const edges = results.map(result => {

});
return (0, nester_1.nester)(data, edges);
return (0, nester_1.nester)(data, edges, nester_modifications);
};

@@ -62,6 +62,7 @@ exports.orma_nester = orma_nester;

(0, any_path_macro_1.apply_any_path_macro)(query, orma_schema);
(0, select_macro_1.apply_select_macro)(query, orma_schema);
const nester_deletions_by_path = (0, select_macro_1.apply_select_macro)(query, orma_schema);
(0, where_connected_macro_1.apply_where_connected_macro)(orma_schema, query, connection_edges);
const query_plan = (0, query_plan_1.get_query_plan)(query);
let results = [];
let nester_modifications = [];
// Sequential for query plan

@@ -74,3 +75,3 @@ for (const paths of query_plan) {

});
const subqueries = paths_to_query.map(path => {
const subquery_data = paths_to_query.map(path => {
// this pretty inefficient, but nesting macro gets confused when it sees the where clauses

@@ -84,14 +85,21 @@ // that it put in the query and thinks that they were there before mutation planning.

const subquery = (0, helpers_1.deep_get)(path, tier_query);
(0, escaping_macros_1.apply_escape_macro)(subquery, orma_schema);
return subquery;
const nester_additions = (0, escaping_macros_1.apply_escape_macro)(subquery, orma_schema);
const nester_deletions = nester_deletions_by_path[JSON.stringify(path)];
return { subquery, nester_additions, nester_deletions };
});
// Promise.all for each element in query plan.
// dont call query is there are no sql strings to run
const output = subqueries.length > 0
? await query_function(subqueries.map(subquery => (0, mutation_statements_1.generate_statement)(subquery, [], [])))
const output = subquery_data.length > 0
? await query_function(subquery_data.map(({ subquery }) => (0, mutation_statements_1.generate_statement)(subquery, [], [])))
: [];
// Combine outputs
subqueries.forEach((_, i) => results.push([paths_to_query[i], output[i]]));
subquery_data.forEach((_, i) => {
results.push([paths_to_query[i], output[i]]);
nester_modifications.push({
additions: subquery_data[i].nester_additions,
deletions: subquery_data[i].nester_deletions,
});
});
}
const output = (0, exports.orma_nester)(results, query, orma_schema);
const output = (0, exports.orma_nester)(orma_schema, query, nester_modifications, results);
return output;

@@ -98,0 +106,0 @@ };

@@ -10,10 +10,10 @@ "use strict";

(0, mocha_1.test)('nests restults', () => {
const result = (0, query_1.orma_nester)([
[['posts'], [{ user_id: 1 }]],
[['posts', 'users'], [{ id: 1 }]],
], {
const result = (0, query_1.orma_nester)(global_test_schema_1.global_test_schema, {
posts: {
users: {},
},
}, global_test_schema_1.global_test_schema);
}, [], [
[['posts'], [{ user_id: 1 }]],
[['posts', 'users'], [{ id: 1 }]],
]);
(0, chai_1.expect)(result).to.deep.equal({

@@ -20,0 +20,0 @@ posts: [

import { OrmaSchema } from '../schema/schema_types';
import { GetAllEntities, GetFields, GetFieldType, Keyword } from '../schema/schema_helper_types';
import { GetAliases, OrmaQueryAliases } from './query_types';
export type OrmaQueryResult<Schema extends OrmaSchema, Query extends object, Entity extends GetAllEntities<Schema> = never> = Omit<{
-readonly [Key in keyof Query]: Query[Key] extends {
import { DeepMutable, GetAllEntities, GetFields, GetFieldType } from '../schema/schema_helper_types';
import { GetAliases, OrmaQueryAliases, GetRootAliases } from './query_types';
export type OrmaQueryResult<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Query extends object> = {
-readonly [Key in keyof Query & (GetAllEntities<Schema> | GetRootAliases<Schema, Aliases>)]?: Query[Key] extends {
$from: GetAllEntities<Schema>;
} ? OrmaQueryResult<Schema, Query[Key], Query[Key]['$from']>[] | undefined : Key extends GetAllEntities<Schema> ? Query[Key] extends object ? Exclude<keyof Query[Key], Keyword> extends never ? never : OrmaQueryResult<Schema, Query[Key], Key>[] | undefined : never : GetSchemaTypeForField<Schema, Entity, Key, Query[Key]>;
}, Keyword>;
type GetSchemaTypeForField<Schema extends OrmaSchema, Entity extends GetAllEntities<Schema>, Key, Value> = Value extends true ? Key extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Key> : any : Value extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Value> : any;
} ? OrmaRecord<Schema, Aliases, Query[Key]['$from'], Query[Key]>[] : Query[Key] extends object ? Key extends GetAllEntities<Schema> ? OrmaRecord<Schema, Aliases, Key, Query[Key]>[] : never : never;
};
export type OrmaRecord<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Entity extends GetAllEntities<Schema>, Subquery extends object> = {
-readonly [Key in keyof Subquery & (GetAllEntities<Schema> | GetFields<Schema, Entity> | GetAliases<Schema, Aliases, Entity>)]: Subquery[Key] extends {
$from: GetAllEntities<Schema>;
} ? OrmaRecord<Schema, Aliases, Subquery[Key]['$from'], Subquery[Key]>[] | undefined : Subquery[Key] extends true ? Key extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Key> : "Unrecognized field name for value 'true'" : Subquery[Key] extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Subquery[Key]> : Key extends GetAllEntities<Schema> ? Subquery[Key] extends object ? OrmaRecord<Schema, Aliases, Key, Subquery[Key]>[] | undefined : any : any;
} ? OrmaRecord<Schema, Aliases, Subquery[Key]['$from'], Subquery[Key]>[] | undefined : Subquery[Key] extends {
$escape: any;
} ? DeepMutable<Subquery[Key]['$escape']> : Subquery[Key] extends true ? Key extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Key> : "Unrecognized field name for value 'true'" : Subquery[Key] extends GetFields<Schema, Entity> ? GetFieldType<Schema, Entity, Subquery[Key]> : Key extends GetAllEntities<Schema> ? Subquery[Key] extends object ? OrmaRecord<Schema, Aliases, Key, Subquery[Key]>[] | undefined : any : any;
};
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*
Subquery[Key] extends { $escape }
? Subquery[Key]['$escape']
*/
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const test = () => {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
const query_response = (query) => '';

@@ -140,2 +140,38 @@ {

}
{
// handles simple excape
const q = {
posts: {
title: true,
my_title: {
$escape: 123,
},
},
};
const result = query_response(q);
(_1 = result.posts) === null || _1 === void 0 ? void 0 : _1.map(post => {
const test = true;
});
}
{
// handles object escape
const q = {
posts: {
title: true,
my_title: {
$escape: [123],
},
id: {
$escape: {
$guid: 'a',
},
},
},
};
const result = query_response(q);
(_2 = result.posts) === null || _2 === void 0 ? void 0 : _2.map(post => {
const test = true;
const test2 = true;
});
}
};

@@ -55,3 +55,5 @@ import { OrmaSchema } from '../schema/schema_types';

type QueryAliasedField<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Entity extends GetAllEntities<Schema>> = Expression<Schema, Aliases, Entity>;
export type Expression<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Entity extends GetAllEntities<Schema>> = ExpressionFunction<Schema, Aliases, Entity, keyof typeof sql_function_definitions> | GetFields<Schema, Entity> | GetAliases<Schema, Aliases, Entity>;
export type Expression<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Entity extends GetAllEntities<Schema>> = ExpressionFunction<Schema, Aliases, Entity, keyof typeof sql_function_definitions> | GetFields<Schema, Entity> | GetAliases<Schema, Aliases, Entity> | {
$escape: any;
};
type ExpressionFunction<Schema extends OrmaSchema, Aliases extends OrmaQueryAliases<Schema>, Entity extends GetAllEntities<Schema>, FunctionNames extends string> = FunctionNames extends string ? {

@@ -58,0 +60,0 @@ [Key in FunctionNames]: Expression<Schema, Aliases, Entity>;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const query_1 = require("../../query/query");
const global_test_schema_1 = require("../../test_data/global_test_schema");
{

@@ -221,10 +219,10 @@ // allows fields and aliases

{
(0, query_1.as_orma_query)(global_test_schema_1.global_test_schema, {
const t = {
posts: {
id: true,
_asdas: {
$from: 'users',
}
my_title: {
$escape: 123,
},
},
});
};
}
{
"name": "orma",
"version": "1.0.238",
"version": "1.0.239",
"description": "A declarative relational syncronous orm",

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

@@ -5,7 +5,11 @@ import { get_higher_path } from '../mutate/helpers/mutate_helpers'

export const nester = (data: NesterData, edges: NesterEdges) => {
export const nester = (
data: NesterData,
edges: NesterEdges,
nester_modifications: NesterModification[]
) => {
// indexes are used to quickly get references to records deep in the result json. Using an index
// allows accessing these records directly, which is faster than using deep_get or deep_set.
const indexes = initialize_indexes(data, edges)
const result = get_results(data, edges, indexes)
const result = get_results(data, edges, indexes, nester_modifications)
return result

@@ -45,6 +49,26 @@ }

/**
* Adds and deletes according to the nester modifications. Mutates input records
*/
const apply_nester_modifications = (
nester_modification: NesterModification | undefined,
record: Record<string, any>
) => {
if (!nester_modification) {
return
}
nester_modification.additions.forEach(({ field, value }) => {
record[field] = value
})
nester_modification.deletions.forEach(({ field }) => {
delete record[field]
})
}
const get_results = (
data: NesterData,
edges: NesterEdges,
indexes: IndexesByField[]
indexes: IndexesByField[],
nester_modifications: NesterModification[]
) => {

@@ -54,2 +78,3 @@ let result: Record<string, any> = {}

const index = indexes[datum_index]
const nester_modification = nester_modifications[datum_index]

@@ -72,3 +97,6 @@ const array_mode = last(path_template) === 0

// add this record to the index so we can nest other stuff on it
records?.forEach(record => add_to_index(index, record))
records?.forEach(record => {
add_to_index(index, record)
apply_nester_modifications(nester_modification, record)
})

@@ -99,2 +127,3 @@ return

nester_set(higher_record, record_to_nest, set_field, array_mode)
apply_nester_modifications(nester_modification, record)
})

@@ -137,56 +166,7 @@ })

export type NesterEdges = (null | string[])[]
// // old nester code ------------------------
// /**
// * @param data Takes a list of nest path and nest data pairs ordered by acceptable insert order
// * @param edges Takes a list of edges corresponding to the points between the data
// */
// export const nester = (data, edges) => {
// // Requires that data is sorted so that later elements are equal or deeper in json tree
// let result = {}
// for (let i = 0; i < data.length; i++) {
// const [pth, list]: any = data[i]
// const array_mode = last(pth) === 0
// const path = array_mode ? drop_last(1, pth) : pth
// if (!edges[i]) deep_set(path, list, result)
// else {
// const left_list = extract_subpaths(drop_last(1, path), result)
// const { left, inner, right } = lir_join(
// left_list,
// result,
// list,
// el => deep_get([...el, edges[i][0]], result),
// (l, acc, r) => {
// r.forEach((right_adjacent, r_index) => {
// l.forEach((left_adjacent, l_index) => {
// // When the same item appears in multiple spots
// // we want to make a copy of it
// const item_to_nest =
// l_index === 0
// ? right_adjacent
// : clone(right_adjacent)
// if (array_mode) {
// push_path(
// [...left_adjacent, last(path)],
// item_to_nest,
// acc
// )
// } else {
// deep_set(
// [...left_adjacent, last(path)],
// item_to_nest,
// acc
// )
// }
// })
// })
// return acc
// },
// el => el[edges[i][1]]
// )
// }
// }
// return result
// }
export type NesterModification = {
additions: NesterAddition[]
deletions: NesterDeletion[]
}
export type NesterDeletion = { field: string }
export type NesterAddition = { field: string; value: any }

@@ -46,3 +46,3 @@ import { expect } from 'chai'

let result = nester(data, edges)
let result = nester(data, edges, [])

@@ -89,3 +89,3 @@ expect(result).to.deep.equal(goal)

let result = nester(data, edges)
let result = nester(data, edges, [])

@@ -149,3 +149,3 @@ expect(result).to.deep.equal(goal)

let result = nester(data, edges)
let result = nester(data, edges, [])

@@ -180,3 +180,3 @@ expect(result).to.deep.equal(goal)

let result = nester(data, edges)
let result = nester(data, edges, [])

@@ -222,3 +222,3 @@ expect(result).to.deep.equal(goal)

let result = nester(data, edges)
let result = nester(data, edges, [])

@@ -301,3 +301,3 @@ expect(result).to.deep.equal(goal)

// for (let i = 0; i < 10000; i++) {
result = nester(data, edges)
result = nester(data, edges, [])
// }

@@ -328,3 +328,3 @@ console.timeEnd('t')

const result: any = nester(data, edges)
const result: any = nester(data, edges, [])
const len = result.order_items[0].variants[0].products.length

@@ -331,0 +331,0 @@ expect(len).to.equal(1)

@@ -17,2 +17,3 @@ import { before, beforeEach } from 'mocha'

import {
GlobalTestAliases,
GlobalTestMutation,

@@ -108,3 +109,3 @@ GlobalTestSchema,

query: T
): Promise<OrmaQueryResult<GlobalTestSchema, T>> => {
): Promise<OrmaQueryResult<GlobalTestSchema, GlobalTestAliases, T>> => {
validate_errors([validate_query(query, global_test_schema)])

@@ -111,0 +112,0 @@ const res = await (orma_query as any)(

@@ -105,2 +105,3 @@ import { expect } from 'chai'

views: true,
user_id: true,
$where: {

@@ -227,3 +228,2 @@ $or: [

last_name: 'Anderson',
id: 1,
likes: [

@@ -234,3 +234,3 @@ {

post_id: 1,
posts: [{ title: 'First post!', id: 1 }],
posts: [{ title: 'First post!' }],
},

@@ -554,2 +554,52 @@ ],

})
test('handles selecting escaped object', async () => {
const res = await test_query({
posts: {
id: {
$escape: { $guid: 'a' },
},
my_title: {
$escape: ['hi'],
},
total_views: {
$escape: 1,
},
users: {
id: true,
},
$limit: 1,
},
} as const satisfies GlobalTestQuery)
expect(res).to.deep.equal({
posts: [
{
id: { $guid: 'a' },
my_title: ['hi'],
total_views: 1,
users: [
{
id: 1,
},
],
},
],
})
})
test('removes intermediate foriegn keys', async () => {
const res = await test_query({
users: {
posts: {
title: true,
$limit: 1,
},
$limit: 1,
},
} as const satisfies GlobalTestQuery)
//@ts-ignore
expect(res.users?.[0].id).to.equal(undefined)
//@ts-ignore
expect(res.users?.[0].posts?.[0].user_id).to.equal(undefined)
})
test.skip('allows $identifying_fields override')

@@ -556,0 +606,0 @@ test.skip('handles manual guid + raw value linking')

import { orma_escape } from '../../helpers/escape'
import { deep_for_each, deep_set, last } from '../../helpers/helpers'
import {
deep_for_each,
deep_set,
is_simple_object,
last,
} from '../../helpers/helpers'
import { NesterAddition } from '../../helpers/nester'
import { OrmaSchema } from '../../types/schema/schema_types'
import { get_real_entity_name } from '../query'
import { get_any_path_context_entity } from './any_path_macro'
export const apply_escape_macro = (query, orma_schema: OrmaSchema) => {
apply_escape_macro_to_query_part(orma_schema, undefined, query)
return apply_escape_macro_to_query_part(orma_schema, undefined, query)
}

@@ -18,5 +23,39 @@

let raw_paths: any[] = []
let nester_additions: NesterAddition[] = []
deep_for_each(query, (value, path) => {
if (value?.$escape !== undefined) {
// We can select an escaped value, to simply return that value. For strings and numbers,
// we can send something like SELECT 1 AS my_column to our database and have it return
// 1 for every row. This also lets us do computed values or having clauses using my_column.
// however this wont work for ararys and objects, so we need to remove these from the query
// - they will be added back to the query results later.
if (last(path) === '$select') {
const select = value as any[]
const delete_indices = select
.flatMap((select_el, i) => {
const escape_value = select_el?.$as?.[0]?.$escape
const is_object_or_array =
Array.isArray(escape_value) ||
is_simple_object(escape_value)
return is_object_or_array ? [i] : []
})
// deletions need to start from the end to not mess up the indices
.reverse()
delete_indices.forEach(i => {
// make sure the escaped select is added back in later by the nester
nester_additions.push({
value: select[i].$as[0].$escape,
field: select[i].$as[1],
})
select.splice(i, 1)
})
}
// handle regular escapes
const escape_value = value?.$escape
const is_object_or_array =
Array.isArray(escape_value) || is_simple_object(escape_value)
const is_deleted = path.includes('select') && is_object_or_array
if (escape_value !== undefined && !is_deleted) {
raw_paths.push([path, value])

@@ -48,2 +87,4 @@ }

})
return nester_additions
}

@@ -1,5 +0,4 @@

import { escapeId } from 'sqlstring'
import { is_simple_object, last } from '../../helpers/helpers'
import { NesterDeletion } from '../../helpers/nester'
import {
get_direct_edge,
get_direct_edges,

@@ -16,6 +15,26 @@ is_reserved_keyword,

export const apply_select_macro = (query, orma_schema: OrmaSchema) => {
let nester_deletions: { [stringified_path: string]: NesterDeletion[] } = {}
query_for_each(query, (value, path) => {
const new_select = get_select(value, path, query, orma_schema)
const existing_select = value.$select ?? []
const $select = [...existing_select, ...new_select]
const converted_select = get_converted_select(value)
const new_select = get_new_select(value, path, query, orma_schema)
// any selects we added should be removed by the nester so the user doesnt get them
const selects_to_delete_in_nester = new_select.filter(
new_el =>
!existing_select.includes(new_el) &&
!converted_select.includes(new_el)
)
nester_deletions[JSON.stringify(path)] =
selects_to_delete_in_nester.map(field => ({
field,
}))
const $select = [
...new Set([
...existing_select,
...converted_select,
...new_select,
]),
]
const $from = value.$from ?? last(path)

@@ -31,20 +50,15 @@

const new_select_names = new_select.map(el =>
const converted_select_fields = converted_select.map(el =>
// @ts-ignore
el?.$as ? el.$as[1] : el
)
for (const select of new_select_names) {
for (const select of converted_select_fields) {
delete value[select]
}
})
return nester_deletions
}
export const get_select = (
subquery,
subquery_path: string[],
query,
orma_schema: OrmaSchema
) => {
const entity_name = get_real_entity_name(last(subquery_path), subquery)
export const get_converted_select = subquery => {
const $select = Object.keys(subquery).flatMap(key => {

@@ -66,2 +80,21 @@ if (is_reserved_keyword(key)) {

return [] // subqueries are not handled here
})
return $select
}
export const get_new_select = (
subquery,
subquery_path: string[],
query,
orma_schema: OrmaSchema
) => {
const entity_name = get_real_entity_name(last(subquery_path), subquery)
const $select = Object.keys(subquery).flatMap(key => {
if (is_reserved_keyword(key)) {
return []
}
if (is_simple_object(subquery[key]) && is_subquery(subquery[key])) {

@@ -79,3 +112,3 @@ const lower_subquery = subquery[key]

return [] // subqueries are not handled here
return []
})

@@ -93,3 +126,3 @@

return [...new Set($select)] // unique values
return [...new Set($select)]
}

@@ -10,6 +10,3 @@ import { expect } from 'chai'

const result = orma_nester(
[
[['posts'], [{ user_id: 1 }]],
[['posts', 'users'], [{ id: 1 }]],
],
global_test_schema,
{

@@ -20,3 +17,7 @@ posts: {

},
global_test_schema
[],
[
[['posts'], [{ user_id: 1 }]],
[['posts', 'users'], [{ id: 1 }]],
]
)

@@ -23,0 +24,0 @@

import { clone, deep_get, drop_last, last } from '../helpers/helpers'
import { nester, NesterData } from '../helpers/nester'
import { nester, NesterData, NesterModification } from '../helpers/nester'
import { get_direct_edge } from '../helpers/schema_helpers'

@@ -45,5 +45,6 @@ import { MysqlFunction } from '../mutate/mutate'

export const orma_nester = (
orma_schema: OrmaSchema,
query,
nester_modifications: NesterModification[],
results: [string[], Record<string, unknown>[]][],
query,
orma_schema: OrmaSchema
) => {

@@ -82,3 +83,3 @@ // get data in the right format for the nester

return nester(data, edges)
return nester(data, edges, nester_modifications)
}

@@ -96,3 +97,3 @@

connection_edges: ConnectionEdges = {}
): Promise<OrmaQueryResult<Schema, Query>> => {
): Promise<OrmaQueryResult<Schema, Aliases, Query>> => {
const query = clone(raw_query) // clone query so we can apply macros without mutating the actual input query

@@ -103,3 +104,3 @@ const orma_schema = orma_schema_input as any // this is just because the codebase isnt properly typed

apply_any_path_macro(query, orma_schema)
apply_select_macro(query, orma_schema)
const nester_deletions_by_path = apply_select_macro(query, orma_schema)
apply_where_connected_macro(orma_schema, query, connection_edges)

@@ -109,2 +110,3 @@

let results: any[] = []
let nester_modifications: NesterModification[] = []

@@ -122,3 +124,3 @@ // Sequential for query plan

})
const subqueries = paths_to_query.map(path => {
const subquery_data = paths_to_query.map(path => {
// this pretty inefficient, but nesting macro gets confused when it sees the where clauses

@@ -134,5 +136,7 @@ // that it put in the query and thinks that they were there before mutation planning.

const subquery = deep_get(path, tier_query)
apply_escape_macro(subquery, orma_schema)
const nester_additions = apply_escape_macro(subquery, orma_schema)
const nester_deletions =
nester_deletions_by_path[JSON.stringify(path)]
return subquery
return { subquery, nester_additions, nester_deletions }
})

@@ -143,5 +147,5 @@

const output =
subqueries.length > 0
subquery_data.length > 0
? await query_function(
subqueries.map(subquery =>
subquery_data.map(({ subquery }) =>
generate_statement(subquery, [], [])

@@ -153,8 +157,17 @@ )

// Combine outputs
subqueries.forEach((_, i) =>
subquery_data.forEach((_, i) => {
results.push([paths_to_query[i], output[i]])
)
nester_modifications.push({
additions: subquery_data[i].nester_additions,
deletions: subquery_data[i].nester_deletions,
})
})
}
const output = orma_nester(results, query, orma_schema)
const output = orma_nester(
orma_schema,
query,
nester_modifications,
results
)

@@ -161,0 +174,0 @@ return output as any

@@ -13,3 +13,3 @@ import {

query: Query
): OrmaQueryResult<GlobalTestSchema, Query> => '' as any
): OrmaQueryResult<GlobalTestSchema, GlobalTestAliases, Query> => '' as any

@@ -174,2 +174,40 @@ {

}
{
// handles simple excape
const q = {
posts: {
title: true,
my_title: {
$escape: 123,
},
},
} as const satisfies GlobalTestQuery
const result = query_response(q)
result.posts?.map(post => {
const test: IsEqual<typeof post.my_title, 123> = true
})
}
{
// handles object escape
const q = {
posts: {
title: true,
my_title: {
$escape: [123],
},
id: {
$escape: {
$guid: 'a' as 'a' | 'b',
},
},
},
} as const satisfies GlobalTestQuery
const result = query_response(q)
result.posts?.map(post => {
const test: IsEqual<typeof post.my_title, [123]> = true
const test2: IsEqual<typeof post.id, { $guid: 'a' | 'b' }> = true
})
}
}
import { OrmaSchema } from '../schema/schema_types'
import {
DeepMutable,
GetAllEntities,

@@ -152,25 +153,46 @@ GetFields,

// }>
// export type OrmaQueryResult<
// Schema extends OrmaSchema,
// Query extends object,
// Entity extends GetAllEntities<Schema> = never
// > =
// Omit<
// {
// // should be returned as a result if the key is not a keyword and the value is not a subquery
// -readonly [Key in keyof Query]: Query[Key] extends {
// $from: GetAllEntities<Schema>
// } // if the value has a $from prop, it is always a subquery
// ?
// | OrmaQueryResult<Schema, Query[Key], Query[Key]['$from']>[]
// | undefined
// : Key extends GetAllEntities<Schema> // The other option for a subquery is that the prop is an entity name
// ? Query[Key] extends object // and the value is an object
// ? Exclude<keyof Query[Key], Keyword> extends never // and the value has at least one non-keyword prop
// ? never
// : OrmaQueryResult<Schema, Query[Key], Key>[] | undefined
// : never
// : GetSchemaTypeForField<Schema, Entity, Key, Query[Key]>
// },
// Keyword
// >
export type OrmaQueryResult<
Schema extends OrmaSchema,
Query extends object,
Entity extends GetAllEntities<Schema> = never
> = Omit<
{
// should be returned as a result if the key is not a keyword and the value is not a subquery
-readonly [Key in keyof Query]: Query[Key] extends {
$from: GetAllEntities<Schema>
} // if the value has a $from prop, it is always a subquery
?
| OrmaQueryResult<Schema, Query[Key], Query[Key]['$from']>[]
| undefined
: Key extends GetAllEntities<Schema> // The other option for a subquery is that the prop is an entity name
? Query[Key] extends object // and the value is an object
? Exclude<keyof Query[Key], Keyword> extends never // and the value has at least one non-keyword prop
? never
: OrmaQueryResult<Schema, Query[Key], Key>[] | undefined
: never
: GetSchemaTypeForField<Schema, Entity, Key, Query[Key]>
},
Keyword
>
Aliases extends OrmaQueryAliases<Schema>,
Query extends object
> = {
-readonly [Key in keyof Query &
(
| GetAllEntities<Schema>
| GetRootAliases<Schema, Aliases>
)]?: Query[Key] extends {
$from: GetAllEntities<Schema>
}
? OrmaRecord<Schema, Aliases, Query[Key]['$from'], Query[Key]>[]
: Query[Key] extends object
? Key extends GetAllEntities<Schema>
? OrmaRecord<Schema, Aliases, Key, Query[Key]>[]
: never
: never
}

@@ -212,2 +234,4 @@ type GetSchemaTypeForField<

| undefined // subquery with $from
: Subquery[Key] extends { $escape }
? DeepMutable<Subquery[Key]['$escape']>
: Subquery[Key] extends true

@@ -226,2 +250,6 @@ ? Key extends GetFields<Schema, Entity>

type DefaultCase<Key> = Key extends `$${string}` ? never : any
/*
Subquery[Key] extends { $escape }
? Subquery[Key]['$escape']
*/
import { as_orma_query } from '../../query/query'
import {
GlobalTestAliases,
GlobalTestQuery,

@@ -7,3 +8,3 @@ GlobalTestSchema,

} from '../../test_data/global_test_schema'
import { SimplifiedQuery } from './query_types'
import { FieldObj, SimplifiedQuery } from './query_types'

@@ -249,10 +250,10 @@ {

{
as_orma_query(global_test_schema, {
const t = {
posts: {
id: true,
_asdas: {
$from: 'users',
}
my_title: {
$escape: 123,
},
},
})
} as const satisfies GlobalTestQuery
}

@@ -180,2 +180,3 @@ import { OrmaSchema } from '../schema/schema_types'

| GetAliases<Schema, Aliases, Entity>
| { $escape: any }

@@ -182,0 +183,0 @@ type ExpressionFunction<

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