{"id":34289178,"url":"https://github.com/eclecticlogic/pedal-loader","last_synced_at":"2025-12-17T01:47:59.709Z","repository":{"id":25212715,"uuid":"28636767","full_name":"eclecticlogic/pedal-loader","owner":"eclecticlogic","description":"Groovy DSL driven database data loading and dbunit on steroids.","archived":false,"fork":false,"pushed_at":"2016-08-19T15:19:34.000Z","size":92,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-16T07:32:29.253Z","etag":null,"topics":["dbunit","dsl","groovy","java","test"],"latest_commit_sha":null,"homepage":"http://www.eclecticlogic.com/pedal-loader","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/eclecticlogic.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}},"created_at":"2014-12-30T16:07:07.000Z","updated_at":"2023-11-10T09:26:34.000Z","dependencies_parsed_at":"2022-08-23T21:20:35.636Z","dependency_job_id":null,"html_url":"https://github.com/eclecticlogic/pedal-loader","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/eclecticlogic/pedal-loader","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclecticlogic%2Fpedal-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclecticlogic%2Fpedal-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclecticlogic%2Fpedal-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclecticlogic%2Fpedal-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eclecticlogic","download_url":"https://codeload.github.com/eclecticlogic/pedal-loader/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eclecticlogic%2Fpedal-loader/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27774749,"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","status":"online","status_checked_at":"2025-12-16T02:00:10.477Z","response_time":57,"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":["dbunit","dsl","groovy","java","test"],"created_at":"2025-12-17T01:47:58.858Z","updated_at":"2025-12-17T01:47:59.702Z","avatar_url":"https://github.com/eclecticlogic.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"pedal-loader\n============\n\nA Groovy DSL for data loading that is particularly suited for database unit-testing. The load scripts work at the JPA entity level (not database columns and values but JPA entity properties and higher-level types). \n\n## Getting started\n\nDownload the pedal-loader jar from Maven central:\n\n```\n\t\u003cgroupId\u003ecom.eclecticlogic\u003c/groupId\u003e\n\t\u003cartifactId\u003epedal-loader\u003c/artifactId\u003e\n\t\u003cversion\u003e1.0.2\u003c/version\u003e\n```\n\nMinimum dependencies that you need to provide in your application:\n\n1. slf4j (over logback or log4j) v1.7.7 or higher\n2. Spring boot jpa edition or\n4. hibernate-core and hibernate-entitymanager 4.3 or higher.\n5. JDBC4 compliant driver.\n6. groovy-all.jar 2.3 or above\n\n\n### Configuration \n\n#### Vanilla setup\n\nFor classpath-based loading, create an instance of `Loader` (concrete class `com.eclecticlogic.pedal.loader.impl.LoaderImpl`) and give it a reference to an `EntityManager`.  For filesystem-based loading, create an instance of `com.eclecticlogic.pedal.loader.impl.FileSystemLoaderImpl` instead of `com.eclecticlogic.pedal.loader.impl.LoaderImpl`.\n\n#### Spring \n\nIf you are using @ComponentScan, include the `com.eclecticlogic.pedal.loader` package in the packages to be scanned. If you are using a Spring managed unit test, setup your test as shown below:\n\n```\n     @RunWith(SpringJUnit4ClassRunner.class)\n     @SpringApplicationConfiguration(classes = JpaConfiguration.class)\n     public class MyDatabaseTest {\n\n    \t@Autowired\n    \tprivate Loader loader;\n\n\n\t    @Test\n    \t@Transactional\n\t    public void myTest() {\n            Map\u003cString, Object\u003e variables = loader //\n                .withScriptDirectory(\"\u003cdirectory-with-scripts\u003e\") // Classpath resource dir\n                .load(\"script-reference\"); \n            ...\n        }\n    }\n```\n  \n \n## Data Loading\n\nThe pedal data loader is accessed via the Loader interface. Create your load script as one or more groovy scripts in your classpath.\n\nThe Loader interface provides a number of methods to specify your script and input variables for the script. Here are some ways to launch the script:\n\n```\n    loader.withScriptDirectory(\"myScripts\").load(\"basicdata.groovy\");\n```\nThis specifies that the loader should read the script basicdata.groovy contained within a classpath or filesystem directory called myScripts. The file could just as well have been specified with the directory as `myScripts\\basicdata.groovy`. However, the withScriptDirectory allows you to setup a well known directory and have all other calls simply reference the script by name without worry about relative paths.\n\n### Script Format\n\nThe scripts are simple groovy files. To insert rows into a table, use the table() method. The method takes two parameters and a closure:\n\n1. Class reference of JPA entity\n2. List of attributes names you want to populate.\n\nThe method returns a list of entities created in the closure.\n\nThe table method should have a closure should have one more more row lines:\n\n```\n   rowsCreated = table(MyEntity, ['id', 'name', 'age']) {\n\trow value1, value2, value3 ...\n    row value1, value2, value3 ....\n   }\n```\n\nThe values are what you'd populate in the JPA entity, not in the database. So for a foreign key, you'd pass the @JoinColumn object. For a character field mapped to an Enum, you'd pass the actual Enum\n\nHere is an example of a simple script to populate a table and then a child table (i.e., JPA entities called School and Student):\n\n```\n\timport com.test.School\n    import com.test.Student\n\timport com.test.SchoolType\n    import com.test.Gender\n\n\ttable(School, ['name', 'type', 'address']) {\n\t\trow 'Lee Elementary', SchoolType.ELEMENTARY, '1 Lee Rd'\n\t\trow 'Park View School', SchoolType.MIDDLE, '10 Elm Street'\n\t\thighSchool = row 'Mountain Top High', SchoolType.HIGH, '12 Dream Street'\n\t} \n\n\tprintln highSchool.id\n\n    myStudents = table(Student, ['name', 'gender', 'school']) {\n\t\trow 'Joe Schmuckately', Gender.MALE, highSchool\n    }\n\n    // myStudents is a list of all the rows created.\n\n\tfind(Student, 1)\n```     \n\nIf your script expects say a starting primary key value, you can easily pass it as an input:\n\n```\n    Map\u003cString, Object inputs = new HashMap\u003c\u003e();\n    inputs.put(\"pkStart\", 123);\n   \tloader.withInputs(inputs).load(\"basicdata.groovy\", \"secondScript.groovy\");\n```\n\nThe value is now available as a property called pkStart to the script (and to `secondScript.groovy` as well) and can be referenced directly:\n\n```\n    table(School, ['id', 'name', 'type', 'address']) {\n\t\trow pkStart++, 'Lee Elementary', SchoolType.ELEMENTARY, '1 Lee Rd'\n\t\trow pkStart++, 'Park View School', SchoolType.MIDDLE, '10 Elm Street'\n\t\thighSchool = row pkStart++, 'Mountain Top High', SchoolType.HIGH, '12 Dream Street'\n\t} \t\n```    \n\nSometimes the groovy compiler can get confused in evaluating the syntax for the columns. To help the compiler, wrap the column values in parenthesis:\n\n```\n    table(School, ['id', 'name', 'type', 'address']) {\n\t\trow (pkStart++, 'Lee Elementary', SchoolType.ELEMENTARY, '1 Lee Rd')\n\t\trow (pkStart++, 'Park View School', SchoolType.MIDDLE, '10 Elm Street')\n\t\thighSchool = row (pkStart++, 'Mountain Top High', SchoolType.HIGH, '12 Dream Street')\n\t} \n```\n\nSince the scripts are groovy based, you can use all groovy control structures to help you populate your data:\n\n```\n\ttable(MyValue, ['id', 'value']) {\n\t\t10.times { i -\u003e\n\t\t\trow i, i * 50\n    \t}\n\t}\n```\n\nWhen testing your database functionality, sometimes you need reference to data that already exists. This is particularly important if the data has a generated PK. In the example above we created schools and created a reference to the high school in a variable called `highSchool`. This variable (strictly speaking, property) is automatically returned to the caller in a map. The key is a string with the value `highSchool` and the value is an instance of School. \n\n*Note: Do not declare highschool using a type or `def` as shown:*\n\n```\n    table(School, ['id', 'name', 'type', 'address']) {\n\t\trow (pkStart++, 'Lee Elementary', SchoolType.ELEMENTARY, '1 Lee Rd')\n\t\trow (pkStart++, 'Park View School', SchoolType.MIDDLE, '10 Elm Street')\n\t\tdef highSchool = row (pkStart++, 'Mountain Top High', SchoolType.HIGH, '12 Dream Street')\n\t} \n```\n\nThis will make highSchool a local variable and it will not be returned to the caller. Of course, if you need to temporarily hold on to large collections that you don't want to return back to the calling script, then do mark them with a `def` or type.\n\nIf you are invoking multiple scripts and some of the scripts return values that are named the same, you can define namespaces for the scripts. If two scripts `myScript1.groovy` and `myScript2.groovy` both create a property called `x`, you can load the scripts with namespaces as shown:\n\n```\n\tMap\u003cString, Object\u003e variables = loader.withInputs(inputs).load(Script.with(\"myScript1.groovy\", \"a\"), Script.with(\"myScript2.groovy\", \"b\");\n\n    Map\u003cString, Object\u003e script1Vars = variables.get(\"a\");\n    Object x = script1Vars.get(\"x\");\n```\n\nYou can also call scripts from within scripts. Use the `load()` method. The load method accepts a list of script names or a map of `namespace:script-name`.\n\n```\n   \toutput = load('a': 'simple.loader.groovy', 'b': 'simple.loader.groovy')\t\n\tassert output.a.simple1.amount == 20\n\n\tmyIndex = 101\n\tinputReaderVars = withInput(['index': myIndex]).load('input.reader.groovy')\n\tassert inputReaderVars.inputReaderReturn.amount == 101000\n``` \n\nwhere `simple.loader.groovy` is:\n\n```\n\timport com.eclecticlogic.pedal.loader.dm.SimpleType\n\t\n\ttable(SimpleType, ['amount']) {\n\t    simple1 = row 10\n\t    simple2 = row 20\n\t}\n```  \n\nand `input.reader.groovy` is:\n\n```\n\timport com.eclecticlogic.pedal.loader.dm.SimpleType\n\n\ttable(SimpleType, ['amount']) {\n    \tinputReaderReturn = simple1 = row (1000 * index)\n\t    simple2 = row 2000\n\t}\n```\n\nVariables created in one script are available to the next script when multiple scripts are passed to the same load() call. The find method can be used to retrieve data that has been created by primary key.\n\n### Default row\n\nSometimes you want to set certain columns of each row to the same value or the value can easily be defined as an expression. Pedal makes it easy to avoid repeating the value of the column in each row by defining a \"default\" row closure:\n\n```\n    tone = table (MyTable, ['id', 'name', 'insertedOn']) {\n        defaultRow {\n            it.insertedOn = new Date()\n        }\n        row 1, 'Joe'\n\t\trow 2, 'Schmoe'\n\t\trow 3, 'Jane'\n\t\trow 4, 'Jack'\n    }\n```\n\n### Custom functions\n\nYou can define custom functions that should be available within the load script. To define a custom-function, use the `.withCustomMethod` method on Loader passing in a closure:\n\n```\n    Map\u003cString, Object\u003e variables = loader //\n            .withCustomMethod(\"doubler\", new Closure\u003cObject\u003e(this) {\n\n                @Override\n                public Object call(Object... args) {\n                    Integer i = (Integer) args[0];\n                    return i * 2;\n                }\n            }).withScriptDirectory(\"loader\") //\n            .load(\"customMethod.loader.groovy\");\n```  \n\n`doubler` is now a custom-function that can be called within your script:\n\n\n```\n     myvar = doubler 200\n```\n\n### Find and Flush\n\nThe find(Class, id) method is available to your DSL scripts to load records by JPA entity class and primary key. The flush() method does what you would think it should - flush the JPA session to the database.\n\nSee the src/test/resources/loader folder of the pedal-loader source for more examples.\n\n### Release notes\n\n# 1.1.1\n\n- Moved the @PersistenceContext annotation from field to setter method so that users can override the method and the annotation to specify non-default annotation parameters.\n\n# 1.1.0 \n\n- Upgraded to use Hibernate 5.x and corresponding Pedal dialect 1.2\n\n# 1.0.2\n\n- Support for file system based script loading and associated refactoring by [csetera](https://github.com/csetera)\n\n# 1.0.1 \n\n- Fixed a failing unit test.\n- Changed java_home reference in pom to standard value.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclecticlogic%2Fpedal-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feclecticlogic%2Fpedal-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feclecticlogic%2Fpedal-loader/lists"}