{"id":14972114,"url":"https://github.com/zouwei/onela","last_synced_at":"2025-04-06T12:10:59.826Z","repository":{"id":57314629,"uuid":"47875820","full_name":"zouwei/onela","owner":"zouwei","description":"Onela is an open source object relational mapping framework based on node.js（Onela是一个基于node.js的开源对象关系映射框架）","archived":false,"fork":false,"pushed_at":"2025-02-01T12:50:02.000Z","size":225,"stargazers_count":59,"open_issues_count":0,"forks_count":12,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-30T09:07:47.109Z","etag":null,"topics":["database","mysql","mysql-database","onela","orm","orm-framework","postgre","postgresql","sql","sqlite"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zouwei.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":"2015-12-12T11:39:39.000Z","updated_at":"2025-02-01T12:50:06.000Z","dependencies_parsed_at":"2025-03-14T21:03:09.505Z","dependency_job_id":"a0e1d56f-d9ab-4c8b-8542-98e530ca756f","html_url":"https://github.com/zouwei/onela","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouwei%2Fonela","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouwei%2Fonela/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouwei%2Fonela/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zouwei%2Fonela/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zouwei","download_url":"https://codeload.github.com/zouwei/onela/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247478324,"owners_count":20945266,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["database","mysql","mysql-database","onela","orm","orm-framework","postgre","postgresql","sql","sqlite"],"created_at":"2024-09-24T13:46:24.557Z","updated_at":"2025-04-06T12:10:59.808Z","avatar_url":"https://github.com/zouwei.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Onela一个Node.js开源的ORM对象关系映射框架\r\n\r\n\u003e Onela是基于node.js开源的基于对象的映射框架，支持各种关系数据库数据基础设施。 同时支持各种数据库对象的读写分离，数据库实例垂直拆分。 在onela架构之上，您可以体验无SQL编程的乐趣，您只需要关注业务逻辑代码部分。 而且，我将在后面的版本的支持下加入分布式缓存来实现前端和后端的node.js程序来挑战大规模应用的情况。\r\n\u003e\r\n\r\n\r\n\r\n[![NPM version](https://img.shields.io/npm/v/onela.svg)](https://www.npmjs.com/package/onela)\r\n[![Downloads](https://img.shields.io/npm/dm/onela.svg)](https://www.npmjs.com/package/onela)\r\n\r\n[![NPM](https://nodei.co/npm/onela.png?downloads=true)](https://nodei.co/npm/onela/)\r\n\r\n\r\n\r\n### 重大更新：v2.0版本发布\r\n\r\n此版本重大更新，原有如果使用了V2.0.0之前的版本请注意，升级到最新版，最原有代码也需要微调。\r\n\r\n特别感谢Hugh-won在v2.0.0版本改进提供帮助~\r\n\r\n目前（v2.3.0）已经支持 MySQL、PostgreSQL、SQL Server、SQLite数据库\r\n\r\n### 步骤一：安装node模块（step 1 npm install node_modules）\r\n\r\n~~~~~~\r\nnpm install onela\t\t// 项目核心包\r\n\r\n依赖包安装\r\nnpm install mysql\t// MySQL数据库\r\nnpm install pg\t\t// PostgreSQL数据库\r\nnpm install sqlite3\t// SQLite数据库\r\nnpm install tedious\t// SQL Server数据库\r\n~~~~~~\r\n\r\n\r\n\r\n### 步骤二：配置数据源（step 2 Mapping data sources）\r\n\r\n数据库的配置可以配置在config全局配置中，在初始化调用取出来就可以了了\r\n\r\n```\r\n/**\r\n * 数据库配置，可以初始化多个数据库实例\r\n */\r\nlet dbconfig = [{\r\n    \"engine\": \"default\",    // 数据库实例名称\r\n    \"type\": \"mysql\",        // 数据库类型：MYSQL（不区分大小写）,支持类型：mysql、postgresql、sqlite、sqlserver\r\n    \"value\": {\r\n        \"connectionLimit\": 5,\r\n        \"host\": \"localhost\",\r\n        \"user\": \"\",\r\n        \"password\": \"\",\r\n        \"database\": \"todo\"\r\n    }\r\n},\r\n{\r\n    \"engine\": \"default\",\r\n    \"type\": \"PostgreSQL\",           // 数据库类型：PostgreSQL（不区分大小写）\r\n    \"value\": {\r\n        \"port\": 3432,\r\n        \"host\": \"127.0.0.1\",\r\n        \"user\": \"manor\",\r\n        \"password\": \"test\",\r\n        \"database\": \"test_db\"\r\n    }\r\n}];\r\n\r\n```\r\n\r\n\r\n\r\n### 步骤三：Onela ORM对象初始化（step 3 Onela ORM object initialization）\r\n\r\n~~~~~~\r\nconst {Onela, OnelaBaseModel}  = require(\"onela\");\r\n// 初始化Onela模块（建议全局初始化）\r\nOnela.init(dbconfig);\r\n~~~~~~\r\n\r\n\r\n\r\n### 步骤四：单例（数据表）对象配置以及方法的扩展封装\r\n\r\n~~~~~\r\n// 在OnelaBaseModel类中封装了常用的ORM方法\r\nclass ToDoManager extends OnelaBaseModel {\r\n    // 可以在此自定义扩展方法（默认封装没有的方法）\r\n}\r\n\r\n/**\r\n * 【重要】单例模式，数据表配置\r\n * tableName：数据表名\r\n * engine：数据库引擎名称，需要和dbconfig配置的名称对应起来\r\n * fields[n].name:数据表字段名\r\n * fields[n].type:数据表字段类型\r\n * fields[n].default:默认值\r\n * */\r\nToDoManager.configs = {\r\n    fields: [\r\n        {name: \"id\", type: \"int\", default: null},\r\n        {name: \"content\", type: \"varchar\"},\r\n        {name: \"is_done\", type: \"int\", default: 0},\r\n        {\r\n            name: \"create_time\", type: \"datetime\", default: () =\u003e {\r\n            return new Date()\r\n        }\r\n        },\r\n        {name: \"finish_time\", type: \"datetime\", default: null}\r\n    ],\r\n    tableName: \"todos\",\r\n    engine: \"default\"\r\n};\r\n~~~~~\r\n\r\n\r\n\r\n### 步骤五：常用CRUD操作代码示例（step 5 Examples of common CRUD operation code）\r\n\r\n到这一步骤，可以直接使用ORM的方法了，增删改查，包含事务处理。\r\n\r\n```\r\n// 【重要】单例模式，数据表配置\r\nToDoManager.configs = {\r\n    fields: [\r\n        {name: \"id\", type: \"int\", default: null},\r\n        {name: \"content\", type: \"varchar\"},\r\n        {name: \"is_done\", type: \"int\", default: 0},\r\n        {\r\n            name: \"create_time\", type: \"datetime\", default: () =\u003e {\r\n            return new Date()\r\n        }\r\n        },\r\n        {name: \"finish_time\", type: \"datetime\", default: null}\r\n    ],\r\n    tableName: \"todos\",\r\n    engine: \"default\"\r\n};\r\n\r\n/**\r\n * 事务\r\n */\r\nToDoManager.transaction().then(t =\u003e {\r\n    // 先新增一条记录\r\n    ToDoManager.insertEntity({\r\n        \"content\": \"测试事务\"\r\n    }, {transaction: t})\r\n        .then(data =\u003e {\r\n            // 再对新增的记录执行修改\r\n            return ToDoManager.updateEntity({\r\n                \"update\": [\r\n                    {\"key\": \"content\", \"value\": \"事务修改\", \"operator\": \"replace\"}    // 修改了content字段\r\n                ],\r\n                \"where\": [\r\n                    {\"logic\": \"and\", \"key\": \"id\", operator: \"=\", \"value\": 8}\r\n                ]\r\n            }, {transaction: t});\r\n        })\r\n        .then(data =\u003e {\r\n            console.log('执行结果', data);\r\n            t.commit().then(d=\u003e{\r\n                console.log(d);\r\n            });\r\n        })\r\n        .catch(ex =\u003e {\r\n            console.log('事务异常回滚', ex);\r\n            t.rollback().then(d=\u003e{\r\n                console.log(d);\r\n            });\r\n        });\r\n});\r\n\r\n\r\n/**\r\n * 单例模式：数据查询\r\n */\r\nToDoManager.getEntity({\r\n    where: [\r\n        //{\"logic\": \"and\", \"key\": \"id\", \"operator\": \"=\", \"value\": 1}\r\n    ]\r\n}, null).then(data =\u003e {\r\n    console.log('查询结果', data)\r\n}).then();\r\n\r\n/**\r\n * 单例模式：新增\r\n */\r\nToDoManager.insertEntity({\r\n    \"content\":\"测试\"\r\n}).then(data=\u003e{console.log('查询结果',data)});\r\n\r\n/**\r\n * 单例模式：分页查询\r\n */\r\nToDoManager.getEntityList({\r\n    \"where\": [\r\n            //{\"logic\": \"and\", \"key\": \"id\", \"operator\": \"=\", \"value\": 1}\r\n        ]\r\n}).then(console.log);\r\n\r\n/**\r\n * 单例模式：新增\r\n */\r\nToDoManager.insertEntity({\r\n    content: \"设计智能保险顾问的用户体系\"\r\n}).then(console.log);\r\n\r\n/**\r\n * 单例模式：批量新增\r\n */\r\nToDoManager.insertBatch([\r\n    {content: \"测试1\"},\r\n    {content: \"测试2\"},\r\n    {content: \"测试3\"}\r\n]).then(console.log);\r\n\r\n/**\r\n * 单例模式：删除（物理删除，不推荐使用）\r\n */\r\nToDoManager.deleteEntity({\r\n    \"where\": [\r\n        {\"key\": \"id\", operator: \"in\", value: [12360,12361], logic: \"and\"},\r\n        // {\"key\": \"is_done\", operator: \"=\", value: 1, logic: \"and\"}\r\n    ]\r\n}).then(console.log);\r\n\r\n/**\r\n * 单例模式：更新（对于删除，建议使用逻辑删除）\r\n */\r\nToDoManager.updateEntity({\r\n    update: [\r\n        {key: \"is_done\", value: 1, operator: \"replace\"}\r\n    ],\r\n    where: [\r\n        {\"key\": \"id\", operator: \"in\", value: [12362], logic: \"and\"},\r\n    ]\r\n}).then(console.log);\r\n\r\n/**\r\n * 单例模式：实时统计\r\n */\r\nToDoManager.getEntityByAggregate({\r\n    // where:\r\n    \"aggregate\":[\r\n        {\"function\": \"count\", \"field\": \"is_done\", \"name\": \"undone_tasks\"},\r\n    ]\r\n}).then(console.log);\r\n```\r\n\r\n\r\n\r\nOk, you can now play happily~\r\n\r\n### Use instance to show（方法使用示例）\r\n\r\n#### Query example（示例：查询）\r\n\r\nThere are several ways to apply the query to different business scenarios. Paging query, waterfall flow inquiries, Standard query\r\n\r\n~~~\r\n\t//parameter\r\n    let p = {\r\n        \"select\": [\"t.id\"],     //Specify the output field, query all fields, use t. * Or select attributes by default\r\n        \"where\": [\r\n            {\"logic\": \"and\", \"key\": 'valid', \"operator\": \"=\", \"value\": 1},\r\n            {\"logic\": \"and\", \"key\": 'id', \"operator\": \"=\", \"value\": id}\r\n        ],\r\n        \"orderBy\": {\"created_time\": \"DESC\"},\r\n        \"limit\": [0, 1]         //Take the first data of the query results\r\n    }\r\n    //execute select\r\n    ToDoManager.getEntity(p)\r\n        .then(function (data) {\r\n            resolve(data);\r\n        })\r\n        .catch(function (err) {\r\n            reject(err);\r\n        });\r\n~~~\r\n\r\n\r\n\r\n#### Insert example（示例：新增）\r\n\r\nThere is also a new batch method db_instance.insertBatch(arr),The incoming value is an array of objects\r\n\r\n~~~\r\n\t//parameter\r\n    let p = {\r\n        \"name\":\"Sandy\",\r\n        \"sex\":\"female\",\r\n        \"email\":\"sandy@xxx.com\"\r\n        //……\r\n        //Other fields are added in turn\r\n    }\r\n    //execute insert\r\n    ToDoManager.insertEntity(p)\r\n        .then((data)=\u003e {\r\n            resolve(data);\r\n        })\r\n        .catch(function (err) {\r\n            reject(err);\r\n        });\r\n~~~\r\n\r\n\r\n\r\n#### Update example（示例：更新）\r\n\r\nThere are two main ways to update the field,replace or plus\r\n\r\n~~~\r\n //parameter\r\n var p = {\r\n     \"update\": [\r\n         //operator：replace update\r\n         {\"key\": \"name\", \"value\": 'Sandy', \"operator\": \"replace\"},\r\n         //operator：plus update,The field type needs to be a numeric type\r\n         {\"key\": \"money\", \"value\": 2, \"operator\": \"plus\"},\r\n         //operator：reduce update,The field type needs to be a numeric type\r\n         {\"key\": \"score\", \"value\": 1, \"operator\": \"reduce\"}\r\n         \r\n     ],\r\n     \"where\": [\r\n        //where条件：一般以主键id作为更新条件，支持多条件组合语\r\n        {\"logic\": \"and\",\"key\": \"id\",  \"operator\": \"=\", \"value\": 'abc'}\r\n     ]\r\n }\r\n //execute update\r\n  ToDoManager.updateEntity(p)\r\n        .then((data)=\u003e {\r\n            resolve(data);\r\n        })\r\n        .catch(function (err) {\r\n            reject(err);\r\n        });\r\n~~~\r\n\r\n\r\n\r\n#### Update example（示例：复杂SQL更新）\r\n\r\ncase when then else end 用法举例\r\n\r\n```\r\n SQL示例：update todos set is_done=1,content= (CASE id WHEN 12381 THEN '修改结果A' WHEN 12384 THEN '修改结果B' END)  where  1=1  and id in (12381, 12384); \r\n \r\n //parameter\r\n var p = {\r\n    update: [\r\n        {key: \"is_done\", value: 1, operator: \"replace\"},\r\n        {\r\n            \"key\": \"content\",\t\t //update field\r\n            \"case_field\": \"id\",\t\t //balance =  CASE id\r\n            \"case_item\": [\r\n                {\"case_value\": 3, \"value\": \"修改结果A\", \"operator\": \"replace\"},\t\t//WHEN '001' THEN 1\r\n                {\"case_value\": 6, \"value\": \"修改结果B\", \"operator\": \"replace\"}\t\t//WHEN '001' THEN balance+2\r\n            ]\r\n        }\r\n    ],\r\n    where: [\r\n        {\"key\": \"id\", operator: \"in\", value: [3,6], logic: \"and\"},\r\n    ]\r\n }\r\n //execute update\r\n  ToDoManager.updateEntity(p)\r\n        .then((data)=\u003e {\r\n            resolve(data);\r\n        })\r\n        .catch(function (err) {\r\n            reject(err);\r\n        });\r\n```\r\n\r\n\r\n\r\n#### Delete example（示例：删除）\r\n\r\nPhysical deletion, generally do not recommend this operation, it is recommended to delete the logic\r\n\r\n~~~\r\n\r\n\t//parameter\r\n    let p = {\r\n        \"where\": [\r\n            //Allow multiple query conditions\r\n            //{\"key\": \"字段名1\", \"value\": \"值\", \"logic\": \"连接联符 （默认为and 非必须 ）\", operator: \"关联符号 (默认为: =)\"},\r\n            {\"key\": \"id\", \"value\": \"abc\", \"logic\": \"and\", operator: \"=\"}\r\n        ]\r\n    }\r\n    //execute delete\r\n    ToDoManager.deleteEntity(p)\r\n        .then((data=\u003e) {\r\n            resolve(data);\r\n        })\r\n        .catch(function (err) {\r\n            reject(err);\r\n        });\r\n~~~\r\n\r\n\r\n\r\n### sql example（实例：直接执行SQL案例）\r\n\r\nNot recommended，Direct execution of sql can only be applied to specific types of databases\r\n\r\n~~~\r\nvar sql = \"SELECT * FROM tableName Where ...\";\r\n \r\n ToDoManager.streak(sql).then(result =\u003e{\r\n \t// Get execution results\r\n }); \r\n~~~\r\n\r\n\r\n\r\n#### Transaction example（实例：事务）\r\n\r\nCan only achieve local Transaction \r\n\r\n~~~\r\n// transaction\r\nToDoManager.transaction().then(t =\u003e {\r\n    // 先新增一条记录\r\n    ToDoManager.insertEntity({\r\n        \"content\": \"测试\"\r\n    }, {transaction: t})\r\n        .then(data =\u003e {\r\n            // 再对新增的记录执行修改\r\n            return ToDoManager.updateEntity({\r\n                \"update\": [\r\n                    {\"key\": \"content\", \"value\": \"执行修改测试\", \"operator\": \"replace\"}    // 修改了content字段\r\n                ],\r\n                \"where\": [\r\n                    {\"logic\": \"and\", \"key\": \"id\", operator: \"=\", \"value\": data.insertId}\r\n                ]\r\n            }, {transaction: t});\r\n        })\r\n        .then(data =\u003e {\r\n            console.log('执行结果', data);\r\n            // 事务提交\r\n            t.commit();\r\n        })\r\n        .catch(ex =\u003e {\r\n            console.log('事务异常回滚', ex.message);\r\n            // 事务回滚\r\n            t.rollback();\r\n        });\r\n});\r\n~~~\r\n\r\n*onela.js v1 版本已经下线*\r\n\r\n~~~~~\r\n在就版本中模块引用需要批量调整下(2.0.0之前的老版本兼容）\r\nconst onela = require('onela');\r\n更改为：\r\nconst onela = require('onela').Old;\r\n~~~~~\r\n\r\n此版本文档已经更新为最新文档，v2.0.0之前的老版本文档请查看：[老版本文档](https://github.com/zouwei/onela/wiki/v1.*%E7%89%88%E6%9C%AC%E6%96%87%E6%A1%A3%EF%BC%88%E6%97%A7%E7%89%88%EF%BC%89)\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzouwei%2Fonela","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzouwei%2Fonela","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzouwei%2Fonela/lists"}