{"id":15069817,"url":"https://github.com/stardogventures/stardao","last_synced_at":"2026-03-11T06:32:32.393Z","repository":{"id":37270854,"uuid":"79784019","full_name":"stardogventures/stardao","owner":"stardogventures","description":"Simple base DAO classes for MongoDB and DynamoDB","archived":false,"fork":false,"pushed_at":"2023-06-14T22:45:21.000Z","size":236,"stargazers_count":11,"open_issues_count":5,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-23T07:07:53.772Z","etag":null,"topics":["autovalue","dao","data-access-object-pattern","dropwizard","dynamodb","hibernate-validator","jackson","java","java8","jersey","mongodb","pojo"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stardogventures.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":"2017-01-23T08:16:26.000Z","updated_at":"2025-05-20T23:23:24.000Z","dependencies_parsed_at":"2024-10-13T04:00:45.501Z","dependency_job_id":"c69db119-f6d1-4b53-a614-4de3170d46ff","html_url":"https://github.com/stardogventures/stardao","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/stardogventures/stardao","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stardogventures%2Fstardao","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stardogventures%2Fstardao/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stardogventures%2Fstardao/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stardogventures%2Fstardao/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stardogventures","download_url":"https://codeload.github.com/stardogventures/stardao/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stardogventures%2Fstardao/sbom","scorecard":{"id":846292,"data":{"date":"2025-08-11","repo":{"name":"github.com/stardogventures/stardao","commit":"7ea2e6d4916eb2a44bd31baadec841199d49bab7"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"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":"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":"Code-Review","score":0,"reason":"Found 2/26 approved changesets -- score normalized to 0","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":"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":"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":"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":"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":"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":"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":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 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"}},{"name":"Vulnerabilities","score":0,"reason":"67 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-vmq6-5m68-f53m","Warn: Project is vulnerable to: GHSA-668q-qrv7-99fm","Warn: Project is vulnerable to: GHSA-6v67-2wr5-gvf4","Warn: Project is vulnerable to: GHSA-pr98-23f8-jwxv","Warn: Project is vulnerable to: GHSA-h46c-h94j-95f3","Warn: Project is vulnerable to: GHSA-wf8f-6423-gfxg","Warn: Project is vulnerable to: GHSA-27xj-rqx5-2255","Warn: Project is vulnerable to: GHSA-288c-cq4h-88gq","Warn: Project is vulnerable to: GHSA-4w82-r329-3q67","Warn: Project is vulnerable to: GHSA-57j2-w4cx-62h2","Warn: Project is vulnerable to: GHSA-58pp-9c76-5625","Warn: Project is vulnerable to: GHSA-5949-rw7g-wx7w","Warn: Project is vulnerable to: GHSA-5p34-5m6p-p58g","Warn: Project is vulnerable to: GHSA-5r5r-6hpj-8gg9","Warn: Project is vulnerable to: GHSA-5ww9-j83m-q7qx","Warn: Project is vulnerable to: GHSA-6fpp-rgj9-8rwc","Warn: Project is vulnerable to: GHSA-758m-v56v-grj4","Warn: Project is vulnerable to: GHSA-85cw-hj65-qqv9","Warn: Project is vulnerable to: GHSA-89qr-369f-5m5x","Warn: Project is vulnerable to: GHSA-8c4j-34r4-xr8g","Warn: Project is vulnerable to: GHSA-8w26-6f25-cm9x","Warn: Project is vulnerable to: GHSA-95cm-88f5-f2c7","Warn: Project is vulnerable to: GHSA-9gph-22xh-8x98","Warn: Project is vulnerable to: GHSA-9m6f-7xcq-8vf8","Warn: Project is vulnerable to: GHSA-9vvp-fxw6-jcxr","Warn: Project is vulnerable to: GHSA-c265-37vj-cwcc","Warn: Project is vulnerable to: GHSA-c2q3-4qrh-fm48","Warn: Project is vulnerable to: GHSA-c8hm-7hpq-7jhg","Warn: Project is vulnerable to: GHSA-cf6r-3wgc-h863","Warn: Project is vulnerable to: GHSA-cmfg-87vq-g5g4","Warn: Project is vulnerable to: GHSA-cvm9-fjm9-3572","Warn: Project is vulnerable to: GHSA-f3j5-rmmp-3fc5","Warn: Project is vulnerable to: GHSA-f9hv-mg5h-xcw9","Warn: Project is vulnerable to: GHSA-f9xh-2qgp-cq57","Warn: Project is vulnerable to: GHSA-fmmc-742q-jg75","Warn: Project is vulnerable to: GHSA-fqwf-pjwf-7vqv","Warn: Project is vulnerable to: GHSA-gjmw-vf9h-g25v","Warn: Project is vulnerable to: GHSA-gwp4-hfv6-p7hw","Warn: Project is vulnerable to: GHSA-gww7-p5w4-wrfv","Warn: Project is vulnerable to: GHSA-h3cw-g4mq-c5x2","Warn: Project is vulnerable to: GHSA-h4rc-386g-6m85","Warn: Project is vulnerable to: GHSA-h822-r4r5-v8jg","Warn: Project is vulnerable to: GHSA-j823-4qch-3rgm","Warn: Project is vulnerable to: GHSA-jjjh-jjxp-wpff","Warn: Project is vulnerable to: GHSA-m6x4-97wx-4q27","Warn: Project is vulnerable to: GHSA-mc6h-4qgp-37qh","Warn: Project is vulnerable to: GHSA-mph4-vhrx-mv67","Warn: Project is vulnerable to: GHSA-mx7p-6679-8g3q","Warn: Project is vulnerable to: GHSA-mx9v-gmh4-mgqw","Warn: Project is vulnerable to: GHSA-p43x-xfjf-5jhr","Warn: Project is vulnerable to: GHSA-q93h-jc49-78gg","Warn: Project is vulnerable to: GHSA-qjw2-hr98-qgfh","Warn: Project is vulnerable to: GHSA-qmqc-x3r4-6v39","Warn: Project is vulnerable to: GHSA-r3gr-cxrf-hg25","Warn: Project is vulnerable to: GHSA-r695-7vr9-jgc2","Warn: Project is vulnerable to: GHSA-rf6r-2c4q-2vwg","Warn: Project is vulnerable to: GHSA-rgv9-q543-rqg4","Warn: Project is vulnerable to: GHSA-rpr3-cw39-3pxh","Warn: Project is vulnerable to: GHSA-v3xw-c963-f5hc","Warn: Project is vulnerable to: GHSA-v585-23hc-c647","Warn: Project is vulnerable to: GHSA-vfqx-33qm-g869","Warn: Project is vulnerable to: GHSA-wh8g-3j2c-rqj5","Warn: Project is vulnerable to: GHSA-h4x4-5qp2-wp46","Warn: Project is vulnerable to: GHSA-5mg8-w23w-74h3","Warn: Project is vulnerable to: GHSA-7g45-4rm6-3mm3","Warn: Project is vulnerable to: GHSA-2qp4-g3q3-f92w","Warn: Project is vulnerable to: GHSA-cqj8-47ch-rvvq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T21:31:27.815Z","repository_id":37270854,"created_at":"2025-08-23T21:31:27.815Z","updated_at":"2025-08-23T21:31:27.815Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30373475,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-11T06:09:32.197Z","status":"ssl_error","status_checked_at":"2026-03-11T06:09:17.086Z","response_time":84,"last_error":"SSL_read: 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":["autovalue","dao","data-access-object-pattern","dropwizard","dynamodb","hibernate-validator","jackson","java","java8","jersey","mongodb","pojo"],"created_at":"2024-09-25T01:44:51.431Z","updated_at":"2026-03-11T06:32:32.355Z","avatar_url":"https://github.com/stardogventures.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Stardao\n\nSimple immutable-friendly base DAO classes for MongoDB and DynamoDB\n\n## Why use this?\n\nThese Data Access Object (DAO) superclasses are a good choice if:\n\n  - You want clean separation between your business logic and your DAO, mapping data to POJOs\n  - *But* within your DAOs, you want to hand-code your data access, and don't want a heavy abstraction layer adding indirection between you and the full features of the database\n  - **But** you don't want to have to hand-roll basic CRUD operations for every new DAO\n\nYou also might like these DAO superclasses if:\n\n  - You favor immutable data model POJOs, such as those generated by AutoValue\n  - You are switching back and forth between MongoDB and DynamoDB and want a common idiom\n  - You're using Dropwizard, or something else that uses Jersey and Jackson\n  - You want a good way to handle partial updates (PATCH requests) coming from users\n  - You want to easily set the user id and timestamp on creation and update\n\n## How To Use Stardao\n\n### Installation\n\nTo use Stardao, add the following to your project's POM file:\n\n```\n\u003cproperties\u003e\n    \u003cstardao.version\u003e0.3.4\u003c/stardao.version\u003e\n    ...\n\u003c/properties\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.stardog.stardao\u003c/groupId\u003e\n    \u003cartifactId\u003estardao-core\u003c/artifactId\u003e\n    \u003cversion\u003e${stardao.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n  ...\n\u003c/dependencies\u003e\n```\n\nThen add any of the following modules you want to use. If you are using DynamoDB:\n\n```\n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.stardog.stardao\u003c/groupId\u003e\n    \u003cartifactId\u003estardao-dynamodb\u003c/artifactId\u003e\n    \u003cversion\u003e${stardao.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n```\n\nIf you're using MongoDB:\n\n```\n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.stardog.stardao\u003c/groupId\u003e\n    \u003cartifactId\u003estardao-dynamodb\u003c/artifactId\u003e\n    \u003cversion\u003e${stardao.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n```\n\nIf you want to use the `@AutoPartial` feature for automatically generating Partial entity classes:\n\n```\n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.stardog.stardao\u003c/groupId\u003e\n    \u003cartifactId\u003estardao-auto\u003c/artifactId\u003e\n    \u003cversion\u003e${stardao.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n```\n\nIf you're using Jersey:\n\n```\n  \u003cdependency\u003e\n    \u003cgroupId\u003eio.stardog.stardao\u003c/groupId\u003e\n    \u003cartifactId\u003estardao-jersey\u003c/artifactId\u003e\n    \u003cversion\u003e${stardao.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n```\n\n### Define POJOs\n\nDefine your basic POJO entity model classes however you like. They can be immutable or not, as you prefer. The classes must be capable of being de/serialized with [Jackson](https://github.com/FasterXML/jackson), and they must use getters for field access.\n\nThe classes can be subclasses, but they should not derive fields from parents (the class hierarchy will not be examined for annotations).\n\nPersonally, the author prefers using [AutoValue](https://github.com/google/auto/blob/master/value/userguide/index.md) with builders, but it's up to you.\n\n### Annotations\n\nPlace your annotations over the getter methods. All annotations are optional, but you should normally use `@Id`. If `@Id` is not present, but a `getId()` method is present, Stardao will assume that that's the id.\n\n- ``@Id`` - mark the primary key\n- ``@CreatedAt`` - field will be timestamped on creation\n- ``@CreatedBy`` - field will be marked with the id of user who created it\n- ``@UpdatedAt`` - field will be timestamped on update\n- ``@UpdatedBy`` - field will be marked with the id of the user who updated\n- ``@Updatable`` - marks a field as permissible to change in a user-generated partial update. For example, for a user, `email` might take updates, but `lastLoginTime` might not\n- ``@Creatable`` - marks a field as permissible to set on creation, but not on an update\n- ``@StorageName(\"name\")`` - store a field under a different name in the database\n\nYou are also encouraged to use Hibernate Validator annotations, such as `@Email` or `@Min`.\n\n### Use @AutoPartial to generate partials\n\nWhile it's not required, you can set up your Dao to make a distinction between the base entity model class, and a supporting model class called a `Partial`. Partials are like entities, except every single field on them is an `Optional`. For example, if you have a `User` class, you might have a `PartialUser` to go with it.\n\nThis frees you to make all your required fields non-Nullable and non-Optional, on the base entity class. When you pass around and interact with a `User`, you can be certain that none of the required fields are null, and set up the non-required fields as `Optional`s.\n\nSo what are Partials useful for?\n  - **Updates:** when performing partial updates, you usually only want to pass in the specific fields you intend to update. This idea is much better represented by a Partial than an entity.\n  - **Creates:** when creating an entity, usually the caller omits the primary key id (letting the database generate the id). However, the id must exist on all of your entities after they're created. The same is usually true of created-by/created-at fields. So as long as it gets validated to ensure it's not missing any required fields, a Partial is a better way to pass in the initial data.\n  - **Limited views:** sometimes you want to expose a view of an object, for a particular user, that has certain sensitive fields omitted. Or for performance/memory reasons, you only want to retrieve a couple of the fields from the database. Partials are a good way to represent these views.\n  \nPartials can't derive from the base class, since the methods have different signatures. So while you could write Partials yourself, you'd be violating DRY pretty badly. Fortunately, Stardao has a solution, inspired by Google's AutoValue. To automatically generate Partials, just include the `stardao-auto` module, and add `@AutoPartial` to your entity class.\n\nStardao will automatically generate a `PartialEntityname` class to go with your entity. This leverages AutoValue and will therefore be immutable. It uses builders, with no prefix on the setter methods. You can also convert a regular entity into a partial with `PartialEntityname.of(entity)`.\n\n### Define Your Dao\n\nExtend either the `AbstractMongoDao` or `AbstractDynamoDao` superclass. The type parameters are, in order:\n\n- `M`: Model Class\n- `P`: Partial Model Class (can be the same as the Model Class, if you don't want to use partials)\n- `K`: Primary key type (type of the `@Id` field)\n- `I`: User-id foreign key type (type of the `@CreatedBy` and `@UpdatedBy` fields)\n\nFor example, if you have a MongoDB collection called `org` to track organizations, that uses `Org` as the model class, `PartialOrg` as the partial model class, `Long `as the org `_id` and `ObjectId` as the associated user id type:\n\n```\npublic class OrgDao extends AbstractMongoDao\u003cOrg,PartialOrg,Long,ObjectId\u003e {\n```\n\n### Write a constructor\n\nTypically the constructor takes the appropriate connection object from the driver and calls the superclass. For example, for MongoDB:\n\n```\npublic class OrgDao extends AbstractMongoDao\u003cOrg,PartialOrg,Long,ObjectId\u003e {\n    public OrgDao(MongoDatabase db) {\n        super(Org.class, PartialOrg.class, db.getCollection(\"org\"));\n    }\n```\n\nFor DynamoDB:\n\n```\npublic class OrgDao extends AbstractDynamoDao\u003cOrg,PartialOrg,Long,UUID\u003e {\n    public OrgDao(DynamoDB db) {\n        super(Org.class, PartialOrg.class, db, \"org\");\n    }\n```\n\n### What you get for free\n\nEvery Dao automatically comes with the following public methods:\n\n- ``M load(K id)`` - loads an object and throws a DataNotFoundException (a runtime exception) if it's not found\n- ``Optional\u003cM\u003e loadOpt(K id)`` - loads an object as an Optional\n- ``M create(P partial, [I createdBy])`` - creates a new object\n- ``void update(K id, Update\u003cP\u003e update[, I updatedBy])`` - perform a partial update\n- ``M updateAndReturn(K id, Update\u003cP\u003e update[, I updatedBy])`` - perform an update and return the object prior to modification\n- ``void delete(K id)`` - delete an object by id\n- ``Iterable\u003cM\u003e iterateAll()`` - iterate through the whole table\n- ``initTable()`` - initialize the table and ensure indexes (never destructive of data)\n- ``dropTable()`` - drop the whole table\n\n### Write your methods\n\nWith the boring CRUD out of the way, write methods specific to the model -- for example, you might use the conventions:\n\n- ``loadByX`` queries that return an object by fields other than the id\n- ``findByX`` queries that return ``Results\u003cM,K\u003e`` objects\n- ``updateX`` methods that perform various updates\n- Anything else you want -- the above are just suggestions\n\nThe two superclasses (`AbstractDynamoDao` and `AbstractMongoDao`) have some different protected methods that you can use to simplify writing queries.\n\nBoth superclasses have a mapper for transforming the model classes into the specific document type for the database (an ItemMapper for DynamoDB and a DocumentMapper for Mongo) which you can get at with a call to `getModelMapper()` and `getPartialMapper()`. You can convert the database-returned objects to your POJO with `getModelMapper().toObject(databaseObject)`\n\n### Where's save()?\n\nIn the author's opinion, a save() (which typically overwrites the whole object), is fairly dangerous, and should be avoided in favor of partial updates, which are more performant and avoid potential race conditions.\n\nOf course, if you want to add a save() to your Dao subclasses, nothing's stopping you from writing one.\n\n### What about arbitrary queries?\n\nAgain purely in the author's opinion, all queries should be hand-written and live within the DAO. A codebase that allows any caller throughout the application to make any arbitrary queries -- especially arbitrary queries whose impact on the underlying storage layer are not fully understood -- is a dangerous codebase.\n\nThe author is also not fond of layering a special query syntax or DSL on top of the native driver. These tend to just add indirection, and the native syntax is usually just as easy to learn.\n\nSo you are advised to simply write findX methods on your subclass, using the specific functionality of the native drivers.\n\n## Validation\n\nThe ``ModelValidator`` class provides a convenient shortcut to Hibernate Validation that allows you to easily validate your models, especially as passed in from JAX-RS endpoints.\n\n- `validateModel()` validates every field present on the model, without regard for which ones are optional, updatable, or creatable\n- `validateCreate()` validates the fields present on a model, ensuring that it is a valid user-submitted creation. Specifically that:\n  - only `@Updatable` or `@Creatable` fields are present\n  - all non-optional `@Updatable` and `@Creatable` fields are present\n  - all present fields pass validation\n- `validateUpdate()` validates an `Update`, ensuring that:\n  - the `Update` is only touching `@Updatable` fields\n  - the `Update` is not unsetting any non-optional fields\n  - all fields being set pass validation\n\nIn each case the validate method will throw a runtime `DataValidationException` if it fails, and return true if it succeeds.\n\nYou should probably inject a `ModelValidator` instance, but for convenience, there is a static `DefaultModelValidator` that implements the methods.\n\n## Using with Jersey / Dropwizard: Partial Updates\n\nThe `Update\u003cP\u003e` object comes with a Jackson deserializer, so you can include it as the body for PATCH requests.\n\nA simple update resource method might look like:\n\n```java\n@PATCH\n@Path(\"/org/{id}\")\npublic Response updateOrg(@Auth User user, @PathParam(\"id\") ObjectId id, Update\u003cPartialOrg\u003e update) {\n    DefaultValidator.validateUpdate(update, orgDao);\n    // perform ACL checks here...\n    orgDao.update(id, update, user.getId());\n    return Response.noContent().build();\n}\n```\n\nIf a user PATCHes a request like this:\n\n```\n/v1/org/123\n{\"name\":\"Stardog Ventures\",\"email\":null}\n```\n\nIt will be interpreted as a request to set the `name` field to `Stardog Ventures`, and unset the `email `field. Other fields will not be changed. The whole request will only be allowed if both name and email are marked `@Updatable`.\n\nEmpty strings also will be treated as a request to unset fields.\n\n## Using with Jersey / Dropwizard: Exception Mapper\n\nYou probably want to register the Stardao-specific exception modelMapper classes with Jersey. `DataValidationExceptionMapper` in particular provides a friendly 400 which contains all the errors for extraction.\n\n```java\nenv.jersey().register(new DataNotFoundExceptionMapper());\nenv.jersey().register(new DataValidationExceptionMapper());\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstardogventures%2Fstardao","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstardogventures%2Fstardao","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstardogventures%2Fstardao/lists"}