{"id":20366560,"url":"https://github.com/hookyns/typeorm-linq","last_synced_at":"2026-05-06T13:03:37.927Z","repository":{"id":111395643,"uuid":"261280631","full_name":"Hookyns/typeorm-linq","owner":"Hookyns","description":"True LINQ wrapper around TypeORM using Expression\u003c\u003e","archived":false,"fork":false,"pushed_at":"2020-05-24T22:03:15.000Z","size":26,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-05T07:46:12.377Z","etag":null,"topics":["javascript","linq","nodejs","plugin","query","query-builder","transformer","typeorm-linq","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Hookyns.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-04T19:48:51.000Z","updated_at":"2022-03-02T09:48:20.000Z","dependencies_parsed_at":"2023-05-18T21:15:44.114Z","dependency_job_id":null,"html_url":"https://github.com/Hookyns/typeorm-linq","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Hookyns/typeorm-linq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hookyns%2Ftypeorm-linq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hookyns%2Ftypeorm-linq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hookyns%2Ftypeorm-linq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hookyns%2Ftypeorm-linq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Hookyns","download_url":"https://codeload.github.com/Hookyns/typeorm-linq/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Hookyns%2Ftypeorm-linq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32694980,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["javascript","linq","nodejs","plugin","query","query-builder","transformer","typeorm-linq","typescript"],"created_at":"2024-11-15T00:25:41.221Z","updated_at":"2026-05-06T13:03:37.885Z","avatar_url":"https://github.com/Hookyns.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TypeORM-LINQ\nTrue LINQ expressions in Typescript over TypeORM thanks to custom [typescript-expression-transformer](https://www.npmjs.com/package/typescript-expression-transformer).\nThanks to this wrapper, you are able to write clear TS(/JS) with typing support of IDEs, it's regular code.\n\n## Early development!\nThis is an early stage of development. Everything is subject to change.\n\n## Working Examples\n```typescript\n// Filter model\nlet filter = {\n    findLastName: \"Paul\",\n    lastNameStarts: \"A.*\",\n    requestedNames: [\"Lukas\", \"Leon\", \"Paul\"]\n};\n\nlet field = \"lastName\";\n\nlet users = await new LinqSelectQueryBuilder(getConnection().manager, User)\n    .where(user =\u003e (user.firstName == \"Nash\" || user[field] == filter.findLastName) \u0026\u0026 user![\"midName\"] != \"Carl\")\n    .getRawMany();\n\n// Generated query: SELECT * FROM `user` `__mainEntity` WHERE (`__mainEntity`.`firstName` = 'Nash' OR `__mainEntity`.`lastName` = ?) AND `__mainEntity`.`midName` != 'Carl' -- PARAMETERS: [\"Paul\"]\n\nlet users2 = await new LinqSelectQueryBuilder(getConnection().manager, User)\n    .where(user =\u003e user.firstName.match(filter.lastNameStarts) \u0026\u0026 user.midName != null)\n    .getRawMany();\n\n// Generated query: SELECT * FROM `user` `__mainEntity` WHERE `__mainEntity`.`firstName` LIKE ? AND `__mainEntity`.`midName` IS NOT NULL -- PARAMETERS: [\"A%\"]\n\nlet users3 = await new LinqSelectQueryBuilder(getConnection().manager, User)\n    .where(user =\u003e filter.requestedNames.includes(user.firstName) || user.midName.startsWith(\"A\") || user.midName.endsWith(\"s\"))\n    .getRawMany();\n\n// Generated query: SELECT * FROM `user` `__mainEntity` WHERE `__mainEntity`.`firstName` IN (?) OR `__mainEntity`.`midName` LIKE 'A%' OR `__mainEntity`.`midName` LIKE '%s' -- PARAMETERS: [[\"Lukas\",\"Leon\",\"Paul\"]]\n```\n\n### Transpiled Code:\n```javascript\nlet filter = {\n    findLastName: \"Paul\",\n    lastNameStarts: \"A.*\",\n    requestedNames: [\"Lukas\", \"Leon\", \"Paul\"]\n};\n\nlet users = await new LinqSelectQueryBuilder_1.default(typeorm_1.getConnection().manager, User_1.User)\n    .where({ compiled: user =\u003e (user.firstName == \"Nash\" || user.lastName == filter.findLastName) \u0026\u0026 user.midName != \"Carl\", context: { filter }, expression: { \"flags\": 33024, \"kind\": 202, \"parameters\": [{ \"flags\": 32768, \"kind\": 156, \"name\": { \"flags\": 32768, \"kind\": 75, \"escapedText\": \"user\" }, \"symbol\": { \"flags\": 1, \"escapedName\": \"user\", \"declarations\": [null], \"exports\": {} } }], \"equalsGreaterThanToken\": { \"flags\": 32768, \"kind\": 38 }, \"body\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 200, \"expression\": { \"flags\": 0, \"kind\": 209,\n                    \"left\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0,\n                                \"kind\": 75, \"escapedText\": \"firstName\" } }, \"operatorToken\": { \"flags\": 0, \"kind\": 34 }, \"right\": { \"flags\": 0, \"kind\": 10, \"text\": \"Nash\" } }, \"operatorToken\": { \"flags\": 0, \"kind\": 56 }, \"right\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\"\n                            }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"lastName\" } }, \"operatorToken\": { \"flags\": 0, \"kind\": 34 }, \"right\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"filter\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"findLastName\" }\n                        } } } },\n            \"operatorToken\": { \"flags\": 0, \"kind\": 55 }, \"right\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"midName\" } },\n                \"operatorToken\": { \"flags\": 0, \"kind\": 35 }, \"right\": { \"flags\": 0, \"kind\": 10, \"text\": \"Carl\" } } }, \"symbol\": { \"flags\": 16, \"escapedName\": \"__function\", \"declarations\": [null] }, \"locals\": {}, \"endFlowNode\": { \"flags\": 4, \"antecedents\": [{ \"flags\": 1088, \"antecedent\": { \"flags\": 3136,\n                        \"antecedent\": { \"flags\": 3074 } } },\n                { \"flags\": 1056, \"antecedent\": { \"flags\": 3076, \"antecedents\": [{ \"flags\": 1056 },\n                            { \"flags\": 1056 }] } }, { \"flags\": 1088 }] } } })\n    .getRawMany();\n\nlet users2 = await new LinqSelectQueryBuilder_1.default(typeorm_1.getConnection().manager, User_1.User)\n    .where({ compiled: user =\u003e user.firstName.match(filter.lastNameStarts) \u0026\u0026 user.midName != null, context: { filter }, expression: { \"flags\": 33024, \"kind\": 202, \"parameters\": [{ \"flags\": 32768, \"kind\": 156, \"name\": { \"flags\": 32768, \"kind\": 75, \"escapedText\": \"user\" }, \"symbol\": { \"flags\": 1, \"escapedName\": \"user\", \"declarations\": [null], \"exports\": {} } }], \"equalsGreaterThanToken\": { \"flags\": 32768, \"kind\": 38 }, \"body\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 196, \"expression\": { \"flags\": 0, \"kind\": 194,\n                    \"expression\": { \"flags\": 0, \"kind\": 194,\n                        \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"firstName\" } }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"match\" } }, \"arguments\": [{ \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75,\n                            \"escapedText\": \"filter\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"lastNameStarts\" } }] }, \"operatorToken\": { \"flags\": 0,\n                \"kind\": 55 }, \"right\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"midName\" } }, \"operatorToken\": { \"flags\": 0, \"kind\": 35 },\n                \"right\": { \"flags\": 0,\n                    \"kind\": 100 } } }, \"symbol\": {\n            \"flags\": 16, \"escapedName\": \"__function\", \"declarations\": [null] }, \"locals\": {}, \"endFlowNode\": { \"flags\": 4, \"antecedents\": [{ \"flags\": 1088, \"antecedent\": { \"flags\": 3074 } }, { \"flags\": 1056, \"antecedent\": { \"flags\": 3104 } }, { \"flags\": 1088 }]\n        } } })\n    .getRawMany();\n\nlet users3 = await new LinqSelectQueryBuilder_1.default(typeorm_1.getConnection().manager, User_1.User)\n    .where({ compiled: user =\u003e filter.requestedNames.includes(user.firstName) || user.midName.startsWith(\"A\") || user.midName.endsWith(\"s\"), context: { filter }, expression: { \"flags\": 33024, \"kind\": 202, \"parameters\": [{ \"flags\": 32768, \"kind\": 156, \"name\": { \"flags\": 32768, \"kind\": 75, \"escapedText\": \"user\" }, \"symbol\": { \"flags\": 1, \"escapedName\": \"user\", \"declarations\": [null], \"exports\": {} } }], \"equalsGreaterThanToken\": { \"flags\": 32768, \"kind\": 38 }, \"body\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 209, \"left\": { \"flags\": 0, \"kind\": 196, \"expression\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"filter\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"requestedNames\" } }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"includes\" } }, \"arguments\": [{ \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"firstName\" } }] }, \"operatorToken\": { \"flags\": 0, \"kind\": 56 }, \"right\": { \"flags\": 0, \"kind\": 196, \"expression\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0,\n                                \"kind\": 75, \"escapedText\": \"midName\" } }, \"name\": {\n                            \"flags\": 0, \"kind\": 75, \"escapedText\": \"startsWith\" } }, \"arguments\": [{ \"flags\": 0, \"kind\": 10, \"text\": \"A\" }] } }, \"operatorToken\": { \"flags\": 0, \"kind\": 56 }, \"right\": { \"flags\": 0, \"kind\": 196, \"expression\": { \"flags\": 0, \"kind\": 194, \"expression\": { \"flags\": 0, \"kind\": 194,\n                        \"expression\": { \"flags\": 0,\n                            \"kind\": 75, \"escapedText\": \"user\" }, \"name\": { \"flags\": 0, \"kind\": 75, \"escapedText\": \"midName\" } }, \"name\": { \"flags\": 0, \"kind\": 75,\n                        \"escapedText\": \"endsWith\" } }, \"arguments\": [{ \"flags\": 0, \"kind\": 10, \"text\": \"s\" }] } }, \"symbol\": { \"flags\": 16, \"escapedName\": \"__function\", \"declarations\": [null] },\n        \"locals\": {}, \"endFlowNode\": { \"flags\": 4, \"antecedents\": [{ \"flags\": 1056, \"antecedent\": { \"flags\": 3074 } }, {\n                    \"flags\": 1056, \"antecedent\": { \"flags\": 3136 } }, { \"flags\": 1056, \"antecedent\": { \"flags\": 3136 } }, { \"flags\": 1088 }] } } })\n    .getRawMany();\n```\n\n### Valid but not Working Example (soon)\n```typescript\nawait new LinqSelectQueryBuilder(getConnection().manager, User)\n    .innerJoin(\n        UserAccount, \n        (user, userAccount) =\u003e user.userAccountId == userAccount.id,\n        (user, userAccount) =\u003e ({\n            user,\n            userAccount\n        }))\n    .innerJoin(\n        UserRole, \n        (x, userRole) =\u003e x.user.userRoleId == userRole.id,\n        (x, userRole) =\u003e ({\n            ...x,\n            userRole\n        }))\n    .where(x =\u003e x.user.firstName.match(\"A.*\") || x.userRole.sysName == UserRoleSysNames.Admin)\n    .map(x =\u003e ({\n        name: x.user.firstName + \" \" + x.user.lastName,\n        login: x.userAccount.login,\n        passHash: x.userAccount.passHash,\n        salt: x.userAccount.salt\n    }))\n    .where(x =\u003e !!x.name)\n    .getMany()\n```\n\n## How to Run\nTo run this, you just need to transpile typescript with mentioned transform plugin. Use [ttypescript](https://www.npmjs.com/package/ttypescript) package for it.\nJust add transformer to `tsconfig.json` and run `ttsc` instead of `tsc`.\n```json\n{\n    \"compilerOptions\": {\n        \"plugins\": [\n            { \"transform\": \"typescript-expression-transformer\" }\n        ]\n    }\n}\n```\n\nor Webpack\n```javascript\n{\n    test: /\\.(ts|tsx)$/,\n    loader: require.resolve('awesome-typescript-loader'),\n    // or\n    loader: require.resolve('ts-loader'),\n    options: {\n        compiler: 'ttypescript'\n    }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookyns%2Ftypeorm-linq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhookyns%2Ftypeorm-linq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookyns%2Ftypeorm-linq/lists"}