|
1 | | -import _ from 'lodash'; |
| 1 | +import { |
| 2 | + differenceWith, |
| 3 | + isEqual, |
| 4 | + capitalize, |
| 5 | + pick, |
| 6 | + omitBy, |
| 7 | + isNil, |
| 8 | +} from 'es-toolkit'; |
| 9 | +import { get } from 'es-toolkit/compat'; |
2 | 10 | import memoize from 'memoizee'; |
3 | 11 | import stringHash from 'string-hash'; |
4 | 12 | import { |
@@ -433,20 +441,21 @@ export class OData2AbstractSQL { |
433 | 441 | if (minimizeAliases === false && aliasLength <= MAX_ALIAS_LENGTH) { |
434 | 442 | return alias; |
435 | 443 | } |
436 | | - alias = _(alias.toLowerCase()) |
| 444 | + alias = alias |
| 445 | + .toLowerCase() |
437 | 446 | .split('.') |
438 | 447 | .map((part) => { |
439 | 448 | if (minimizeAliases === false && aliasLength <= MAX_ALIAS_LENGTH) { |
440 | 449 | return part; |
441 | 450 | } |
442 | 451 | aliasLength -= part.length; |
443 | | - const shortAlias = _(part) |
| 452 | + const shortAlias = part |
444 | 453 | .split('-') |
445 | 454 | .map((part2) => { |
446 | | - part2 = _(part2) |
| 455 | + part2 = part2 |
447 | 456 | .split(' ') |
448 | 457 | .map((part3) => { |
449 | | - part3 = _(part3) |
| 458 | + part3 = part3 |
450 | 459 | .split('$') |
451 | 460 | .map((part4) => shortAliases[part4] ?? part4) |
452 | 461 | .join('$'); |
@@ -500,7 +509,7 @@ export class OData2AbstractSQL { |
500 | 509 | this.reset(); |
501 | 510 | this.bindVarsLength = bindVarsLength; |
502 | 511 | let tree: AbstractSqlQuery; |
503 | | - if (_.isEmpty(path)) { |
| 512 | + if (Object.keys(path).length === 0) { |
504 | 513 | tree = ['$serviceroot']; |
505 | 514 | } else if (['$metadata', '$serviceroot'].includes(path.resource)) { |
506 | 515 | tree = [path.resource]; |
@@ -908,7 +917,7 @@ export class OData2AbstractSQL { |
908 | 917 | ((index.type === 'UNIQUE' && index.predicate == null) || |
909 | 918 | index.type === 'PRIMARY KEY') && |
910 | 919 | sqlFieldNames.length === index.fields.length && |
911 | | - _.isEqual(index.fields.slice().sort(), sqlFieldNames) |
| 920 | + isEqual(index.fields.slice().sort(), sqlFieldNames) |
912 | 921 | ); |
913 | 922 | }) |
914 | 923 | ) { |
@@ -1073,12 +1082,11 @@ export class OData2AbstractSQL { |
1073 | 1082 | `Could not resolve relationship for '${resourceName}'`, |
1074 | 1083 | ); |
1075 | 1084 | } |
1076 | | - const relationshipPath = _(relationship) |
| 1085 | + const relationshipPath = relationship |
1077 | 1086 | .split('__') |
1078 | 1087 | .map(odataNameToSqlName) |
1079 | | - .flatMap((sqlName) => this.Synonym(sqlName).split('-')) |
1080 | | - .value(); |
1081 | | - const relationshipMapping = _.get(resourceRelations, relationshipPath); |
| 1088 | + .flatMap((sqlName) => this.Synonym(sqlName).split('-')); |
| 1089 | + const relationshipMapping = get(resourceRelations, relationshipPath); |
1082 | 1090 | if (!relationshipMapping?.$) { |
1083 | 1091 | throw new SyntaxError( |
1084 | 1092 | `Could not resolve relationship mapping from '${resourceName}' to '${relationshipPath}'`, |
@@ -1110,10 +1118,10 @@ export class OData2AbstractSQL { |
1110 | 1118 | sqlNameToODataName(field.fieldName), |
1111 | 1119 | ]); |
1112 | 1120 | } |
1113 | | - const fields = _.differenceWith( |
| 1121 | + const fields = differenceWith( |
1114 | 1122 | odataFieldNames, |
1115 | 1123 | query.select, |
1116 | | - (a, b) => a[1] === _.last(b), |
| 1124 | + (a, b) => a[1] === b.at(-1), |
1117 | 1125 | ).map((args) => this.AliasSelectField(...args)); |
1118 | 1126 | query.select = query.select.concat(fields); |
1119 | 1127 | } |
@@ -1195,7 +1203,7 @@ export class OData2AbstractSQL { |
1195 | 1203 | case 'and': |
1196 | 1204 | case 'or': |
1197 | 1205 | return [ |
1198 | | - _.capitalize(type), |
| 1206 | + capitalize(type), |
1199 | 1207 | ...rest.map((v) => this.BooleanMatch(v)), |
1200 | 1208 | ]; |
1201 | 1209 | case 'not': { |
@@ -1270,7 +1278,7 @@ export class OData2AbstractSQL { |
1270 | 1278 | throw new SyntaxError('Unexpected function name'); |
1271 | 1279 | } |
1272 | 1280 | const args = properties.args.map((v: any) => this.Operand(v)); |
1273 | | - return [sqlName ?? (_.capitalize(name) as Capitalize<T>), ...args]; |
| 1281 | + return [sqlName ?? (capitalize(name) as Capitalize<T>), ...args]; |
1274 | 1282 | } |
1275 | 1283 | Operand( |
1276 | 1284 | match: any, |
@@ -1558,7 +1566,7 @@ export class OData2AbstractSQL { |
1558 | 1566 | DateMatch(match: any, optional: true): StrictDateTypeNodes | undefined; |
1559 | 1567 | DateMatch(match: any): StrictDateTypeNodes; |
1560 | 1568 | DateMatch(match: any, optional = false): StrictDateTypeNodes | undefined { |
1561 | | - if (_.isDate(match)) { |
| 1569 | + if (match instanceof Date) { |
1562 | 1570 | return ['Date', match]; |
1563 | 1571 | } else if (Array.isArray(match) && match[0] === 'call') { |
1564 | 1572 | const { method } = match[1]; |
@@ -1592,11 +1600,17 @@ export class OData2AbstractSQL { |
1592 | 1600 | if (match == null || typeof match !== 'object') { |
1593 | 1601 | return; |
1594 | 1602 | } |
1595 | | - const duration = _(match) |
1596 | | - .pick('negative', 'day', 'hour', 'minute', 'second') |
1597 | | - .omitBy(_.isNil) |
1598 | | - .value(); |
1599 | | - if (_(duration).omit('negative').isEmpty()) { |
| 1603 | + const picked = pick(match, ['negative', 'day', 'hour', 'minute', 'second']); |
| 1604 | + |
| 1605 | + const duration = omitBy(picked, isNil); |
| 1606 | + |
| 1607 | + // Destructure 'negative' out, collect the 'rest' into a new object |
| 1608 | + const { negative, ...rest } = duration; |
| 1609 | + |
| 1610 | + // Check if 'rest' is empty |
| 1611 | + const isEmptyDuration = Object.keys(rest).length === 0; |
| 1612 | + |
| 1613 | + if (isEmptyDuration) { |
1600 | 1614 | return; |
1601 | 1615 | } |
1602 | 1616 | return ['Duration', duration]; |
@@ -1786,7 +1800,7 @@ export class OData2AbstractSQL { |
1786 | 1800 | }); |
1787 | 1801 | if (existingJoin != null) { |
1788 | 1802 | const existingJoinPredicate = existingJoin[2]?.[1]; |
1789 | | - if (!_.isEqual(navigation.where, existingJoinPredicate)) { |
| 1803 | + if (!isEqual(navigation.where, existingJoinPredicate)) { |
1790 | 1804 | // When we reach this point we have found an already existing JOIN with the |
1791 | 1805 | // same alias as the one we just created but different ON predicate. |
1792 | 1806 | // TODO: In this case we need to be able to generate a new alias for the newly JOINed resource. |
@@ -1837,7 +1851,7 @@ export class OData2AbstractSQL { |
1837 | 1851 | this.defaultResource = undefined; |
1838 | 1852 | } |
1839 | 1853 | Synonym(sqlName: string) { |
1840 | | - return _(sqlName) |
| 1854 | + return sqlName |
1841 | 1855 | .split('-') |
1842 | 1856 | .map((namePart) => { |
1843 | 1857 | const synonym = this.clientModel.synonyms[namePart]; |
@@ -1894,7 +1908,7 @@ export class OData2AbstractSQL { |
1894 | 1908 | extraBindVars: ODataBinds, |
1895 | 1909 | bindVarsLength: number, |
1896 | 1910 | ): ModernDefinition { |
1897 | | - const rewrittenDefinition = _.cloneDeep( |
| 1911 | + const rewrittenDefinition = structuredClone( |
1898 | 1912 | convertToModernDefinition(definition), |
1899 | 1913 | ); |
1900 | 1914 | rewriteBinds(rewrittenDefinition, extraBindVars, bindVarsLength); |
@@ -1953,12 +1967,12 @@ const addAliases = ( |
1953 | 1967 | // We then traverse any non suffix nodes to make sure those parts get their short versions. This should only happen |
1954 | 1968 | // in the case of a '' suffix because it means that the other parts are supersets, eg `of`/`often` and must be added |
1955 | 1969 | // with a longer short alias, eg `of`/`oft` |
1956 | | - _.forEach(node, (value, key) => { |
| 1970 | + for (const [key, value] of Object.entries(node)) { |
1957 | 1971 | if (key === '$suffix') { |
1958 | | - return; |
| 1972 | + continue; // Skips this iteration |
1959 | 1973 | } |
1960 | 1974 | traverseNodes(str + key, value); |
1961 | | - }); |
| 1975 | + } |
1962 | 1976 | }; |
1963 | 1977 |
|
1964 | 1978 | lowerCaseAliasParts.sort().forEach(buildTrie); |
@@ -1988,69 +2002,80 @@ const getRelationships = ( |
1988 | 2002 | const generateShortAliases = (clientModel: RequiredAbstractSqlModelSubset) => { |
1989 | 2003 | const shortAliases: Dictionary<string> = {}; |
1990 | 2004 |
|
1991 | | - const aliasParts = _(getRelationships(clientModel.relationships)) |
1992 | | - .union(Object.keys(clientModel.synonyms)) |
1993 | | - .reject((key) => key === '$') |
1994 | | - .map((alias) => alias.toLowerCase()) |
1995 | | - .value(); |
| 2005 | + // 1. Safely get your source arrays (using ?? [] to handle nulls like Lodash would) |
| 2006 | + const rels = getRelationships(clientModel.relationships) ?? []; |
| 2007 | + const synonyms = Object.keys(clientModel.synonyms ?? {}); |
| 2008 | + |
| 2009 | + // 2. Create the Union (Spread into a Set to remove duplicates, then back to Array) |
| 2010 | + const uniqueKeys = Array.from(new Set([...rels, ...synonyms])); |
| 2011 | + |
| 2012 | + // 3. Filter and Map |
| 2013 | + const aliasParts = uniqueKeys |
| 2014 | + .filter((key) => key !== '$') // Native replacement for .reject() |
| 2015 | + .map((alias) => alias.toLowerCase()); |
1996 | 2016 |
|
1997 | 2017 | // Add the first level of aliases, of names split by `-`/` `/`$`, for short aliases on a word by word basis |
1998 | | - let origAliasParts = _(aliasParts) |
1999 | | - .flatMap((aliasPart) => aliasPart.split(/-| |\$/)) |
2000 | | - .uniq() |
2001 | | - .value(); |
| 2018 | + let origAliasParts = Array.from( |
| 2019 | + new Set(aliasParts.flatMap((aliasPart) => aliasPart.split(/-| |\$/))), |
| 2020 | + ); |
2002 | 2021 | addAliases(shortAliases, origAliasParts); |
2003 | 2022 |
|
2004 | 2023 | // Add aliases for $ containing names |
2005 | | - origAliasParts = _(aliasParts) |
2006 | | - .flatMap((aliasPart) => aliasPart.split(/-| /)) |
2007 | | - .filter((aliasPart) => aliasPart.includes('$')) |
2008 | | - .flatMap((aliasPart) => { |
2009 | | - shortAliases[aliasPart] = aliasPart |
2010 | | - .split('$') |
2011 | | - .map((part) => shortAliases[part]) |
2012 | | - .join('$'); |
2013 | | - return []; |
2014 | | - }) |
2015 | | - .uniq() |
2016 | | - .value(); |
| 2024 | + origAliasParts = Array.from( |
| 2025 | + new Set( |
| 2026 | + aliasParts |
| 2027 | + .flatMap((aliasPart) => aliasPart.split(/-| /)) |
| 2028 | + .filter((aliasPart) => aliasPart.includes('$')) |
| 2029 | + .flatMap((aliasPart) => { |
| 2030 | + shortAliases[aliasPart] = aliasPart |
| 2031 | + .split('$') |
| 2032 | + .map((part) => shortAliases[part]) |
| 2033 | + .join('$'); |
| 2034 | + return []; |
| 2035 | + }), |
| 2036 | + ), |
| 2037 | + ); |
2017 | 2038 | addAliases(shortAliases, origAliasParts); |
2018 | 2039 |
|
2019 | 2040 | // Add the second level of aliases, of names that include a ` `, split by `-`, for short aliases on a verb/term basis |
2020 | | - origAliasParts = _(aliasParts) |
2021 | | - .flatMap((aliasPart) => aliasPart.split('-')) |
2022 | | - .filter((aliasPart) => aliasPart.includes(' ')) |
2023 | | - .flatMap((aliasPart) => |
2024 | | - // Generate the 2nd level aliases for both the short and long versions |
2025 | | - [ |
2026 | | - aliasPart, |
2027 | | - aliasPart |
2028 | | - .split(' ') |
2029 | | - .map((part) => shortAliases[part]) |
2030 | | - .join(' '), |
2031 | | - ], |
2032 | | - ) |
2033 | | - .uniq() |
2034 | | - .value(); |
| 2041 | + origAliasParts = Array.from( |
| 2042 | + new Set( |
| 2043 | + aliasParts |
| 2044 | + .flatMap((aliasPart) => aliasPart.split('-')) |
| 2045 | + .filter((aliasPart) => aliasPart.includes(' ')) |
| 2046 | + .flatMap((aliasPart) => |
| 2047 | + // Generate the 2nd level aliases for both the short and long versions |
| 2048 | + [ |
| 2049 | + aliasPart, |
| 2050 | + aliasPart |
| 2051 | + .split(' ') |
| 2052 | + .map((part) => shortAliases[part]) |
| 2053 | + .join(' '), |
| 2054 | + ], |
| 2055 | + ), |
| 2056 | + ), |
| 2057 | + ); |
2035 | 2058 |
|
2036 | 2059 | addAliases(shortAliases, origAliasParts); |
2037 | 2060 |
|
2038 | 2061 | // Add the third level of aliases, of names that include a `-`, for short aliases on a fact type basis |
2039 | | - origAliasParts = _(aliasParts) |
2040 | | - .filter((aliasPart) => aliasPart.includes('-')) |
2041 | | - .flatMap((aliasPart) => |
2042 | | - // Generate the 3rd level aliases for both the short and long versions |
2043 | | - |
2044 | | - [ |
2045 | | - aliasPart, |
2046 | | - aliasPart |
2047 | | - .split('-') |
2048 | | - .map((part) => shortAliases[part]) |
2049 | | - .join('-'), |
2050 | | - ], |
2051 | | - ) |
2052 | | - .uniq() |
2053 | | - .value(); |
| 2062 | + origAliasParts = Array.from( |
| 2063 | + new Set( |
| 2064 | + aliasParts |
| 2065 | + .filter((aliasPart) => aliasPart.includes('-')) |
| 2066 | + .flatMap((aliasPart) => |
| 2067 | + // Generate the 3rd level aliases for both the short and long versions |
| 2068 | + |
| 2069 | + [ |
| 2070 | + aliasPart, |
| 2071 | + aliasPart |
| 2072 | + .split('-') |
| 2073 | + .map((part) => shortAliases[part]) |
| 2074 | + .join('-'), |
| 2075 | + ], |
| 2076 | + ), |
| 2077 | + ), |
| 2078 | + ); |
2054 | 2079 |
|
2055 | 2080 | addAliases(shortAliases, origAliasParts); |
2056 | 2081 |
|
|
0 commit comments