Skip to content

Commit 6c5c8d6

Browse files
committed
fix: Return a map when dissociating a record basis field
Fixes babashka/babashka#1886.
1 parent ec593ee commit 6c5c8d6

File tree

3 files changed

+47
-20
lines changed

3 files changed

+47
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ SCI is used in [babashka](https://github.com/babashka/babashka),
1616
- Fix [#997](https://github.com/babashka/sci/issues/997): Var is mistaken for local when used under the same name in a `let` body
1717
- Fix [#1001](https://github.com/babashka/sci/issues/1001): JS interop with reserved js keyword fails (regression of [#987](https://github.com/babashka/sci/issues/987))
1818
- `sci.impl.Reflector` was rewritten into Clojure
19+
- Fix [babashka/babashka#1886](https://github.com/babashka/babashka/issues/1886): Return a map when dissociating a
20+
record basis field.
1921

2022
## 0.10.49 (2025-08-22)
2123

src/sci/impl/records.cljc

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
#?(:clj
3737
(deftype SciRecord [rec-name
3838
type
39-
var ext-map
39+
basis-fields
40+
var
41+
ext-map
4042
^:unsynchronized-mutable my_hash
4143
^:unsynchronized-mutable my_hasheq]
4244
clojure.lang.IRecord ;; marker interface
@@ -65,7 +67,7 @@
6567
(meta ext-map))
6668
(withMeta [_ m]
6769
(SciRecord.
68-
rec-name type var (with-meta ext-map m) 0 0))
70+
rec-name type var basis-fields (with-meta ext-map m) 0 0))
6971

7072
clojure.lang.ILookup
7173
(valAt [_this k]
@@ -94,9 +96,11 @@
9496
(iterator [_this]
9597
(clojure.lang.RT/iter ext-map))
9698
(assoc [_this k v]
97-
(SciRecord. rec-name type var (assoc ext-map k v) 0 0))
99+
(SciRecord. rec-name type basis-fields var (assoc ext-map k v) 0 0))
98100
(without [_this k]
99-
(SciRecord. rec-name type var (dissoc ext-map k) 0 0))
101+
(if (contains? basis-fields k)
102+
(dissoc ext-map k)
103+
(SciRecord. rec-name type basis-fields var (dissoc ext-map k) 0 0)))
100104

101105
java.util.Map
102106
java.io.Serializable
@@ -144,13 +148,14 @@
144148
#?(:cljs
145149
(deftype SciRecord [rec-name
146150
type
151+
basis-fields
147152
var ext-map
148153
^:mutable my_hash]
149154
IRecord ;; marker interface
150155

151156
ICloneable
152157
(-clone [_]
153-
(new SciRecord rec-name type var ext-map my_hash))
158+
(new SciRecord rec-name type basis-fields var ext-map my_hash))
154159

155160
IHash
156161
(-hash [_]
@@ -177,7 +182,7 @@
177182
IWithMeta
178183
(-with-meta [_ m]
179184
(new SciRecord
180-
rec-name type var (with-meta ext-map m) my_hash))
185+
rec-name type basis-fields var (with-meta ext-map m) my_hash))
181186

182187
ILookup
183188
(-lookup [_ k]
@@ -201,11 +206,13 @@
201206
(-contains-key? [_ k]
202207
(-contains-key? ext-map k))
203208
(-assoc [_ k v]
204-
(new SciRecord rec-name type var (assoc ext-map k v) nil))
209+
(new SciRecord rec-name type basis-fields var (assoc ext-map k v) nil))
205210

206211
IMap
207212
(-dissoc [_ k]
208-
(new SciRecord rec-name type var (dissoc ext-map k) nil))
213+
(if (contains? basis-fields k)
214+
(dissoc ext-map k)
215+
(new SciRecord rec-name type basis-fields var (dissoc ext-map k) nil)))
209216

210217
ISeqable
211218
(-seq [_]
@@ -242,10 +249,10 @@
242249
(defmethod print-method SciRecord [v w]
243250
(-sci-print-method v w)))
244251

245-
#?(:clj (defn ->record-impl [rec-name type var m]
246-
(SciRecord. rec-name type var m 0 0))
247-
:cljs (defn ->record-impl [rec-name type var m]
248-
(SciRecord. rec-name type var m nil)))
252+
#?(:clj (defn ->record-impl [rec-name type basis-fields var m]
253+
(SciRecord. rec-name type basis-fields var m 0 0))
254+
:cljs (defn ->record-impl [rec-name type basis-fields var m]
255+
(SciRecord. rec-name type basis-fields var m nil)))
249256

250257
(defn defrecord [[_fname & _ :as form] _ record-name fields & raw-protocol-impls]
251258
(let [ctx (store/get-ctx)]
@@ -332,15 +339,22 @@
332339
([~@arg-syms]
333340
(~constructor-fn-sym ~@arg-syms nil nil))
334341
([~@arg-syms meta# ext#]
335-
(sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name)
342+
(sci.impl.records/->record-impl '~rec-type
343+
~rec-type
344+
(set (map keyword ~keys))
345+
(var ~record-name)
336346
(cond-> (zipmap ~keys ~arg-syms)
337-
ext# (merge ext#)
338-
meta# (with-meta meta#)))))
347+
ext# (merge ext#)
348+
meta# (with-meta meta#)))))
339349
(defn ~factory-fn-sym
340350
([~@arg-syms]
341351
(~constructor-fn-sym ~@arg-syms nil nil)))
342352
(defn ~map-factory-sym [m#]
343-
(sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name) (merge '~nil-map m#)))
353+
(sci.impl.records/->record-impl '~rec-type
354+
~rec-type
355+
(set (map keyword ~keys))
356+
(var ~record-name)
357+
(merge '~nil-map m#)))
344358
~@protocol-impls
345359
~record-name)))))
346360

test/sci/records_test.cljc

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
(ns sci.records-test
22
(:require
3-
[clojure.string :as str]
4-
[clojure.test :refer [deftest is testing]]
5-
[sci.core :as sci]
6-
[sci.test-utils :as tu]))
3+
[clojure.string :as str]
4+
[clojure.test :refer [are deftest is testing]]
5+
[sci.core :as sci]
6+
[sci.test-utils :as tu]))
77

88
(deftest protocol-test
99
(let [prog "
@@ -244,3 +244,14 @@
244244
(deftest map-constructor-nil-test
245245
(is (true? (sci/eval-string "(defrecord Foo [a]) (and (contains? (map->Foo {}) :a)
246246
(nil? (:a (map->Foo {}))))"))))
247+
248+
(deftest dissoc-test
249+
(testing "dissoc returns a map if any record basis field is removed"
250+
(are [expected prog] (= expected (with-out-str (print (tu/eval* prog {}))))
251+
"{:a 1, :b 2}" "(defrecord Foo [a b c]) (def r (->Foo 1 2 3)) (dissoc r :c)"
252+
"{:a 1, :b 2}" "(defrecord Foo [a b c]) (def r (->Foo 1 2 3)) (dissoc r :c :d)"
253+
"{}" "(defrecord Foo [a b c]) (def r (->Foo 1 2 3)) (dissoc r :a :b :c)"))
254+
(testing "dissoc keeps record type if no record basis field is removed"
255+
(are [expected prog] (= expected (with-out-str (print (tu/eval* prog {}))))
256+
"#user.Foo{:a 1, :b 2, :c 3}" "(defrecord Foo [a b c]) (def r (->Foo 1 2 3)) (dissoc r :d)"
257+
"#user.Foo{:a 1, :b 2, :c 3, :e 5}" "(defrecord Foo [a b c]) (def r (->Foo 1 2 3)) (-> r (assoc :d 4 :e 5) (dissoc :d))")))

0 commit comments

Comments
 (0)