{"id":15293264,"url":"https://github.com/stephenafamo/boilingfactory","last_synced_at":"2025-05-07T05:11:02.725Z","repository":{"id":57650907,"uuid":"448393092","full_name":"stephenafamo/boilingfactory","owner":"stephenafamo","description":"BoilingFactory is a CLI tool that generates factories for models generated by sqlboiler. https://github.com/volatiletech/sqlboiler.","archived":false,"fork":false,"pushed_at":"2022-01-29T09:38:33.000Z","size":88,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-31T06:41:19.581Z","etag":null,"topics":["database","factorybot","golang","sqlboiler"],"latest_commit_sha":null,"homepage":"","language":"Smarty","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/stephenafamo.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":"2022-01-15T21:18:00.000Z","updated_at":"2024-01-02T11:29:52.000Z","dependencies_parsed_at":"2022-09-05T02:50:55.017Z","dependency_job_id":null,"html_url":"https://github.com/stephenafamo/boilingfactory","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephenafamo%2Fboilingfactory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephenafamo%2Fboilingfactory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephenafamo%2Fboilingfactory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephenafamo%2Fboilingfactory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephenafamo","download_url":"https://codeload.github.com/stephenafamo/boilingfactory/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252817637,"owners_count":21808706,"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","factorybot","golang","sqlboiler"],"created_at":"2024-09-30T16:45:17.750Z","updated_at":"2025-05-07T05:11:02.705Z","avatar_url":"https://github.com/stephenafamo.png","language":"Smarty","readme":"# BoilingFactory\n\nThis is a CLI tool that generates factories for models generated by [`sqlboiler`](https://github.com/volatiletech/sqlboiler).\n\n## Installation\n\n* Install [`sqlboiler`](https://github.com/volatiletech/sqlboiler)\n* Install your database driver for [`sqlboiler`](https://github.com/volatiletech/sqlboiler#supported-databases).\n* Generate your models. [Link](https://github.com/volatiletech/sqlboiler#initial-generation)\n* Install `boilingfactory`: `go install github.com/stephenafamo/boilingfactory`\n* Generate factory: `go run github.com/stephenafamo/boilingfactory psql`\n\n## A little taste\n\n```go\n// Create a new model\nlicense, _ := factory.CreateLicense()\n\n// create with options\npilot, _ := factory.CreatePilot(\n    // Set a Column with a value\n    factory.PilotID(120),\n    // Use a callback with the xxFunc variants\n    factory.PilotNameFunc(func() (string, error) {\n        var randomName string\n        // somehow generate a new name\n        return randomName, nil\n    }),\n    // RELATIONSHIPS\n    // Attach an existing model\n    factory.PilotWithLicense(license),\n    // Build models dynamically\n    factory.PilotWithNewJets(5),\n)\n\n// Insert can be used with any existing model\n// Before Inserting: It checks if there are any foreign keys that are not\n// set and do not have a default and creates models for it\n// After Inserting: It saves any related models found in the relationship struct\n_ = factory.InsertPilot(ctx, db, pilot)\n\n// Set defaults on the factory\nfactory.SetBasePilotMod(factory.PilotMods{\n    // Attach an existing model\n    factory.PilotWithNewLicense(),\n    // Build models automatically\n    factory.PilotWithNewJets(5),\n})\nfactory.SetBaseJetMod(factory.JetMods{\n    factory.JetColor(\"blue\"),\n})\n\n// Now any new pilot will be created with a new license and 5 blue jets\npilot2, _ := factory.CreateAndInsertPilot(ctx, db)\n```\n\n## Configuration\n\n\nThe program accepts these flags to overwrite any configuration.\n\n* `--sqlboiler-models`: The package of your generated models. Needed to import them properly in the factory. DEFAULT: `current/go/module/models`.\n* `--config`: Configuration file path. DEFAULT: `sqlboiler.toml`\n* `--output` or `-o`: The name of the folder to output to. DEFAULT: `factory`\n* `--pkgname` or `-p`: The name you wish to assign to your generated package. DEFAULT: `factory`\n* `--wipe`: Delete the output folder (rm -rf) before generation to ensure sanity. DEFAULT `false`\n* `--version`: Print the version\n* `debug` or `d`: Debug mode prints stack traces on error. DEFAULT `false`\n\nThey can also be set in the config file, or as environment variables\n\nTo attempt to match your generated model options, the defualt the sqlboiler configuration files are used: `sqlboiler.toml` or `json` or `yaml`.\n\n**NOTE:** If you have customized the output folder or pkgname in your `sqlboiler` config file and you are passing the same file to `boilingfactory`, you should overwrite them using the `-o` and `p` flags respectively.\n\n## Mods\n\nMods are central to the design of the factories. Each model has its own mod type, which is an interface that applies a change to the model.\n\nYou can set [base mods][base-mods] for each model on the factory, and pass additional mods when [creating][create] an individual object.\n\n```go\ntype PilotMod interface {\n\tApply(*models.Pilot) error\n}\n```\n\nThere are generated mods for changing the [column][column-mods] or [relationship][relationship-mods] of a model, and some [helper types][mod-helper-types] to make it easier to implement custom mods.\n\n### Column Mods\n\nFor every column in a model, several  fuctions are created:\n\nOne take a value and returns a mod that sets the column's value,\n\n```go\nfactory.PilotName(\"Stephen\") // returns a PilotMod\n```\n\nThe other takes a callback function that is called to generate new values. This plays very nicely with generating random data.\n\n```go\nfactory.PilotNameFunc(func () (string, error) {\n\treturn randomdata.SillyName(), nil\n})\n```\n\n### Relationship Mods\n\nFor every relationship in the model, several functions are created. Each of these generated functional mods do the following:\n\n* They place the relationship in the `.R` struct of both the local model and the relation.\n    * If it is a to-one relationship, this will overwrite any currently set models\n    * For a to-many relationship, `AddXXX` methods are generated which will appended relations to the existing ones instead of overwriting.\n* They set the value of the foreign key of the local model or related model as applicable.\n\nOne `Mod` is generated to set the relationship passing an already created model:\n\n```go\nfactory.PilotWithLicense(licenseModel) // adds the license relationship\n```\n\nAs with the [column mods][column-mods], there is also a variant that takes a callback:\n\n```go\nfactory.PilotWithLicenseFunc(f func() (*models.License, error) {\n    var license *models.License // do some fancy generation\n    return license, nil\n})\n```\n\nFinally, there is a variant that **creates** the relation on the fly using a supplied factory.  \nPass `nil` as the factory to use the default global factory. See the section on [Multiple Factories][multiple-factories].\n\nYou can pass some extra mods that would be applied to the created relations.\n\n```go\n// Using the default factory\nfactory.PilotWithNewLicense(nil, factory.LicenseNumber(\"random\"))\n\nvar myCustomFactory *factory.Factory\nfactory.PilotWithNewLicense(myCustomFactory, factory.LicenseNumber(\"random\"))\n```\n\n**NOTE:** In addition, a To-Many relationship will also have `Add` relationship mods:\n\n```go\nfactory.PilotWithJets(jetModelSlice) // Overwrites all current relationships with this\nfactory.PilotAddJets(jetModelSlice) // Adds the jets to the current ones\n```\n\n### Mod helper types\n\nThere are also helper types to easily create mods.\n\nThe `xxxModFunc` type helps convert a function like `func(*models.Pilot) error` to a `Mod`\n\n```go\ntype PilotModFunc func(*models.Pilot) error\n\nfunc (f PilotModFunc) Apply(n *models.Pilot) error {\n\treturn f(n)\n}\n```\n\nThe `xxxMods` type takes a list of mods and applies them as a single mod\n\n```go\ntype PilotMods []PilotMod\n\nfunc (mods PilotMods) Apply(n *models.Pilot) error {\n\tfor _, f := range mods {\n\t\terr := f.Apply(n)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n```\n\n\nIf you needed to, you could implement your own mods\n\n## Usage\n\n### Creating models\n\nModels are created using the `Create` function.\n\nThese functions can take a variable number of [`Mods`][mods] which it would apply to a fresh object before returning. If there are any base mods defined on the factory, the base mods will be applied **first**.\n\n**Multiple** models can be created with the **CreatePlural()** function. For example, if we have a `Jet` models, `CreateJet` and `CreateJets` will be generated for use.\n\n```go\npilot, err := factory.CreatePilot()\npilotSlice, err := factory.CreatePilots(10)\n```\n\n**NOTE:** This does not save the model in the database. To do that you should use the [`Insert`][insert] or [`CreateAndInsert`][create-and-insert] functions.\n\n### Inserting models\n\nThe **Insert()** function saves the model in the database.\n\n* For every foreign key, if the value is not set and the field does not have a default value, a related model is built (using the default mods) and attached to the model **before** insertion.\n* For dependent relations, models in the `.R` field are also inserted. So if you have a mod that builds and attaches related models, this will also save them.\n\n**Multiple** models can be inserted with the **InsertPlural()** function. For example, if we have a `Jet` models, `InsertJet` and `InsertJets` will be generated for use.\n\n```go\nerr := factory.InsertPilot(ctx, db, pilot)\nerr := factory.InsertPilots(ctx, db, pilotSlice)\n```\n\n### Create and Insert\n\nFor convenience, there are the `CreateAndInsert` functions that do both [creation][create] and [insertion][insert] in a single step. These functions also accept a variable number of [`Mods`][mods].\n\n```go\npilot, err := factory.CreateAndInsertPilot(ctx, db)\npilotSlice, err := factory.CreateAndInsertPilots(ctx, db, 10)\n```\n\n### Multiple Factories\n\nThere is a global factory which is used when the [`Create`][create] or [`Insert`][insert] methods are called,  \nbut we can also create a custom Factory object and call the methods on it.\n\n```go\nvar myCustomFactory = \u0026factory.Factory{}\npilot, _ := myCustomFactory.CreatePilot()\njet, _ :=  myCustomFactory.CreateAndInsertJet(ctx, db)\n```\n\nThese methods works the same way as the package functions. Defaults can also be set on custom factories.\n\n### Setting Defaults\n\nYou can set default values for models by setting a base mod to be applied to all created models in a factory.\n\n```go\n// For the global factory\nfactory.SetBasePilotMod(\n    factory.PilotName(\"Stephen\"),\n)\n\npilot, _ := factory.CreatePilot() // pilot.Name is \"Stephen\"\n\n// For a custom factory\nvar myCustomFactory = \u0026factory.Factory{}\nmyCustomFactory.SetBasePilotMod(\n    factory.PilotName(\"John\"),\n)\n\npilot2, _ := factory.CreatePilot() // pilot2.Name is \"John\"\n```\n\n\n## Contributing\n\nPRs welcome.\n\n[mods]: #mods\n[create]: #creating-models\n[insert]: #inserting-models\n[create-and-insert]: #create-and-insert\n[mod-helper-types]: #mod-helper-types\n[column-mods]: #column-mods\n[relationship-mods]: #relationship-mods\n[base-mods]: #setting-defaults\n[multiple-factories]: #multiple-factories\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephenafamo%2Fboilingfactory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephenafamo%2Fboilingfactory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephenafamo%2Fboilingfactory/lists"}