{"id":15958801,"url":"https://github.com/koooooo-7/kchain","last_synced_at":"2026-02-08T07:06:04.439Z","repository":{"id":52885171,"uuid":"328697851","full_name":"Koooooo-7/KChain","owner":"Koooooo-7","description":":nut_and_bolt: A flexible and configurable check chain.","archived":false,"fork":false,"pushed_at":"2024-08-17T06:02:57.000Z","size":101,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-14T14:26:57.015Z","etag":null,"topics":["chain","configurable","filter","flexible","java","java8-lambda-expression","validator"],"latest_commit_sha":null,"homepage":"https://github.com/Koooooo-7/KChain","language":"Java","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/Koooooo-7.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":"2021-01-11T14:53:59.000Z","updated_at":"2022-03-25T11:20:25.000Z","dependencies_parsed_at":"2024-08-17T07:30:17.112Z","dependency_job_id":null,"html_url":"https://github.com/Koooooo-7/KChain","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Koooooo-7%2FKChain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Koooooo-7%2FKChain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Koooooo-7%2FKChain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Koooooo-7%2FKChain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Koooooo-7","download_url":"https://codeload.github.com/Koooooo-7/KChain/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221701691,"owners_count":16866220,"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":["chain","configurable","filter","flexible","java","java8-lambda-expression","validator"],"created_at":"2024-10-07T14:20:47.262Z","updated_at":"2026-02-08T07:06:04.414Z","avatar_url":"https://github.com/Koooooo-7.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# KChain\n---\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://codecov.io/gh/Koooooo-7/KChain\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/Koooooo-7/KChain/branch/main/graph/badge.svg?token=URSIFCIfsY\"/\u003e\n\u003c/a\u003e\n\u0026nbsp;\n\u003ca href=\"https://travis-ci.com/Koooooo-7/KChain.svg?branch=main\"\u003e\n    \u003cimg src=\"https://travis-ci.com/Koooooo-7/KChain.svg?branch=main\"/\u003e\n\u003c/a\u003e\n\u0026nbsp;\n\u003ca href=\"https://opensource.org/licenses/MIT\" rel=\"nofollow\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/License-MIT-brightgreen.svg\" alt=\"License\" style=\"max-width:100%;\"\u003e\n\u003c/a\u003e\n\u0026nbsp;\n\u003ca href=\"https://opensource.org/licenses/MIT\" rel=\"nofollow\"\u003e\n\u003cimg src=\"https://img.shields.io/badge/Java-JDK8%2B-orange\" alt=\"jdk8+\"\u003e \n\u003c/a\u003e\n\u003c/p\u003e\n\n**English | [中文](README.zh.md)**\n\n\u003e :nut_and_bolt: *`KChain`, a flexible and configurable chain.*\t\n\n---\n\n## What is the problem\n\n\nSometimes, we will face a situations that we need to check various `properties set` such as `Map\u003cString,Object\u003e` or `Entity` entities ( named it as `properties set`).\n\nObviously, there will be one or more different verification rules for different properties.\n\nSo, it is necessary to have a `chain` structure to solve those problems.\n\n`KChain` is an implementation to solve these problems.\n\n\n\n\nThe following two dimensions are usually considered:\n\n**Check Properties**\n\n- For a single `properties set`, such as `Map\u003cString,Object\u003e`\n\n​       It needs to check whether its different properties match one or more rules. \n\n​       For example, the value of  the key called`name` in a `Map\u003cString,Object\u003e` can not be empty.\n\n  \n\n- For batch of `perperties set` , such as `List\u003cUser\u003e`\n\n​      It is necessary to check whether they meet certain rules with each other.\n\n​      For example, such as *the same name of `User`* can not exist in the batch of `User` set.\n\n\n\n**Rule Strategy** \n\n- Fail fast   \n\n  When one of the rule conditions is not met, return directly. \n\n- Full check  \n\n  Running all the verification rules, verify all the rule items for its perperties.\n\n  \n\n---\n\n## How to solve it\n\nThere are some components which play an important role in `KChain`.\n\n- `ChainContext`\n\n  The context for the `chain` which can hold the information you wanna use in the whole chain life circle.\n  Build in the `cache` and `inheritable cache` expired in the current chain test life circle.\n  Such as some global parameters or special symbol.\n\n  \n\n- `DataWrapper`\n\n   Wrapping the `properties set` and the `Rulecontext` together.\n\n  \n\n- `RuleContext`\n\n   It is used to store the check result and the return flag bit of `Predicate` based on different check strategies.\n\n  \n\n- `Rule`\n\n   It contains some rules for checking.\n\n   There are three built-in rules for now:\n\n   - `testNotEmpty`，whether the perperty value is empty based on the rule.\n\n   - `testInCases`，whether the perperty value is in the given collection (` contains`).\n\n   - `testOnCustomized`，the fully customized implementation  rule extension.\n\n    \n\n- `RuleStrategy`\n\n  The check strategy.\n\n  - `FULL_CHECK`\n\n  - `FAIL_FAST ` \n\n     It is usually used to check a single `perperties set` to quickly know whether the `perperties set` is valid.\n  \n    \n  \n- `IChain`\n\n  The interface of chain，build-in:\n\n  - `Predicate`\n\n    `test()`\n\n  ​ Mainly for the verification of a single `properties set`, the verification rule of each property in the `perperties set` can be configured.\n  \n\n  - `Function`\n  \n    `apply()`\n    \n    Mainly for the verification of batch of `properties set`, the verification rule of  the property between each ` perperties set` can be configured.\n    \n    Build in the `duplicate rule `.\n    \n    \n\n\n- `ChainBuiler`  \n​  Build the chain to use, build in.\n\n---\n\n## How to use it\n\n\u003e All the basic usage you can find in`demo/App.java`.\n\u003e\n\u003e You can expand as much as you want, no matter the `Rule`, or the  implementations of getting property value.\n\n\n\nRequests  **JDK8+**, the core is using the `@FunctionalInterface`.\n\n**Import**\n- Maven  \n  It has been published in `Github Packages`, you can import it directly, more details see the [packages](https://github.com/Koooooo-7?tab=packages\u0026repo_name=KChain).\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003ecom.koy\u003c/groupId\u003e\n   \u003cartifactId\u003ekchain\u003c/artifactId\u003e\n   \u003cversion\u003e${latest.version}\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\n\n### Demo\n\n---\n\n### `Map`\n\nSuppose that we need to verify the `name` and `age`  in `map`. The rules are as follows:\n\n**In Single `Map`**\n\n- `name` cannot empty\n- `age`can not empty\n- `age` should in the cases\n\n**In Map Collections**\n\n- `name` cannot duplicate in collections\n\n- `age` cannot duplicate in collections\n\n\n\n#### Build the single properties set chain\n\n- `name` cannot empty\n- `age` cannot empty\n- `age` should in `[1,2,3,4,5]`\n\n```java\n    @Override\n    public Predicate\u003cMapDataWrapper\u003e getPredicateChain(ChainContext ctx) {\n        return Rule.NOT_EMPTY.\u003cMapDataWrapper\u003etestNotEmpty(\"name\"\n                , testEmptyRule(\"name\")\n                , resultProcessor(\"name\", CheckResultCode.NOT_EMPTY))\n                .and(Rule.NOT_EMPTY.testNotEmpty(\"age\"\n                        , testEmptyRule(\"age\")\n                        , resultProcessor(\"age\", CheckResultCode.NOT_EMPTY)\n                ))\n                .and(Rule.IN_CASES.testInCases(\"age\",\n                        CommonTestComponents.testInCasesRule(dataWrapper -\u003e Integer.valueOf(dataWrapper.getString(\"age\"))\n                                , Arrays.asList(1, 2, 3, 4, 5))\n                        , resultProcessor(\"age\", CheckResultCode.IN_CASES)\n                ));\n\n    }\n```\n\n\n\n#### Build the batch properties sets chain\n\n- `name`  cannot duplicated in batch of properties sets\n- `age`cannot duplicated in batch of properties sets\n\n```java\n    @Override\n    public Function\u003cList\u003cMapDataWrapper\u003e, List\u003cMapDataWrapper\u003e\u003e getFunction(ChainContext ctx) {\n        return CommonTestComponents.\u003cMapDataWrapper\u003etestDuplicatedInCollection(ctx\n                , \"name\"\n                , dataWrapper -\u003e true, dataWrapper -\u003e dataWrapper.getString(\"name\"))\n                .andThen(testDuplicatedInCollection(ctx\n                        , \"age\"\n                        , dataWrapper -\u003e true\n                        , dataWrapper -\u003e dataWrapper.getString(\"age\")));\n    }\n```\n\n\n\n\n\n#### Usage\n\n```java\n public static void demoOnMapBuilder(List\u003cHashMap\u003cString, Object\u003e\u003e maps) {\n        // Wrap data to DataWrapper\n        List\u003cMapDataWrapper\u003e mapDataWrappers = Lists.newArrayListWithCapacity(2);\n        for (HashMap\u003cString, Object\u003e map : maps) {\n            MapDataWrapper mapDataWrapper = new MapDataWrapper(map, new MapRuleContext(RuleStrategy.FULL_CHECK));\n            mapDataWrappers.add(mapDataWrapper);\n        }\n\n        // Build the chain with FULL_CHECK strategy\n        Chain\u003cMapDataWrapper, List\u003cMapDataWrapper\u003e\u003e chain = ChainBuilder.newBuilder()\n                .setChainContext(new ChainContext(RuleStrategy.FULL_CHECK))\n                .setChain(new MapPropertiesCheckChain())\n                .build();\n\n        // Verify the property in the map\n        // There use 6 threads execute it to make it speeder\n        chain.test(mapDataWrappers);\n\n        // Verify the rules between batch properties sets\n        chain.apply(mapDataWrappers);\n\n        // Show the result\n        for (MapDataWrapper mapDataWrapper : mapDataWrappers) {\n            System.out.println(mapDataWrapper.getRuleContext().getResult().toString());\n        }\n\n    }\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoooooo-7%2Fkchain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkoooooo-7%2Fkchain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkoooooo-7%2Fkchain/lists"}