Comparing version 1.0.238 to 1.0.239
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; | ||
}; |
@@ -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< |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1662662
40676