Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a builtin to remove a field #139

Open
cueckoo opened this issue Jul 3, 2021 · 3 comments
Open

Add a builtin to remove a field #139

cueckoo opened this issue Jul 3, 2021 · 3 comments
Labels
FeatureRequest New feature or request NeedsDesign Functionality seems desirable, but not sure how it should look like.

Comments

@cueckoo
Copy link
Collaborator

cueckoo commented Jul 3, 2021

Originally opened by @nlewo in cuelang/cue#139

To create a new structure by overriding an existing structure, it would be nice to be able to remove a field from this structure. This field could then be modified with unification.

For instance, let's consider the structure:

s : { a : "a"
      b : { ba : "ba" }
     }

Now suppose I want to create a modified version r of s:

r : { a : "a"
      b : { ba : 2 } //`where 2 is len(r.b.ba)
     }

With a removeField builtin r could be created like:

r = removeField(s.b.ba) & { b ba : len(s.b.ba) }

Note this can be implemented with several nested field comprehensions, but it's really unreadable!

r = { for k, v in s if k != "b" { "\(k)" : v } } &
       { b : { for k, v in s.b if k =! "ba" { "\(k)" : v }} & 
              { ba : len(s.b.ba) }
       }
     }
  • Would it be possible to add such kind of builtin?
  • How should look like removeField arguments?
@cueckoo cueckoo added FeatureRequest New feature or request NeedsDesign Functionality seems desirable, but not sure how it should look like. labels Jul 3, 2021
@cueckoo
Copy link
Collaborator Author

cueckoo commented Jul 3, 2021

Original reply by @mpvl in cuelang/cue#139 (comment)

I can imagine something like struct.Sub({a: 3, c d: 4, c e: 5}, {c d: _}) => {a: 3, c e: 5}.

@cueckoo
Copy link
Collaborator Author

cueckoo commented Jul 3, 2021

Original reply by @rudolph9 in cuelang/cue#139 (comment)

This touches on something I presented in @mpvl proposal cuelang/cue#165 (comment)

The syntax is still conflicting with other things but in the spirit of what is described in the link you could write ([{a: 3, c d: 4, c: e: 5}] & [{c: d: _|_}]) // => {a: 3, c: e: 5}

@cueckoo
Copy link
Collaborator Author

cueckoo commented Jul 3, 2021

Original reply by @rudolph9 in cuelang/cue#139 (comment)

@mpvl Still a little rough but you can do this with current functionality v0.0.14:

Omit: {
	orig: {}
	pathsToOmit: {[_]: true | {}}
	result: {
		pathsToOmit_ = pathsToOmit
		for k, v in orig {
			valueIsStruct = (isValueStruct & {value: v}).result
			inPathToOmit = (isKeySet & {struct: pathsToOmit_, key: "\(k)"}).result
			definatelyShouldOmit = inPathToOmit && (isValueBool & {value: pathsToOmit_[k]}).result
			if !definatelyShouldOmit {
				if valueIsStruct {
					"\(k)": (Omit & {orig: v, pathsToOmit: pathsToOmit_[k]}).result
				}
				if !valueIsStruct {
					"\(k)": v
				}
			}
		}
	}
}

Keep: {
	orig: {}
	pathsToKeep: {[_]: true | {}}
	result: {
		pathsToKeep_ = pathsToKeep
		for k, v in orig {
			valueIsStruct = (isValueStruct & {value: v}).result
			inPathToKeep = (isKeySet & {struct: pathsToKeep_, key: k}).result
			definatelyShouldKeep = inPathToKeep && (isValueBool & {value: pathsToKeep_[k]}).result
			if definatelyShouldKeep {
				"\(k)": v
			}
			if inPathToKeep && valueIsStruct {
				"\(k)": (Keep & {orig: v, pathsToKeep: pathsToKeep_[k]}).result
			}
		}
	}
}

testOmitAndKeep: {
	data: {a: 3, c: {d: 4}, c: e: 5}
	paths: {c: d: true}
	pathsOmit: (Omit & {orig: data, pathsToOmit: paths}).result
	pathsKeep: (Keep & {orig: data, pathsToKeep: paths}).result
}

isKeySet :: {
	struct: {...} // set the key we're checking
	key:          string
	result:       (struct & {[_]: _ | *_|_})[key] != _|_
}

testIsKeySet: {
	iskeySetFoo:               (isKeySet & {struct: {ban:             "something"}, key:  "foo"}).result
	iskeySetBan:               (isKeySet & {struct: {ban:             "something"}, key:  "ban"}).result
	iskeySetFooStruct:         (isKeySet & {struct: {ban: {asdfafoo:  "something"}}, key: "foo"}).result
	iskeySetBanStruct:         (isKeySet & {struct: {ban: {asdfasfoo: "something"}}, key: "ban"}).result
	iskeySetBanStruct:         (isKeySet & {struct: {ban: {asdfasfoo: "something"}}, key: "ban"}).result
	iskeySetBanStructAnything: (isKeySet & {struct: {ban:             _}, key:            "ban"}).result
	iskeySetPathThing:         (isKeySet & {struct: {c: d:            true}, key:         "c"}).result
}

isValueStruct :: {
	value:  _
	result: ((value & {}) | *_|_) != _|_
}

testIsValueStruct: {
	isValueStructStruct: (isValueStruct & {value: {foo: "bar"}}).result
	isValueStructNull:   (isValueStruct & {value:       null}).result
	isValueStructInt:    (isValueStruct & {value:       int}).result
	isValueStructInt4:   (isValueStruct & {value:       4}).result
	isValueStructString: (isValueStruct & {value:       "foo"}).result
	isValueStructBool:   (isValueStruct & {value:       bool}).result
}

isValueBool :: {
	value:  _
	result: ((value & bool) | *_|_) != _|_
}

testIsValueBoolBool: {
	isValueBoolBoolBool:   (isValueBool & {value:       true}).result
	isValueBoolBoolStruct: (isValueBool & {value: {foo: "bar"}}).result
	isValueBoolStruct:     (isValueBool & {value: {foo: "bar"}}).result
	isValueBoolNull:       (isValueBool & {value:       null}).result
	isValueBoolInt:        (isValueBool & {value:       int}).result
	isValueBoolInt4:       (isValueBool & {value:       4}).result
	isValueBoolString:     (isValueBool & {value:       "foo"}).result
}
:!cue eval %!e(MISSING) testOmitAndKeep
data: {
    a: 3
    c: {
        d: 4
        e: 5
    }
}
paths: {
    c: {
        d: true
    }
}
pathsOmit: {
    a: 3
    c: {
        e: 5
    }
}
pathsKeep: {
    c: {
        d: 4
    }
}

The impl touches on some of our previous threads surrounding comprehensions and structural cycles but I believe falls within what is described in the spec.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
FeatureRequest New feature or request NeedsDesign Functionality seems desirable, but not sure how it should look like.
Projects
None yet
Development

No branches or pull requests

3 participants