Skip to content

Instantly share code, notes, and snippets.

@notEthan
Created April 20, 2023 00:10
Show Gist options
  • Save notEthan/b8dd826eff666e8b30438f1988c7d707 to your computer and use it in GitHub Desktop.
Save notEthan/b8dd826eff666e8b30438f1988c7d707 to your computer and use it in GitHub Desktop.
JSI filter serialized ActiveRecord
require 'jsi'
# db/model setup
require 'active_record'
dbpath = Pathname.new("tmp.sqlite3")
dbpath.unlink if dbpath.exist?
at_exit { dbpath.unlink }
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database => dbpath
)
ActiveRecord::Schema.define do
create_table :users do |table|
table.column :name, :string
table.column :email, :string
table.column :age, :integer
table.column :secret, :string
end
end
class User < ActiveRecord::Base
end
# record β†’ JSON
user = User.create!(
name: 'Me',
email: 'me@here',
age: 0,
secret: '🀐',
)
user_json = user.serializable_hash # using ActiveRecord's builtin serialization
puts "json"
pp user_json
# β†’ {"id" => 1, "name" => "Me", "email" => "me@here", "age" => 0, "secret" => "🀐"}
# Filtering by _described_ attributes
user_schema = JSI.new_schema({
"$schema" => "http://json-schema.org/draft-07/schema",
"type" => "object",
"properties" => {
"id" => {},
"name" => {"type" => "string"},
# ❌ no "email"
"age" => {"type" => "integer", "minimum" => 1},
# ❌ no "secret"
},
})
user_jsi = user_schema.new_jsi(user_json)
user_filtered = user_jsi.jsi_select_descendents_leaf_first do |node|
# reject nodes which have no schemas that describe them
!node.jsi_schemas.empty?
end
puts "filter described attributes: no email, no secret"
pp user_filtered
# β†’ #{<JSI> "id" => 1, "name" => "Me", "age" => 0}
# Filtering by _excluded_ attributes with `false` schema
user_schema = JSI.new_schema({
"$schema" => "http://json-schema.org/draft-07/schema",
"type" => "object",
"properties" => {
"id" => {},
"name" => {"type" => "string"},
# βœ… "email" is not specifically excluded
"age" => {"type" => "integer", "minimum" => 1},
"secret" => false, # ❌ will exclude "secret"
},
})
user_jsi = user_schema.new_jsi(user_json)
user_filtered = user_jsi.jsi_select_descendents_leaf_first do |node|
# reject nodes described by `false` schema
!node.jsi_schemas.any? { |s| s.schema_content == false }
end
puts "filter excluded attributes: no secret"
pp user_filtered
# β†’ #{<JSI> "id" => 1, "name" => "Me", "email" => "me@here", "age" => 0}
# Filtering by _valid_ attributes (this seems like a bad idea but worth illustrating)
user_schema = JSI.new_schema({
"$schema" => "http://json-schema.org/draft-07/schema",
"type" => "object",
"properties" => {
"id" => {},
"name" => {"type" => "string"},
# βœ… "email" has no schema, nothing makes it invalid
"age" => {"type" => "integer", "minimum" => 1}, # ❌ age=0 fails validation
"secret" => false, # ❌ nothing is valid against `false` schema
},
})
user_jsi = user_schema.new_jsi(user_json)
user_filtered = user_jsi.jsi_select_descendents_leaf_first do |node|
node.jsi_valid?
end
puts "filter valid attributes: no age, no secret"
pp user_filtered
# β†’ #{<JSI> "id" => 1, "name" => "Me", "email" => "me@here"}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment