diff --git a/entc/gen/func.go b/entc/gen/func.go index 414811a09..e17be4318 100644 --- a/entc/gen/func.go +++ b/entc/gen/func.go @@ -294,6 +294,7 @@ func keys(v reflect.Value) ([]string, error) { for i, v := range v.MapKeys() { keys[i] = v.String() } + sort.Strings(keys) return keys, nil } diff --git a/entc/gen/internal/bindata.go b/entc/gen/internal/bindata.go index 81015ba85..2f6e5048e 100644 --- a/entc/gen/internal/bindata.go +++ b/entc/gen/internal/bindata.go @@ -926,7 +926,7 @@ func templateHeaderTmpl() (*asset, error) { return a, nil } -var _templateHookTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xac\x56\x5f\x6f\xdb\xb6\x17\x7d\x96\x3e\xc5\xfd\x19\x0e\x20\xf5\xa7\xd0\x69\xdf\xb6\x22\x03\x8a\x2c\xc5\x0a\x74\xc9\xb0\xa5\x7b\x29\xba\x81\x95\xae\x2c\xce\x14\x29\x90\x74\x1c\x43\xd3\x77\x1f\x2e\x49\xd9\x8a\xb5\x75\x41\x97\x97\x36\xbe\xff\x79\xce\xe1\x15\xfb\x7e\xf5\x22\xbd\xd2\xdd\xde\x88\x75\xe3\xe0\xd5\xc5\xcb\x6f\xce\x3b\x83\x16\x95\x83\xb7\xbc\xc4\xcf\x5a\x6f\xe0\x9d\x2a\x19\xbc\x91\x12\x7c\x90\x05\xf2\x9b\x7b\xac\x58\x7a\xd7\x08\x0b\x56\x6f\x4d\x89\x50\xea\x0a\x41\x58\x90\xa2\x44\x65\xb1\x82\xad\xaa\xd0\x80\x6b\x10\xde\x74\xbc\x6c\x10\x5e\xb1\x8b\xd1\x0b\xb5\xde\xaa\x2a\x15\xca\xfb\xdf\xbf\xbb\xba\xbe\xf9\xe5\x1a\x6a\x21\x11\xa2\xcd\x68\xed\xa0\x12\x06\x4b\xa7\xcd\x1e\x74\x0d\x6e\xd2\xcc\x19\x44\x96\xbe\x58\x0d\x43\x9a\xf6\x3d\x54\x58\x0b\x85\xb0\x68\xb4\xde\x2c\x20\x1a\x77\xc2\x35\x80\x0f\x0e\x55\x05\x4b\x58\xfc\xc4\xcb\x0d\x5f\xe3\x62\x12\x95\xf4\x3d\x38\x6c\x3b\xc9\x1d\x25\x23\xaf\xd0\x2c\x80\x91\xab\xef\x81\xf2\xa8\x94\x68\x3b\x6d\x1c\x2c\xfa\x1e\x96\xec\x4a\xab\x5a\xac\x59\x2c\x06\xc3\xb0\xf0\xbd\x96\xdd\x66\x0d\xdf\x5e\xc2\x67\x6e\xf1\xef\xa2\x7c\x90\xe1\x6a\x8d\xb0\x54\x14\xb8\x64\x37\xba\x42\x3b\x4e\xb1\x54\xbc\x45\xb2\x77\x46\x28\x07\x4b\xc5\x6e\xc8\xb0\x78\xbb\x55\xe5\x61\xd4\xa5\xdb\x77\xc7\xa0\x1a\x16\x2f\xce\x2c\x3b\xb3\x8b\xd0\x7d\xa9\xd8\x8f\x5b\xc7\x9d\xd0\xca\xe7\x52\xd3\x64\xb5\x82\xbb\x06\xe1\xd0\x61\x18\xc0\x17\x11\x16\xb8\x02\x5e\xf1\xce\x11\x47\x1a\xb8\x94\x7a\xe7\x81\xdf\x5a\x24\xb4\xb5\xa9\x84\xe2\x66\xef\x6b\xd4\x5b\x55\x52\x61\xe0\x36\xd4\x62\xb1\x05\xb4\xd4\x52\x1b\x96\x26\xbe\xee\xb4\x11\x25\x65\xa5\x56\x0e\x1f\x1c\x21\x42\xff\x17\x70\x38\xc7\x30\xe4\x90\x8d\xd0\x0d\x03\xfb\x95\xcb\x2d\x16\x80\xc6\x68\x93\x87\xd1\xfd\x79\x10\x4a\x2e\xa5\x85\x3a\x2b\xdd\x43\x01\x6d\xce\xd2\x84\x4a\x43\x56\x4f\xdb\xe5\x31\x9a\xa2\x60\xd6\xb5\x85\x49\xa7\x11\xa6\x2f\xf4\x87\x3e\x4d\x92\xf6\xbe\x00\xbd\x21\xc0\x5b\x96\x4d\xe7\x4e\x93\x44\xd4\xf0\x3f\xbd\xf1\x61\x89\x41\xb7\x35\x0a\x94\x90\x05\xd4\xad\x63\xd7\x54\xa2\xce\x16\x5b\x85\x0f\x1d\x96\x0e\xab\x00\x13\x01\xe8\x4b\x9c\xdd\x31\x08\xae\x29\x1c\x0b\x3a\x5c\x9a\x24\x43\x7a\x28\x39\x9e\xf9\x3e\x4f\x93\x47\x9a\x5c\xad\xe0\x56\x01\x3e\x60\xb9\x75\x68\x3d\x6f\x6b\x71\x8f\x0a\x48\xdb\xa0\x95\xdc\x43\xad\xcd\xc4\xae\x3b\x34\x7e\x02\x96\xae\x56\xe9\x6a\x95\x50\x20\xbb\x55\xd9\x7b\xbd\x2e\xa6\xe0\x7c\x8f\x12\x1d\xfe\x39\xb1\x5c\x19\xe4\x0e\x73\xca\xf3\xb8\xdf\xaa\xac\xd9\x4c\x53\x7e\xd0\x7a\x53\x80\xee\xa6\xb6\xdb\x2e\x3f\x0d\x21\xb0\xc6\x73\x91\x34\x14\x3e\xb8\x19\x2d\x1e\xfb\x99\xcd\xe3\x1c\x73\x4f\xbd\x48\x77\x24\x0b\x62\x7b\x36\xea\x89\xdf\x96\xdd\x76\x59\xce\xde\xd9\x4c\x77\xd1\x3a\xce\xd0\x6c\xfc\xf4\x39\x3b\x6a\x2e\x92\xe7\xd9\x3b\x28\x82\x06\x99\x85\x0c\x9e\xcc\x40\xe2\x07\x25\xd1\x5a\xb0\x1b\xd1\x7d\x3d\x8b\xa1\xc8\x8c\xc9\x0f\x5d\xc5\x1f\x33\x19\x2c\xb7\x6a\x42\x66\xcc\xfd\xaf\x84\x7a\x4d\x14\xf0\x9b\xee\xf2\x78\xb2\x9f\xf1\x0f\xd2\x77\xf0\x5b\xe0\xe1\x4c\xae\xe1\x64\x23\x97\xa5\x9d\x73\x3c\x91\x0d\xbe\x96\xbb\xb2\x01\xdd\x8d\x07\x0c\x37\xfd\x2e\x07\x6a\x68\xb3\x1c\x3e\x7e\x9a\x4f\xb1\x5a\x1d\x20\x9f\xb9\x83\x37\x09\xe3\x64\x5f\x14\x7a\x80\x27\x2f\x7c\xc6\x40\xff\x0e\x07\x9c\x62\xfe\x93\x30\x69\xfc\xce\xf0\x8a\x7c\x56\x79\xff\xfe\x5c\xe2\xfe\xa7\x85\x75\x66\x8f\x7c\xd0\x27\x42\x69\x17\x3e\x0c\x58\xd1\x72\xf2\xf7\xe1\xa8\xe0\x13\xee\x8f\xd4\x5f\x35\x5c\x28\xe0\x9e\x62\x62\x5e\x0a\xeb\xe8\x93\x42\x0a\xa0\xef\x4e\x45\xb5\xb1\xae\xb1\x74\xe2\x1e\xe5\x1e\x44\x4b\xfb\xf1\xb3\x44\x16\x16\x1b\xbd\x26\xfc\xd2\xa9\x0a\x10\x0e\x76\x42\x4a\xe0\x72\xc7\xf7\x16\x1a\x2d\x2b\x7f\x21\x2c\xad\x7d\x8b\x93\xc2\xf1\xe1\xe0\x1d\xda\x54\x68\x58\xea\x37\x6b\x18\xc7\x3a\xb3\xa5\x7d\x9b\x26\x21\x7a\x26\x94\x38\xfc\x0d\xee\x42\x42\x98\x80\xe6\x57\xb8\x83\xd2\xdb\xc6\x5e\x2c\x88\x62\x8c\xcd\x42\x49\xc6\xd8\x49\xcd\x3c\x36\x3f\x5e\x14\xff\xbb\xe7\x5d\x87\xaa\xca\x66\x33\x64\x4a\xc8\xbc\x88\x3d\x18\xcb\xc7\x35\xe1\x95\xe5\x47\x08\x5b\x62\x8e\xe8\x78\xcf\xc8\x5b\x0b\xc5\xa5\xf7\xc5\x39\xb3\x32\xf4\x0d\xb7\x28\xfb\xd7\xcd\xdc\x8e\xb2\x7c\xba\x7a\x69\x4f\x09\x92\xbd\x44\x95\x95\xcc\x0f\x96\xc3\x39\xbc\x7c\x0d\x02\xbe\xbb\x84\x8b\xd7\x20\xce\xcf\x83\xfc\xc6\xf2\x97\x10\x03\x3f\x8a\x4f\x63\xcf\x93\x0f\x60\xb4\x1e\x17\xe6\x1b\x8f\x5c\x7c\xd6\x11\x39\x1e\x95\x02\x78\x55\x09\xb5\x0e\x02\xe8\xb0\x14\xb5\xc0\xca\x43\x40\x49\x3c\xa2\xc6\x09\x35\x85\x07\xa9\x1c\xbe\xca\xb5\xd4\xbb\x19\x56\xa1\xd5\x53\xb8\x55\xb8\xf3\xeb\xc9\x3f\x15\xf8\x06\xe7\xc4\x16\x70\x51\x3c\x82\xe6\xff\xf4\x23\xfc\x99\x4f\x0a\x5c\x42\x94\xc6\x68\x29\x46\x8c\x48\x0e\x5f\x0e\x9c\x84\x3d\x12\xdb\x18\x31\x42\x78\x1d\x9e\xc4\x4f\x83\xd0\xfb\xbe\x1e\xc3\xd0\x2b\x0b\xb7\x27\xda\x4e\xaf\x44\xc9\x22\xd2\x3e\x6a\x72\xda\xf0\x6a\x8e\x4f\x9e\xbf\x02\x00\x00\xff\xff\x0f\x28\xb5\x6b\xaa\x0c\x00\x00") +var _templateHookTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x58\xdd\x8f\xdb\xb8\x11\x7f\xb6\xff\x8a\x89\xe0\x00\x52\xaa\xa5\x73\xf7\xd6\x06\x29\xb0\xf0\x25\xc8\x02\xd7\x75\x71\xcd\xf5\xe5\x70\xc8\x31\xd2\xc8\x66\x2d\x93\x02\x49\xef\x07\x1c\xfd\xef\xc5\x0c\x45\x49\xb6\x76\xf7\xf6\xd2\x14\xf7\xb2\x6b\xcf\x0c\xe7\xe3\x37\x1f\x1c\xfa\x78\x5c\xbe\x9a\xaf\x4c\x73\x6f\xd5\x66\xeb\xe1\xfb\xd7\xdf\xfd\xf5\xa2\xb1\xe8\x50\x7b\x78\x2f\x0b\xfc\x6c\xcc\x0e\xae\x74\x21\xe0\xb2\xae\x81\x85\x1c\x10\xdf\xde\x60\x29\xe6\x1f\xb7\xca\x81\x33\x07\x5b\x20\x14\xa6\x44\x50\x0e\x6a\x55\xa0\x76\x58\xc2\x41\x97\x68\xc1\x6f\x11\x2e\x1b\x59\x6c\x11\xbe\x17\xaf\x23\x17\x2a\x73\xd0\xe5\x5c\x69\xe6\xff\x78\xb5\x7a\x77\xfd\xaf\x77\x50\xa9\x1a\xa1\xa3\x59\x63\x3c\x94\xca\x62\xe1\x8d\xbd\x07\x53\x81\x1f\x19\xf3\x16\x51\xcc\x5f\x2d\xdb\x76\x3e\x3f\x1e\xa1\xc4\x4a\x69\x84\x64\x6b\xcc\x2e\x81\x8e\x78\xab\xfc\x16\xf0\xce\xa3\x2e\x61\x01\xc9\x3f\x65\xb1\x93\x1b\x4c\x46\x52\xb3\xe3\x11\x3c\xee\x9b\x5a\x7a\x3a\x8c\xb2\x44\x9b\x80\x20\xd6\xf1\x08\x74\x8e\x54\xa9\x7d\x63\xac\x87\xe4\x78\x84\x85\x58\x19\x5d\xa9\x8d\xe8\x94\x41\xdb\x26\x6c\x6b\xd1\xec\x36\xf0\xb7\xb7\xf0\x59\x3a\x7c\x48\x8a\x85\xac\xd4\x1b\x84\x85\x26\xc1\x85\xb8\x36\x25\xba\xe8\xc5\x42\xcb\x3d\x12\xbd\xb1\x4a\x7b\x58\x68\x71\x4d\x84\xe4\xfd\x41\x17\xbd\xab\x0b\x7f\xdf\x0c\x42\x15\x24\xaf\x5e\x3a\xf1\xd2\x25\xc1\xfa\x42\x8b\x7f\x1c\xbc\xf4\xca\x68\x3e\x4b\x46\x67\xcb\x25\x7c\xdc\x22\xf4\x16\xda\x16\x58\x89\x72\x20\x35\xc8\x52\x36\x9e\x72\x64\x40\xd6\xb5\xb9\x65\xe0\x0f\x0e\x09\x6d\x63\x4b\xa5\xa5\xbd\x67\x1d\xd5\x41\x17\xa4\x18\xa4\x0b\xba\x44\x67\x02\xf6\x64\xd2\x58\x31\x9f\xb1\xde\xb1\x21\x3a\x94\x16\x46\x7b\xbc\xf3\x84\x08\xfd\xcf\xa1\x8f\xa3\x6d\x33\x48\x23\x74\x6d\x2b\xfe\x2d\xeb\x03\xe6\x80\xd6\x1a\x9b\x05\xd7\x39\x1e\x84\x42\xd6\xb5\x83\x2a\x2d\xfc\x5d\x0e\xfb\x4c\xcc\x67\xa4\x1a\xd2\x6a\x6c\x2e\xeb\xa4\x49\x0a\x26\x56\xf7\x30\xb2\x14\x61\x7a\xc2\x3e\x1c\xe7\xb3\xd9\xfe\x26\x07\xb3\x23\xc0\xf7\x22\x1d\xfb\x3d\x9f\xcd\x54\x05\x2f\xcc\x8e\xc5\x66\x16\xfd\xc1\x6a\xd0\xaa\xce\xa1\xda\x7b\xf1\x8e\x54\x54\x69\x72\xd0\x78\xd7\x60\xe1\xb1\x0c\x30\x11\x80\xac\xe2\xe5\x47\x01\x81\x35\x86\x23\xa1\xe0\xe6\xb3\x59\x3b\xef\x55\xc6\x98\x6f\xb2\xf9\xec\xa4\x26\x97\x4b\x58\x19\x5d\x2a\xd6\x49\xc9\x04\x2a\x6a\x8a\xbb\xa3\xc5\x8c\x89\x39\x6b\x5f\x9d\x30\x1e\xce\xca\x04\x9d\xcf\xc6\xd4\x6c\xea\x52\x97\xb0\xb1\xe6\xd0\xb8\xc1\x82\x0b\xfd\xc5\xed\x7d\xfd\x03\x98\x06\x6d\x28\x04\xce\xcd\xa5\x2e\xd3\x4a\x59\xe7\x73\x70\x48\x67\x06\x0f\x72\x9a\x1f\x1e\x84\x10\x3d\x29\x1b\xf9\x77\x9c\xf7\xc1\xb3\xa7\x7f\x20\x9b\xe4\x2f\x67\x84\x92\xc3\xd6\x63\xc9\xc0\x97\x2f\xf0\x22\x38\xd2\x93\xc6\xa9\xab\x64\xed\xb0\x83\xbe\x32\x16\x3e\xe5\x1c\x28\xa5\x3e\x34\x2d\xbb\xcc\x27\x48\xf7\x54\xcf\xb9\x22\xd6\x34\x4a\xa4\xb7\x07\xa4\x14\x86\xd4\xad\xed\x53\x70\xae\x7f\x3a\x47\x73\x6d\xff\x5c\x30\x27\x58\x3e\x01\x65\x88\xf4\x99\x48\x3e\x0e\x64\xa7\xe6\x1c\xc7\x0e\xdf\x08\xe4\xb5\xf1\xa0\x71\x23\x3d\x52\x0b\x6c\xd4\x0d\xea\x01\xd2\x0e\xbc\x6b\xe3\xd3\x53\xd0\xbe\x35\x42\x9d\x82\x93\xb2\x18\x7c\xfc\x20\xdd\xba\x09\x3d\x3a\xb4\xa7\x47\xe7\x95\xde\x0c\x73\x21\x64\x7c\xf0\x9a\x4f\xa5\xa6\x19\x9b\x5e\x37\x4f\x78\xfe\xe9\xab\xfd\xde\x8b\x75\x93\x66\xe2\xca\xa5\xa6\x89\x7e\xd3\x41\xf2\xd6\x51\xe2\x4a\x55\x78\x48\x3e\x48\xf7\x5e\x61\x5d\xba\x04\x12\xfe\x90\x30\xed\xb2\x2c\xb1\xec\x19\xc3\xb7\xc0\x5d\xd5\x28\xed\x88\xcf\x1f\x3a\x62\x02\x17\x7c\xd1\x5e\xc4\x8b\x31\x16\xca\x0e\xef\x5d\x34\x1f\xaf\xbe\x3d\xfa\xad\x61\xee\x06\x7d\x64\x86\x13\xa4\x85\x6e\x8b\xe8\x33\xdd\x3d\x67\x70\xdf\xc8\x5a\x95\x92\x11\xff\x4d\x8c\xd4\xb5\xed\x6f\x40\x33\x91\xdd\x8b\xf7\xca\x48\x4f\xca\x1c\x70\xde\x2a\xbd\xc9\x3b\x39\xea\xb6\x40\x39\x4b\xc7\xff\x9a\x0f\xea\x88\xe3\x11\x54\x05\x1a\x7b\x17\xcf\x20\x6b\xdb\x4f\x3c\xad\xc3\x45\x80\x77\xca\x79\x17\x6e\xa8\x93\xb0\x82\xe3\xd9\x1b\x78\xd1\x89\x3c\x3e\xa5\x62\x9b\x86\x50\xfb\x3e\xed\x62\x0d\xe7\xfe\xef\x8e\x4d\x3c\x0b\xae\xb5\x0f\x0e\x96\x50\x34\xa3\xab\xf0\xaa\x02\xbc\xc3\xe2\x40\x63\x80\x26\x68\x18\x04\x7c\x23\x86\x25\x74\x34\x13\x96\xcb\xf9\x72\x39\xfb\x60\xcc\x4e\x5c\x55\xe9\xca\xec\x9b\x83\xc7\xcb\x1b\xb4\x72\x83\x39\xdf\x5b\x7d\xa1\xa7\x42\x88\x2c\x87\xd3\x22\x67\x62\x96\x91\x1e\xae\x96\xab\x2a\xdd\xee\xc6\x89\x25\xd5\xdd\xd0\x1b\x4d\x9c\x33\x81\xf3\xee\xd5\x78\xe7\x27\xd5\xc1\x7b\xc8\x84\x36\xae\xb4\x73\x2e\xd2\xbe\x98\xfe\xe1\x49\xf6\xf4\x1a\xf4\xf4\xa0\xde\xee\xd8\xf9\x4c\x0c\xeb\x57\xb7\xc7\x9c\x64\x8f\x64\xa6\x22\xed\x68\x4e\xae\xf5\xa3\x49\x34\xba\xbe\x07\x2a\xd3\x81\x3e\x9a\x97\x21\xa3\x24\x28\xd6\x3a\xfd\xd1\x6c\x4e\xd6\x99\x1f\xb0\x46\x8f\x5f\x46\x94\x95\x45\xe9\x71\xc8\xe0\x5a\x3f\x98\xc1\xe9\xec\x7d\x3c\x87\x5c\x04\x79\x3f\xb4\xb3\xac\x8b\xe9\x67\x5d\xa3\x73\xe0\x76\xaa\xf9\xfa\xa0\x82\x92\x49\x60\x3f\x37\xa5\x3c\x0d\x2c\x50\xd6\x7a\x14\x5b\x77\xf6\x1b\xc5\x47\x57\xe9\x10\x63\x0c\xf2\x27\xfc\x0f\x6d\xb2\x41\xb4\x5f\x45\xfd\x56\x12\x8d\x58\x8e\x5e\x17\x43\x70\x2e\xf0\xf6\xd2\x17\x5b\x30\x4d\x8c\x35\xec\xf4\x1f\x33\x20\xdb\x2e\xcd\xe0\x97\x5f\xa7\x0e\x2d\x97\x7d\x45\x4d\xd8\x81\x3b\x0b\xee\xa4\x4f\x96\x40\x40\x2a\xcb\xf9\x44\x4b\x7f\xdb\x1e\xb2\xee\xfc\xb3\xe0\xd9\xf2\xeb\x80\xfb\xed\x9b\x36\xef\xf3\x2f\x8f\xdf\x69\xdd\xc7\x9e\x26\x2f\xdd\x90\x0f\xba\x2c\xb5\xf1\xe1\x09\x88\x25\x3d\x43\x78\x23\x18\x1a\x34\xaa\xe1\x4e\xa1\xca\x89\xa9\x5f\x6d\xa5\xd2\x20\x39\xc5\x94\xf9\x5a\x39\x4f\x8f\x47\xaa\x00\x7a\x61\x96\xa4\x1b\xab\x0a\x0b\xaf\x6e\xb0\xbe\x07\xb5\xa7\x8d\xe7\x73\x8d\x22\xb4\x7c\x81\x50\x70\x3b\x96\x39\x28\x0f\xb7\xaa\xae\x41\xd6\xb7\xf2\xde\xc1\xd6\xd4\x25\xf7\x86\xa3\x07\x9e\xc3\x91\xe2\xee\x27\x02\x66\x18\x5b\xa2\x8d\xaf\x1c\x76\xc7\x79\x7b\x28\x78\xc7\x0c\xd2\x93\x42\x89\xcb\x23\xde\x86\x03\xc1\x03\xf2\x5f\xe3\x2d\x14\x4c\x8b\xb6\xe2\x12\xd9\xc9\xa6\x41\xa5\x10\xe2\x4c\x67\xd6\x19\x1f\x7a\x86\xbf\x1f\x65\xd3\xa0\x2e\xd3\x89\x0f\xa9\x56\x75\x96\x77\x36\x84\xc8\xfa\x6d\x91\x9f\x71\x74\x34\x0c\x8c\x29\xa2\xb1\xcf\x88\x5b\x29\x2d\x6b\xe6\x75\x7e\xa6\x45\xb0\x1b\xba\x28\xfd\xdd\x7b\x67\x1f\xcb\xf2\xf9\xd5\x4b\x23\x4b\x51\xd9\xd7\xa8\xd3\x42\xb0\x63\x19\x5c\xc0\x77\x6f\x40\xc1\xdf\xdf\xc2\xeb\x37\xa0\x2e\x2e\x42\xf9\x45\xf5\x6f\xa1\x13\xfc\x45\xfd\x1a\x6d\x9e\x3d\x75\x3b\xea\x70\x1f\x5c\x32\x72\xdd\x0f\x38\xbc\xce\x51\x60\x39\xc8\xb2\xa4\x3d\x8e\x0b\xa0\xc1\x42\x55\x0a\x4b\x86\x80\x0e\xc9\x0e\x35\x49\xa8\x69\xec\x4b\xa5\xdf\xb3\xab\xda\xdc\x4e\xb0\x0a\xa6\x9e\x93\x5b\x8d\xb7\x3c\x9e\x78\xb3\x91\x3b\x9c\x26\x36\x87\xd7\xf9\x09\x34\x7f\xa1\x2f\xe1\x63\x36\x52\xf0\x16\xba\xd2\x88\x94\x3c\x62\x44\xe5\xf0\xb4\xe0\x48\xec\xa4\xd8\xa2\x44\x84\xf0\x5d\xf8\xf1\xeb\x79\x10\x32\xef\xeb\x31\x0c\xb6\xd2\xd0\x3d\x1d\xed\xbc\x25\x0a\xd1\x21\xcd\x52\xa3\x68\xc3\x8b\xa3\xdb\xe8\xfe\x1b\x00\x00\xff\xff\xca\xfd\x92\xb9\x94\x14\x00\x00") func templateHookTmplBytes() ([]byte, error) { return bindataRead( @@ -941,7 +941,7 @@ func templateHookTmpl() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "template/hook.tmpl", size: 3242, mode: os.FileMode(420), modTime: time.Unix(1, 0)} + info := bindataFileInfo{name: "template/hook.tmpl", size: 5268, mode: os.FileMode(420), modTime: time.Unix(1, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/entc/gen/template/hook.tmpl b/entc/gen/template/hook.tmpl index 2485adb54..9fb976a68 100644 --- a/entc/gen/template/hook.tmpl +++ b/entc/gen/template/hook.tmpl @@ -32,14 +32,80 @@ import "{{ $.Config.Package }}" } {{ end }} -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, {{ $pkg }}.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m {{ $pkg }}.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m {{ $pkg }}.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m {{ $pkg }}.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op {{ $pkg }}.Op) Condition { + return func(_ context.Context, m {{ $pkg }}.Mutation) bool { + return m.Op().Is(op) + } +} + +{{ $conds := dict "HasFields" "Field" "HasAddedFields" "AddedField" "HasClearedFields" "FieldCleared" -}} +{{- range $cond := keys $conds }} + {{ $method := get $conds $cond -}} + // {{ $cond }} is a condition validating `.{{ $method }}` on fields. + func {{ $cond }}(field string, fields ...string) Condition { + return func(_ context.Context, m {{ $pkg }}.Mutation) bool { + if {{ if ne $method "FieldCleared" }}_, {{ end }}exists := m.{{ $method }}(field); !exists { + return false + } + for _, field := range fields { + if {{ if ne $method "FieldCleared" }}_, {{ end }}exists := m.{{ $method }}(field); !exists { + return false + } + } + return true + } + } +{{- end }} + +// If executes the given hook under condition. // -// hook.On(Log, {{ $pkg }}.Delete|{{ $pkg }}.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk {{ $pkg }}.Hook, op {{ $pkg }}.Op) {{ $pkg }}.Hook { +func If(hk {{ $pkg }}.Hook, cond Condition) {{ $pkg }}.Hook { return func(next {{ $pkg }}.Mutator) {{ $pkg }}.Mutator { return {{ $pkg }}.MutateFunc(func(ctx context.Context, m {{ $pkg }}.Mutation) ({{ $pkg }}.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -47,12 +113,20 @@ func On(hk {{ $pkg }}.Hook, op {{ $pkg }}.Op) {{ $pkg }}.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, {{ $pkg }}.Delete|{{ $pkg }}.Create) +// +func On(hk {{ $pkg }}.Hook, op {{ $pkg }}.Op) {{ $pkg }}.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, {{ $pkg }}.Update|{{ $pkg }}.UpdateOne) // func Unless(hk {{ $pkg }}.Hook, op {{ $pkg }}.Op) {{ $pkg }}.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/config/ent/hook/hook.go b/entc/integration/config/ent/hook/hook.go index eed0b043b..ef72d8aad 100644 --- a/entc/integration/config/ent/hook/hook.go +++ b/entc/integration/config/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/customid/ent/hook/hook.go b/entc/integration/customid/ent/hook/hook.go index 66db79889..9aa6a5dc0 100644 --- a/entc/integration/customid/ent/hook/hook.go +++ b/entc/integration/customid/ent/hook/hook.go @@ -78,14 +78,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -93,12 +185,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/ent/hook/hook.go b/entc/integration/ent/hook/hook.go index 33c3fd18c..6b1920278 100644 --- a/entc/integration/ent/hook/hook.go +++ b/entc/integration/ent/hook/hook.go @@ -169,14 +169,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -184,12 +276,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/gremlin/ent/hook/hook.go b/entc/integration/gremlin/ent/hook/hook.go index 8ea324c46..3b4b78be1 100644 --- a/entc/integration/gremlin/ent/hook/hook.go +++ b/entc/integration/gremlin/ent/hook/hook.go @@ -169,14 +169,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -184,12 +276,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/hooks/ent/hook/hook.go b/entc/integration/hooks/ent/hook/hook.go index 405555309..d1fa6b51f 100644 --- a/entc/integration/hooks/ent/hook/hook.go +++ b/entc/integration/hooks/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/hooks/ent/migrate/schema.go b/entc/integration/hooks/ent/migrate/schema.go index 06b25d818..7aadcb690 100644 --- a/entc/integration/hooks/ent/migrate/schema.go +++ b/entc/integration/hooks/ent/migrate/schema.go @@ -40,6 +40,7 @@ var ( {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "version", Type: field.TypeInt}, {Name: "name", Type: field.TypeString}, + {Name: "worth", Type: field.TypeUint, Nullable: true}, {Name: "user_best_friend", Type: field.TypeInt, Unique: true, Nullable: true}, } // UsersTable holds the schema information for the "users" table. @@ -50,7 +51,7 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "users_users_best_friend", - Columns: []*schema.Column{UsersColumns[3]}, + Columns: []*schema.Column{UsersColumns[4]}, RefColumns: []*schema.Column{UsersColumns[0]}, OnDelete: schema.SetNull, diff --git a/entc/integration/hooks/ent/mutation.go b/entc/integration/hooks/ent/mutation.go index 13b8f99b7..ac87e5343 100644 --- a/entc/integration/hooks/ent/mutation.go +++ b/entc/integration/hooks/ent/mutation.go @@ -535,6 +535,8 @@ type UserMutation struct { version *int addversion *int name *string + worth *uint + addworth *uint clearedFields map[string]struct{} cards map[int]struct{} removedcards map[int]struct{} @@ -719,6 +721,77 @@ func (m *UserMutation) ResetName() { m.name = nil } +// SetWorth sets the worth field. +func (m *UserMutation) SetWorth(u uint) { + m.worth = &u + m.addworth = nil +} + +// Worth returns the worth value in the mutation. +func (m *UserMutation) Worth() (r uint, exists bool) { + v := m.worth + if v == nil { + return + } + return *v, true +} + +// OldWorth returns the old worth value of the User. +// If the User object wasn't provided to the builder, the object is fetched +// from the database. +// An error is returned if the mutation operation is not UpdateOne, or database query fails. +func (m *UserMutation) OldWorth(ctx context.Context) (v uint, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldWorth is allowed only on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldWorth requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldWorth: %w", err) + } + return oldValue.Worth, nil +} + +// AddWorth adds u to worth. +func (m *UserMutation) AddWorth(u uint) { + if m.addworth != nil { + *m.addworth += u + } else { + m.addworth = &u + } +} + +// AddedWorth returns the value that was added to the worth field in this mutation. +func (m *UserMutation) AddedWorth() (r uint, exists bool) { + v := m.addworth + if v == nil { + return + } + return *v, true +} + +// ClearWorth clears the value of worth. +func (m *UserMutation) ClearWorth() { + m.worth = nil + m.addworth = nil + m.clearedFields[user.FieldWorth] = struct{}{} +} + +// WorthCleared returns if the field worth was cleared in this mutation. +func (m *UserMutation) WorthCleared() bool { + _, ok := m.clearedFields[user.FieldWorth] + return ok +} + +// ResetWorth reset all changes of the "worth" field. +func (m *UserMutation) ResetWorth() { + m.worth = nil + m.addworth = nil + delete(m.clearedFields, user.FieldWorth) +} + // AddCardIDs adds the cards edge to Card by ids. func (m *UserMutation) AddCardIDs(ids ...int) { if m.cards == nil { @@ -856,13 +929,16 @@ func (m *UserMutation) Type() string { // this mutation. Note that, in order to get all numeric // fields that were in/decremented, call AddedFields(). func (m *UserMutation) Fields() []string { - fields := make([]string, 0, 2) + fields := make([]string, 0, 3) if m.version != nil { fields = append(fields, user.FieldVersion) } if m.name != nil { fields = append(fields, user.FieldName) } + if m.worth != nil { + fields = append(fields, user.FieldWorth) + } return fields } @@ -875,6 +951,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.Version() case user.FieldName: return m.Name() + case user.FieldWorth: + return m.Worth() } return nil, false } @@ -888,6 +966,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldVersion(ctx) case user.FieldName: return m.OldName(ctx) + case user.FieldWorth: + return m.OldWorth(ctx) } return nil, fmt.Errorf("unknown User field %s", name) } @@ -911,6 +991,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetName(v) return nil + case user.FieldWorth: + v, ok := value.(uint) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetWorth(v) + return nil } return fmt.Errorf("unknown User field %s", name) } @@ -922,6 +1009,9 @@ func (m *UserMutation) AddedFields() []string { if m.addversion != nil { fields = append(fields, user.FieldVersion) } + if m.addworth != nil { + fields = append(fields, user.FieldWorth) + } return fields } @@ -932,6 +1022,8 @@ func (m *UserMutation) AddedField(name string) (ent.Value, bool) { switch name { case user.FieldVersion: return m.AddedVersion() + case user.FieldWorth: + return m.AddedWorth() } return nil, false } @@ -948,6 +1040,13 @@ func (m *UserMutation) AddField(name string, value ent.Value) error { } m.AddVersion(v) return nil + case user.FieldWorth: + v, ok := value.(uint) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddWorth(v) + return nil } return fmt.Errorf("unknown User numeric field %s", name) } @@ -955,7 +1054,11 @@ func (m *UserMutation) AddField(name string, value ent.Value) error { // ClearedFields returns all nullable fields that were cleared // during this mutation. func (m *UserMutation) ClearedFields() []string { - return nil + var fields []string + if m.FieldCleared(user.FieldWorth) { + fields = append(fields, user.FieldWorth) + } + return fields } // FieldCleared returns a boolean indicates if this field was @@ -968,6 +1071,11 @@ func (m *UserMutation) FieldCleared(name string) bool { // ClearField clears the value for the given name. It returns an // error if the field is not defined in the schema. func (m *UserMutation) ClearField(name string) error { + switch name { + case user.FieldWorth: + m.ClearWorth() + return nil + } return fmt.Errorf("unknown User nullable field %s", name) } @@ -982,6 +1090,9 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldName: m.ResetName() return nil + case user.FieldWorth: + m.ResetWorth() + return nil } return fmt.Errorf("unknown User field %s", name) } diff --git a/entc/integration/hooks/ent/schema/user.go b/entc/integration/hooks/ent/schema/user.go index 45c5f7e0a..f2398e426 100644 --- a/entc/integration/hooks/ent/schema/user.go +++ b/entc/integration/hooks/ent/schema/user.go @@ -30,6 +30,8 @@ func (User) Mixin() []ent.Mixin { func (User) Fields() []ent.Field { return []ent.Field{ field.String("name"), + field.Uint("worth"). + Optional(), } } diff --git a/entc/integration/hooks/ent/user.go b/entc/integration/hooks/ent/user.go index e880320ea..d40c17825 100644 --- a/entc/integration/hooks/ent/user.go +++ b/entc/integration/hooks/ent/user.go @@ -23,6 +23,8 @@ type User struct { Version int `json:"version,omitempty"` // Name holds the value of the "name" field. Name string `json:"name,omitempty"` + // Worth holds the value of the "worth" field. + Worth uint `json:"worth,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the UserQuery when eager-loading is set. Edges UserEdges `json:"edges"` @@ -80,6 +82,7 @@ func (*User) scanValues() []interface{} { &sql.NullInt64{}, // id &sql.NullInt64{}, // version &sql.NullString{}, // name + &sql.NullInt64{}, // worth } } @@ -112,7 +115,12 @@ func (u *User) assignValues(values ...interface{}) error { } else if value.Valid { u.Name = value.String } - values = values[2:] + if value, ok := values[2].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field worth", values[2]) + } else if value.Valid { + u.Worth = uint(value.Int64) + } + values = values[3:] if len(values) == len(user.ForeignKeys) { if value, ok := values[0].(*sql.NullInt64); !ok { return fmt.Errorf("unexpected type %T for edge-field user_best_friend", value) @@ -166,6 +174,8 @@ func (u *User) String() string { builder.WriteString(fmt.Sprintf("%v", u.Version)) builder.WriteString(", name=") builder.WriteString(u.Name) + builder.WriteString(", worth=") + builder.WriteString(fmt.Sprintf("%v", u.Worth)) builder.WriteByte(')') return builder.String() } diff --git a/entc/integration/hooks/ent/user/user.go b/entc/integration/hooks/ent/user/user.go index 1dee0a226..56e1aef6a 100644 --- a/entc/integration/hooks/ent/user/user.go +++ b/entc/integration/hooks/ent/user/user.go @@ -19,6 +19,8 @@ const ( FieldVersion = "version" // FieldName holds the string denoting the name field in the database. FieldName = "name" + // FieldWorth holds the string denoting the worth field in the database. + FieldWorth = "worth" // EdgeCards holds the string denoting the cards edge name in mutations. EdgeCards = "cards" @@ -49,6 +51,7 @@ var Columns = []string{ FieldID, FieldVersion, FieldName, + FieldWorth, } // ForeignKeys holds the SQL foreign-keys that are owned by the User type. diff --git a/entc/integration/hooks/ent/user/where.go b/entc/integration/hooks/ent/user/where.go index 546d700bf..78debe53a 100644 --- a/entc/integration/hooks/ent/user/where.go +++ b/entc/integration/hooks/ent/user/where.go @@ -109,6 +109,13 @@ func Name(v string) predicate.User { }) } +// Worth applies equality check predicate on the "worth" field. It's identical to WorthEQ. +func Worth(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldWorth), v)) + }) +} + // VersionEQ applies the EQ predicate on the "version" field. func VersionEQ(v int) predicate.User { return predicate.User(func(s *sql.Selector) { @@ -296,6 +303,96 @@ func NameContainsFold(v string) predicate.User { }) } +// WorthEQ applies the EQ predicate on the "worth" field. +func WorthEQ(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldWorth), v)) + }) +} + +// WorthNEQ applies the NEQ predicate on the "worth" field. +func WorthNEQ(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldWorth), v)) + }) +} + +// WorthIn applies the In predicate on the "worth" field. +func WorthIn(vs ...uint) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldWorth), v...)) + }) +} + +// WorthNotIn applies the NotIn predicate on the "worth" field. +func WorthNotIn(vs ...uint) predicate.User { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.User(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldWorth), v...)) + }) +} + +// WorthGT applies the GT predicate on the "worth" field. +func WorthGT(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldWorth), v)) + }) +} + +// WorthGTE applies the GTE predicate on the "worth" field. +func WorthGTE(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldWorth), v)) + }) +} + +// WorthLT applies the LT predicate on the "worth" field. +func WorthLT(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldWorth), v)) + }) +} + +// WorthLTE applies the LTE predicate on the "worth" field. +func WorthLTE(v uint) predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldWorth), v)) + }) +} + +// WorthIsNil applies the IsNil predicate on the "worth" field. +func WorthIsNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldWorth))) + }) +} + +// WorthNotNil applies the NotNil predicate on the "worth" field. +func WorthNotNil() predicate.User { + return predicate.User(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldWorth))) + }) +} + // HasCards applies the HasEdge predicate on the "cards" edge. func HasCards() predicate.User { return predicate.User(func(s *sql.Selector) { diff --git a/entc/integration/hooks/ent/user_create.go b/entc/integration/hooks/ent/user_create.go index 1d5db0931..ab77002b8 100644 --- a/entc/integration/hooks/ent/user_create.go +++ b/entc/integration/hooks/ent/user_create.go @@ -44,6 +44,20 @@ func (uc *UserCreate) SetName(s string) *UserCreate { return uc } +// SetWorth sets the worth field. +func (uc *UserCreate) SetWorth(u uint) *UserCreate { + uc.mutation.SetWorth(u) + return uc +} + +// SetNillableWorth sets the worth field if the given value is not nil. +func (uc *UserCreate) SetNillableWorth(u *uint) *UserCreate { + if u != nil { + uc.SetWorth(*u) + } + return uc +} + // AddCardIDs adds the cards edge to Card by ids. func (uc *UserCreate) AddCardIDs(ids ...int) *UserCreate { uc.mutation.AddCardIDs(ids...) @@ -170,6 +184,14 @@ func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) { }) u.Name = value } + if value, ok := uc.mutation.Worth(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Value: value, + Column: user.FieldWorth, + }) + u.Worth = value + } if nodes := uc.mutation.CardsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/entc/integration/hooks/ent/user_update.go b/entc/integration/hooks/ent/user_update.go index 21359edcb..2c267aa59 100644 --- a/entc/integration/hooks/ent/user_update.go +++ b/entc/integration/hooks/ent/user_update.go @@ -59,6 +59,33 @@ func (uu *UserUpdate) SetName(s string) *UserUpdate { return uu } +// SetWorth sets the worth field. +func (uu *UserUpdate) SetWorth(u uint) *UserUpdate { + uu.mutation.ResetWorth() + uu.mutation.SetWorth(u) + return uu +} + +// SetNillableWorth sets the worth field if the given value is not nil. +func (uu *UserUpdate) SetNillableWorth(u *uint) *UserUpdate { + if u != nil { + uu.SetWorth(*u) + } + return uu +} + +// AddWorth adds u to worth. +func (uu *UserUpdate) AddWorth(u uint) *UserUpdate { + uu.mutation.AddWorth(u) + return uu +} + +// ClearWorth clears the value of worth. +func (uu *UserUpdate) ClearWorth() *UserUpdate { + uu.mutation.ClearWorth() + return uu +} + // AddCardIDs adds the cards edge to Card by ids. func (uu *UserUpdate) AddCardIDs(ids ...int) *UserUpdate { uu.mutation.AddCardIDs(ids...) @@ -240,6 +267,26 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { Column: user.FieldName, }) } + if value, ok := uu.mutation.Worth(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Value: value, + Column: user.FieldWorth, + }) + } + if value, ok := uu.mutation.AddedWorth(); ok { + _spec.Fields.Add = append(_spec.Fields.Add, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Value: value, + Column: user.FieldWorth, + }) + } + if uu.mutation.WorthCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Column: user.FieldWorth, + }) + } if nodes := uu.mutation.RemovedCardsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -396,6 +443,33 @@ func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { return uuo } +// SetWorth sets the worth field. +func (uuo *UserUpdateOne) SetWorth(u uint) *UserUpdateOne { + uuo.mutation.ResetWorth() + uuo.mutation.SetWorth(u) + return uuo +} + +// SetNillableWorth sets the worth field if the given value is not nil. +func (uuo *UserUpdateOne) SetNillableWorth(u *uint) *UserUpdateOne { + if u != nil { + uuo.SetWorth(*u) + } + return uuo +} + +// AddWorth adds u to worth. +func (uuo *UserUpdateOne) AddWorth(u uint) *UserUpdateOne { + uuo.mutation.AddWorth(u) + return uuo +} + +// ClearWorth clears the value of worth. +func (uuo *UserUpdateOne) ClearWorth() *UserUpdateOne { + uuo.mutation.ClearWorth() + return uuo +} + // AddCardIDs adds the cards edge to Card by ids. func (uuo *UserUpdateOne) AddCardIDs(ids ...int) *UserUpdateOne { uuo.mutation.AddCardIDs(ids...) @@ -575,6 +649,26 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (u *User, err error) { Column: user.FieldName, }) } + if value, ok := uuo.mutation.Worth(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Value: value, + Column: user.FieldWorth, + }) + } + if value, ok := uuo.mutation.AddedWorth(); ok { + _spec.Fields.Add = append(_spec.Fields.Add, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Value: value, + Column: user.FieldWorth, + }) + } + if uuo.mutation.WorthCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeUint, + Column: user.FieldWorth, + }) + } if nodes := uuo.mutation.RemovedCardsIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/entc/integration/hooks/hooks_test.go b/entc/integration/hooks/hooks_test.go index d0c752f50..7eb1e6f83 100644 --- a/entc/integration/hooks/hooks_test.go +++ b/entc/integration/hooks/hooks_test.go @@ -238,3 +238,40 @@ func TestOldValues(t *testing.T) { a8m = client.User.UpdateOne(a8m).SetName("Ariel").SetVersion(a8m.Version + 1).SaveX(ctx) require.Equal(t, "Ariel", a8m.Name) } + +func TestConditions(t *testing.T) { + client := enttest.Open(t, "sqlite3", "file:ent?mode=memory&cache=shared&_fk=1", enttest.WithMigrateOptions(migrate.WithGlobalUniqueID(true))) + defer client.Close() + + var calls int + defer func() { require.Equal(t, 2, calls) }() + client.Card.Use(hook.If(func(next ent.Mutator) ent.Mutator { + return hook.CardFunc(func(ctx context.Context, m *ent.CardMutation) (ent.Value, error) { + require.True(t, m.Op().Is(ent.OpUpdateOne)) + calls++ + return next.Mutate(ctx, m) + }) + }, hook.Or( + hook.HasFields(card.FieldName), + hook.HasClearedFields(card.FieldName), + ))) + client.User.Use(hook.If(func(next ent.Mutator) ent.Mutator { + return hook.UserFunc(func(ctx context.Context, m *ent.UserMutation) (ent.Value, error) { + require.True(t, m.Op().Is(ent.OpUpdate)) + incr, exists := m.AddedWorth() + require.True(t, exists) + require.EqualValues(t, 100, incr) + return next.Mutate(ctx, m) + }) + }, hook.HasAddedFields(user.FieldWorth))) + + ctx := context.Background() + crd := client.Card.Create().SetNumber("9876").SaveX(ctx) + crd = crd.Update().SetName("alexsn").SaveX(ctx) + crd = crd.Update().ClearName().SaveX(ctx) + client.Card.DeleteOne(crd).ExecX(ctx) + + alexsn := client.User.Create().SetName("alexsn").SaveX(ctx) + client.User.Update().Where(user.ID(alexsn.ID)).AddWorth(100).SaveX(ctx) + client.User.DeleteOne(alexsn).ExecX(ctx) +} diff --git a/entc/integration/idtype/ent/hook/hook.go b/entc/integration/idtype/ent/hook/hook.go index 9ab6eefa3..62130a4bf 100644 --- a/entc/integration/idtype/ent/hook/hook.go +++ b/entc/integration/idtype/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/json/ent/hook/hook.go b/entc/integration/json/ent/hook/hook.go index 25dd25e05..e8498a767 100644 --- a/entc/integration/json/ent/hook/hook.go +++ b/entc/integration/json/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/migrate/entv1/hook/hook.go b/entc/integration/migrate/entv1/hook/hook.go index f08b5c0df..3bd5c7adb 100644 --- a/entc/integration/migrate/entv1/hook/hook.go +++ b/entc/integration/migrate/entv1/hook/hook.go @@ -39,14 +39,106 @@ func (f UserFunc) Mutate(ctx context.Context, m entv1.Mutation) (entv1.Value, er return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, entv1.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m entv1.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m entv1.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m entv1.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op entv1.Op) Condition { + return func(_ context.Context, m entv1.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv1.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv1.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv1.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, entv1.Delete|entv1.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk entv1.Hook, op entv1.Op) entv1.Hook { +func If(hk entv1.Hook, cond Condition) entv1.Hook { return func(next entv1.Mutator) entv1.Mutator { return entv1.MutateFunc(func(ctx context.Context, m entv1.Mutation) (entv1.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk entv1.Hook, op entv1.Op) entv1.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, entv1.Delete|entv1.Create) +// +func On(hk entv1.Hook, op entv1.Op) entv1.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, entv1.Update|entv1.UpdateOne) // func Unless(hk entv1.Hook, op entv1.Op) entv1.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/migrate/entv2/hook/hook.go b/entc/integration/migrate/entv2/hook/hook.go index dc33981ec..782667141 100644 --- a/entc/integration/migrate/entv2/hook/hook.go +++ b/entc/integration/migrate/entv2/hook/hook.go @@ -65,14 +65,106 @@ func (f UserFunc) Mutate(ctx context.Context, m entv2.Mutation) (entv2.Value, er return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, entv2.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m entv2.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m entv2.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m entv2.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op entv2.Op) Condition { + return func(_ context.Context, m entv2.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv2.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv2.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m entv2.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, entv2.Delete|entv2.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk entv2.Hook, op entv2.Op) entv2.Hook { +func If(hk entv2.Hook, cond Condition) entv2.Hook { return func(next entv2.Mutator) entv2.Mutator { return entv2.MutateFunc(func(ctx context.Context, m entv2.Mutation) (entv2.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -80,12 +172,20 @@ func On(hk entv2.Hook, op entv2.Op) entv2.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, entv2.Delete|entv2.Create) +// +func On(hk entv2.Hook, op entv2.Op) entv2.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, entv2.Update|entv2.UpdateOne) // func Unless(hk entv2.Hook, op entv2.Op) entv2.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/privacy/ent/hook/hook.go b/entc/integration/privacy/ent/hook/hook.go index d3b5a058f..97469ff78 100644 --- a/entc/integration/privacy/ent/hook/hook.go +++ b/entc/integration/privacy/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f PlanetFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, erro return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/entc/integration/template/ent/hook/hook.go b/entc/integration/template/ent/hook/hook.go index e39b0910d..5f1cbb0c8 100644 --- a/entc/integration/template/ent/hook/hook.go +++ b/entc/integration/template/ent/hook/hook.go @@ -52,14 +52,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -67,12 +159,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/edgeindex/ent/hook/hook.go b/examples/edgeindex/ent/hook/hook.go index 1136dd599..44ac69a46 100644 --- a/examples/edgeindex/ent/hook/hook.go +++ b/examples/edgeindex/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f StreetFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, erro return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/entcpkg/ent/hook/hook.go b/examples/entcpkg/ent/hook/hook.go index 9cea8ed23..d419861c3 100644 --- a/examples/entcpkg/ent/hook/hook.go +++ b/examples/entcpkg/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/m2m2types/ent/hook/hook.go b/examples/m2m2types/ent/hook/hook.go index dc038dd5d..5c4c488ac 100644 --- a/examples/m2m2types/ent/hook/hook.go +++ b/examples/m2m2types/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/m2mbidi/ent/hook/hook.go b/examples/m2mbidi/ent/hook/hook.go index b2532e01e..fd89e6c61 100644 --- a/examples/m2mbidi/ent/hook/hook.go +++ b/examples/m2mbidi/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/m2mrecur/ent/hook/hook.go b/examples/m2mrecur/ent/hook/hook.go index dda5f5337..0df78d829 100644 --- a/examples/m2mrecur/ent/hook/hook.go +++ b/examples/m2mrecur/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/o2m2types/ent/hook/hook.go b/examples/o2m2types/ent/hook/hook.go index 2bb5239b6..8d449ea60 100644 --- a/examples/o2m2types/ent/hook/hook.go +++ b/examples/o2m2types/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/o2mrecur/ent/hook/hook.go b/examples/o2mrecur/ent/hook/hook.go index 385d36d16..2f706f1af 100644 --- a/examples/o2mrecur/ent/hook/hook.go +++ b/examples/o2mrecur/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f NodeFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/o2o2types/ent/hook/hook.go b/examples/o2o2types/ent/hook/hook.go index 71726a0f7..3426eba8c 100644 --- a/examples/o2o2types/ent/hook/hook.go +++ b/examples/o2o2types/ent/hook/hook.go @@ -39,14 +39,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -54,12 +146,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/o2obidi/ent/hook/hook.go b/examples/o2obidi/ent/hook/hook.go index b0c9a4823..64dba8420 100644 --- a/examples/o2obidi/ent/hook/hook.go +++ b/examples/o2obidi/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/o2orecur/ent/hook/hook.go b/examples/o2orecur/ent/hook/hook.go index 9a1287233..dff3b6bed 100644 --- a/examples/o2orecur/ent/hook/hook.go +++ b/examples/o2orecur/ent/hook/hook.go @@ -26,14 +26,106 @@ func (f NodeFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -41,12 +133,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/start/ent/hook/hook.go b/examples/start/ent/hook/hook.go index 6aca7c457..3f05cb246 100644 --- a/examples/start/ent/hook/hook.go +++ b/examples/start/ent/hook/hook.go @@ -52,14 +52,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -67,12 +159,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op. diff --git a/examples/traversal/ent/hook/hook.go b/examples/traversal/ent/hook/hook.go index dd55a2349..0db89c5e9 100644 --- a/examples/traversal/ent/hook/hook.go +++ b/examples/traversal/ent/hook/hook.go @@ -52,14 +52,106 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } -// On executes the given hook only for the given operation. +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. // -// hook.On(Log, ent.Delete|ent.Create) +// Hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) // -func On(hk ent.Hook, op ent.Op) ent.Hook { +func If(hk ent.Hook, cond Condition) ent.Hook { return func(next ent.Mutator) ent.Mutator { return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { - if m.Op().Is(op) { + if cond(ctx, m) { return hk(next).Mutate(ctx, m) } return next.Mutate(ctx, m) @@ -67,12 +159,20 @@ func On(hk ent.Hook, op ent.Op) ent.Hook { } } +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + // Unless skips the given hook only for the given operation. // // hook.Unless(Log, ent.Update|ent.UpdateOne) // func Unless(hk ent.Hook, op ent.Op) ent.Hook { - return On(hk, ^op) + return If(hk, Not(HasOp(op))) } // Reject returns a hook that rejects all operations that match op.