{"id":25569639,"url":"https://github.com/dieselpoint/norm","last_synced_at":"2026-04-09T04:31:49.217Z","repository":{"id":6163326,"uuid":"7392993","full_name":"dieselpoint/norm","owner":"dieselpoint","description":"Access a database in one line of code. ","archived":false,"fork":false,"pushed_at":"2026-02-27T18:08:09.000Z","size":255,"stargazers_count":214,"open_issues_count":22,"forks_count":37,"subscribers_count":14,"default_branch":"master","last_synced_at":"2026-02-27T22:23:41.044Z","etag":null,"topics":["database","java","jdbc","orm","sql"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dieselpoint.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2013-01-01T03:48:36.000Z","updated_at":"2026-02-27T18:08:15.000Z","dependencies_parsed_at":"2023-12-18T23:27:35.993Z","dependency_job_id":null,"html_url":"https://github.com/dieselpoint/norm","commit_stats":{"total_commits":159,"total_committers":17,"mean_commits":9.352941176470589,"dds":0.6163522012578616,"last_synced_commit":"a379f867b8c0de76f5206071f5e31804995674e2"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/dieselpoint/norm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dieselpoint%2Fnorm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dieselpoint%2Fnorm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dieselpoint%2Fnorm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dieselpoint%2Fnorm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dieselpoint","download_url":"https://codeload.github.com/dieselpoint/norm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dieselpoint%2Fnorm/sbom","scorecard":{"id":341573,"data":{"date":"2025-08-11","repo":{"name":"github.com/dieselpoint/norm","commit":"0626cc7823918dde41c5988c912043b0e3180797"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 4/16 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 18 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T06:00:31.972Z","repository_id":6163326,"created_at":"2025-08-18T06:00:31.972Z","updated_at":"2025-08-18T06:00:31.972Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31586403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["database","java","jdbc","orm","sql"],"created_at":"2025-02-21T00:02:32.829Z","updated_at":"2026-04-09T04:31:49.210Z","avatar_url":"https://github.com/dieselpoint.png","language":"Java","funding_links":[],"categories":["数据库开发"],"sub_categories":[],"readme":"# Norm\n\n[Read a blog post on this project.](https://blog.dieselpoint.com/a-minimalist-good-enough-approach-to-object-relational-mapping-64df9798b276)\n\nNorm is a simple way to access a JDBC database, usually in one line of code. It purges your code of the complex mess that is [Hibernate](http://www.hibernate.org), [JPA](http://en.wikipedia.org/wiki/Java_Persistence_API), and [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping).\n\n[Lots of people think that complex ORMs are a bad idea.](http://stackoverflow.com/questions/398134/what-are-the-advantages-of-using-an-orm/398182)\n\nHere it is:\n\n```Java\nList\u003cPerson\u003e people = db.where(\"name=?\", \"Bob\").results(Person.class);\n```\n\n### Get Started\n\n[Configure your system](#configuration).\n\n[Start with this sample code](#sample-code).\n\n### Overview\n\nNorm is an extremely lightweight layer over JDBC. It gets rid of large amounts of boilerplate JDBC code. It steals some ideas from [ActiveJDBC](http://javalite.io/), which is a very nice system, but requires some very ugly instrumentation / byte code rewriting. \n\n### Why?\n\nSometimes the most important thing about writing software is knowing when to stop. A solution that gets you 90% of the way is often good enough, because the other 90% isn't worth the hassle. In this case, Norm gives you a fast and convenient way to do select, insert, update and delete, and when you need more, you just drop into straight SQL.\n\nNorm returns results as a list of [POJOs](http://en.wikipedia.org/wiki/Plain_Old_Java_Object) or as a `List` of `Map` objects, whichever you prefer.\n\nPOJOs are fabulous, truly fabulous:\n\n* Populating them is really fast with the newer JVMs.\n* You can use them for declaratory data validation.\n* Using [Jackson](https://github.com/FasterXML/jackson), you can serialize them to JSON.\n\nwhich means that, yes, you can use the same class to fetch a record from a database and then create JSON from it.\n\n### Sample Code\n\n[There's a full example here.](https://github.com/dieselpoint/norm/blob/master/src/test/java/com/dieselpoint/norm/SampleCode.java)\n\n```Java\nDatabase db = new Database();\n\nPerson joe = new Person();\njoe.firstName = \"Joe\";\njoe.lastName = \"Sixpack\";\n\ndb.insert(joe);\n\nList\u003cPerson\u003e people = db.where(\"lastname=?\", \"Sixpack\").orderBy(\"lastName\").results(Person.class);\n```\n\nThe `Person` class:\n\n```Java\n@Table(name=\"people\")\nclass Person {\n\tpublic String firstName;\n\tpublic String lastName;\n    // you can also use getters and setters\n}\n```\nYou can modify your database using .insert(), .upsert(), .update(), .delete(), and .sql().execute():\n\n```Java\nint rowsAffected = db.table(\"people\").where(\"firstName=?\", \"Joe\").delete();\n\n// or just:\nint rowsAffected = db.delete(joe);\n\n// rowsAffected will equal the number of rows inserted, updated, or deleted\n\n```\n\nWhen you need more than this, just use straight SQL. This is the best way to do joins:\n\n```Java\nList\u003cMyPojo\u003e list1 = db.sql(\n    \"select lastname, sum(amount) from account, transaction \" +\n    \"where account.accountId = transaction.accountId \" +\n\t\"and date \u003e ?\", \"2000-01-01\")\n\t.results(MyPojo.class);\n```\n\nYou can also use straight SQL to modify the database:\n\n```Java\ndb.sql(\"drop table people\").execute();\n```\n\n### Maps and Lists\n\nDon't want to create a new POJO class for every query? No problem, just use a Map:\n\n```Java\nList\u003cMap\u003e list = db.sql(\"select * from people\").results(HashMap.class);\n```\n\nHashMap, LinkedHashMap or any class that implements the Map interface will work.\n\nNote that you must specify full sql, or at a minimum a table name, because the system won't be able to guess the table name from the Map class. Unless you've annotated it to that effect.\n\n### Primitives\n\nA single column result set can come back in the form of a list of primitives, or even as a single primitive.\n\n```Java\nLong count = db.sql(\"select count(*) from people\").first(Long.class);\n```\n\nIt's sometimes really useful to get a result in the form of a `List\u003cString\u003e`.\n\nNote that you have to specify the full sql when doing primitives because the system won't be able to guess the column or tables names from the primitive class.\n\n\n### Annotations\n\nTell the system what to do with your POJOs by using a few annotations. Norm implements a subset of the `javax.persistence` annotations, including [@Table](http://docs.oracle.com/javaee/7/api/javax/persistence/Table.html), [@Id](http://docs.oracle.com/javaee/7/api/javax/persistence/Id.html), [@GeneratedValue](http://docs.oracle.com/javaee/7/api/javax/persistence/GeneratedValue.html), [@Transient](http://docs.oracle.com/javaee/7/api/javax/persistence/Transient.html), [@Column](http://docs.oracle.com/javaee/7/api/javax/persistence/Column.html) and [@Enumerated](http://docs.oracle.com/javaee/7/api/javax/persistence/Enumerated.html).\n\n```Java\n@Table(name=\"people\")\npublic class Person {\n\t@Id\n\t@GeneratedValue\n\tpublic long personId;\n\n\tpublic String name;\n\n\t@Column(name = \"theColumnName\")\n\tpublic String renameThis;\n\n\t@Transient\n\tpublic String thisFieldGetsIgnored;\n}\n\n```\n\n`@Table` specifies the table name. If it's not there, the table defaults to the class name.\n\n`@Id` specifies the primary key. The system uses this to identify the record to delete or update.\n\n`@GeneratedValue` indicates that the field is marked AUTO_INCREMENT and will be generated on the server. This prevents the field from being inserted, and it fills in the value in the POJO after an insert.\n\n`@Transient` tells the system to ignore the field. It doesn't get persisted to the database. (Note that this is `javax.persistence.Transient`, not `java.beans.Transient`. Different annotations.)\n\n`@Column` implements a subset of `javax.persistence.Column`. `Column.name` will attach a property to a database column of a different name. `Column.unique`, `.nullable`, `.length`, `.precision`, and `.scale` apply when you call `Database.createTable()`;\n\n`@Enumerated` specifies the type of the enumeration to be stored in the database. By default `EnumType.STRING` is used for string representation. One can select `EnumType.ORDINAL` for integer representation.\n\n\nColumn-level annotations can go on either a public property or on a public getter for the property. Annotations on setters will be ignored.\n\n\n### Transactions\n\nIf you need multiple database operations to succeed or fail as a unit, use a transaction. The basic scheme is to create a Transaction object, pass it to every query that needs it, and then .commit() or .rollback().\n\n```Java\nTransaction trans = db.startTransaction();\ntry {\n\tdb.transaction(trans).insert(row1);\n\tdb.transaction(trans).update(row2);\n\ttrans.commit();\n} catch (Throwable t) {\n\ttrans.rollback();\n}\n\n```\nTransaction is a pretty simple class, so if it doesn't do what you need,  just subclass it and make it behave differently.\n\n### Latency Checking\n\nAs data volumes increase and functionality enhancements are made, the calls to your database have a nasty habit of slowing down. For the whole database, or for individual Queries and Transactions, you can specify a max acceptable latency. Database calls exceeding that SLA will be reported via a pluggable LatencyAlerter.\n\n```Java\n // alert with an slf4j log message any call to the database takes \u003e30 milliseconds\ndb.setMaxLatency(30);\ndb.addLatencyAlerter( new Slf4jLatencyAlerter() );\n\n// raise an alert if latency on these queries exceeds \u003e20ms\nvar people = db.where(\"lastname=?\", \"Sixpack\").maxLatency(20).results(Person.class);\ndb.sql(\"select count(*) from people\").maxLatency(20).first(Long.class);\n\n// latency checking also works with Transaction commits\nTransaction trans = db.startTransaction().maxLatency(30);\n\n```\nMore information can be found here: [LatencyChecking.md](LatencyChecking.md)\n\n\n### Custom Serialization\n\n\u003e The older @DbSerializable and @DbSerializer annotations are now deprecated.\n\u003e Use @Converter and an AttributeConverter class instead.\n\nNorm now supports JPA serialization. We'll add a bit more documentation here later, but for\nnow you can learn all about it here:\n\n[https://thoughts-on-java.org/jpa-21-how-to-implement-type-converter/](https://thoughts-on-java.org/jpa-21-how-to-implement-type-converter/)\n\nand here:\n\n[https://www.baeldung.com/jpa-attribute-converters](https://www.baeldung.com/jpa-attribute-converters)\n\nIn short, @Converter give you a way of converting a particular column datatype in your database\nto a particular datatype in your POJO. So, you can store a list of integers in your database\nas String, and in your POJO as List\u0026lt;Integer\u003e.\n\nNote that you can sometimes achieve the same purpose by using appropriate getters and setters on your POJO. Mark the ones that Norm should ignore with @Transient.\n\n\n### Pluggable SQL Flavors\n\nYou can specify the particular flavor of SQL for your database with `Database.setSqlMaker()`. By default, the `StandardSqLMaker` will handle most needs. As of version 0.8.1, there is also a `MySqlMaker` class that will handle MySql-style upserts. To implement your own flavor, subclass `StandardSqlMaker` and possibly `StandardPojoInfo` and do what you need.\n\n```Java\nDatabase db = new Database();\ndb.setSqlMaker(new MySqlMaker());\n```\nSome database-specific notes:\n\nMySQL: Should work out of the box.\n\nPostgres: Inexplicably, Postgres converts all column names to lowercase when you create a table, and\nforces you to use double quotes around column names if you want mixed or upper case. The workaround\nis to add an @Column(name=\"somelowercasename\") annotation to the fields in your pojo.\n\nH2: Does the opposite of Postgres. It forces all column names to upper case. Avoid the problem by\nadding the database_to_upper option to the jdbcUrl: `jdbc:h2:./h2test;database_to_upper=false`\n\n\n\n### Configuration\nHere's the Maven dependency:\n\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.dieselpoint\u003c/groupId\u003e\n    \u003cartifactId\u003enorm\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.5\u003c/version\u003e\n\u003c/dependency\u003e\n```  \n\nTo specify the database connection parameters:\n\n```Java\nDatabase db = new Database();\ndb.setJdbcUrl(\"jdbc:mysql://localhost:3306/mydb?useSSL=false\");\ndb.setUser(\"root\");\ndb.setPassword(\"rootpassword\");\n```\n\nor\n\n```Java\nSystem.setProperty(\"norm.jdbcUrl\", \"jdbc:mysql://localhost:3306/mydb?useSSL=false\");\nSystem.setProperty(\"norm.user\", \"root\");\nSystem.setProperty(\"norm.password\", \"rootpassword\");\n```\n\nInternally, Norm uses the [Hikari](http://brettwooldridge.github.io/HikariCP/) connection pool. Hikari allows you to use the jdbcUrl method or [DataSource class names](https://github.com/brettwooldridge/HikariCP#popular-datasource-class-names). Your database is bound to be on the list.\n\nIf you don't want to use system properties, or your DataSource needs some custom startup parameters, just subclass the [Database](https://github.com/dieselpoint/norm/blob/master/src/main/java/com/dieselpoint/norm/Database.java) class and override the .getDataSource() method. You can supply any DataSource you like.\n\n### Dependencies\nNorm needs javax.persistence, but that's just for annotations.\n\nIt also has a dependency on HikariCP for connection pooling, but that's entirely optional. If you don't want it, add an `\u003cexclude\u003e`  to the Norm dependency in your project's pom. Then subclass Database and override the getDataSource() method.\n\nFinally, you'll need to include your JDBC driver as a dependency. Here's a sample for MySQL:\n\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003emysql\u003c/groupId\u003e\n    \u003cartifactId\u003emysql-connector-java\u003c/artifactId\u003e\n    \u003cversion\u003e8.0.15\u003c/version\u003e\n\u003c/dependency\u003e\n```  \n\n****\n\nThat's about it. Post any bugs or feature requests to the issue tracker.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdieselpoint%2Fnorm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdieselpoint%2Fnorm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdieselpoint%2Fnorm/lists"}