Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Add a builtin to remove a field #139

Closed
nlewo opened this issue Oct 3, 2019 · 4 comments
Closed

Add a builtin to remove a field #139

nlewo opened this issue Oct 3, 2019 · 4 comments
Labels
FeatureRequest New feature or request NeedsDesign Functionality seems desirable, but not sure how it should look like.

Comments

@nlewo
Copy link
Contributor

nlewo commented Oct 3, 2019

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?
@mpvl
Copy link
Contributor

mpvl commented Oct 4, 2019

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

@mpvl mpvl added FeatureRequest New feature or request NeedsDesign Functionality seems desirable, but not sure how it should look like. labels Oct 4, 2019
@rudolph9
Copy link
Contributor

This touches on something I presented in @mpvl proposal #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}

@rudolph9
Copy link
Contributor

rudolph9 commented Nov 21, 2019

@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 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.

@cueckoo
Copy link

cueckoo commented Jul 3, 2021

This issue has been migrated to cue-lang/cue#139.

For more details about CUE's migration to a new home, please see cue-lang/cue#1078.

@cueckoo cueckoo closed this as completed Jul 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
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

4 participants