Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions cedar-policy-core/src/ast/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

use crate::ast::*;
use crate::entities::{err::EntitiesError, json::err::JsonSerializationError, EntityJson};
use crate::evaluator::{EvaluationError, RestrictedEvaluator};
use crate::extensions::Extensions;
use crate::parser::err::ParseErrors;
Expand Down Expand Up @@ -438,6 +439,25 @@ impl Entity {
ancestors,
)
}

/// Write the entity to a json document
pub fn write_to_json(&self, f: impl std::io::Write) -> Result<(), EntitiesError> {
let ejson = EntityJson::from_entity(self)?;
serde_json::to_writer_pretty(f, &ejson).map_err(JsonSerializationError::from)?;
Ok(())
}

pub fn to_json_value(&self) -> Result<serde_json::Value, EntitiesError> {
let ejson = EntityJson::from_entity(self)?;
let v = serde_json::to_value(ejson).map_err(JsonSerializationError::from)?;
Ok(v)
}

pub fn to_json_string(&self) -> Result<String, EntitiesError> {
let ejson = EntityJson::from_entity(self)?;
let string = serde_json::to_string(&ejson).map_err(JsonSerializationError::from)?;
Ok(string)
}
}

impl PartialEq for Entity {
Expand Down
37 changes: 36 additions & 1 deletion cedar-policy-core/src/entities/json/entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use super::{
use crate::ast::{
BorrowedRestrictedExpr, Entity, EntityType, EntityUID, PartialValue, RestrictedExpr,
};
use crate::entities::conformance::EntitySchemaConformanceChecker;
use crate::entities::{
conformance::err::{EntitySchemaConformanceError, UnexpectedEntityTypeError},
schematype_of_partialvalue, Entities, EntitiesError, GetSchemaTypeError, TCComputation,
Expand All @@ -31,8 +32,8 @@ use crate::jsonvalue::JsonValueWithNoDuplicateKeys;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use smol_str::SmolStr;
use std::collections::HashMap;
use std::sync::Arc;
use std::{collections::HashMap, io::Read};

#[cfg(feature = "wasm")]
extern crate tsify;
Expand Down Expand Up @@ -78,6 +79,7 @@ pub struct EntityJsonParser<'e, 's, S: Schema = NoEntitiesSchema> {
}

/// Schema information about a single entity can take one of these forms:
#[derive(Debug)]
enum EntitySchemaInfo<E: EntityTypeDescription> {
/// There is no schema, i.e. we're not doing schema-based parsing
NoSchema,
Expand Down Expand Up @@ -212,6 +214,39 @@ impl<'e, 's, S: Schema> EntityJsonParser<'e, 's, S> {
Ok(entities.into_iter())
}

/// Parse a single entity from an in-memory JSON value
pub fn single_from_json_value(
&self,
value: serde_json::Value,
) -> Result<Entity, EntitiesError> {
let ejson = serde_json::from_value(value).map_err(JsonDeserializationError::from)?;
self.single_from_ejson(ejson)
}

/// Parse a single entity from a JSON string
pub fn single_from_json_str(&self, src: impl AsRef<str>) -> Result<Entity, EntitiesError> {
let ejson = serde_json::from_str(src.as_ref()).map_err(JsonDeserializationError::from)?;
self.single_from_ejson(ejson)
}

/// Parse a single entity from a JSON reader
pub fn single_from_json_file(&self, r: impl Read) -> Result<Entity, EntitiesError> {
let ejson = serde_json::from_reader(r).map_err(JsonDeserializationError::from)?;
self.single_from_ejson(ejson)
}

fn single_from_ejson(&self, ejson: EntityJson) -> Result<Entity, EntitiesError> {
let entity = self.parse_ejson(ejson)?;
match self.schema {
None => Ok(entity),
Some(schema) => {
let checker = EntitySchemaConformanceChecker::new(schema, self.extensions);
checker.validate_entity(&entity)?;
Ok(entity)
}
}
}

/// Internal function that creates an [`Entities`] from a stream of [`EntityJson`].
///
/// If the `EntityJsonParser` has a `schema`, this also adds `Action`
Expand Down
1 change: 1 addition & 0 deletions cedar-policy-validator/src/coreschema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl<'a> entities::Schema for CoreSchema<'a> {
}

/// Struct which carries enough information that it can impl Core's `EntityTypeDescription`
#[derive(Debug)]
pub struct EntityTypeDescription {
/// Core `EntityType` this is describing
core_type: ast::EntityType,
Expand Down
2 changes: 2 additions & 0 deletions cedar-policy/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- JSON representation for Policy Sets, along with methods like
`::from_json_value/file/str` and `::to_json` for `PolicySet`. (#783,
resolving #549)
- Added methods for reading and writing individual `Entity`s as JSON
(resolving #807)

### Changed

Expand Down
79 changes: 79 additions & 0 deletions cedar-policy/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use miette::Diagnostic;
use ref_cast::RefCast;
use smol_str::SmolStr;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::io::Read;
use std::str::FromStr;

/// Extended functionality for `Entities` struct
Expand Down Expand Up @@ -260,6 +261,84 @@ impl Entity {
ancestors.into_iter().map(EntityUid::new).collect(),
)
}

/// Parse an entity from an in-memory JSON value
/// If a schema is provided, it is handled identically to
/// [Entities](https://docs.rs/cedar-policy/latest/cedar_policy/struct.Entities.html#method.from_json_str)
Copy link
Contributor

@john-h-kastner-aws john-h-kastner-aws May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just the auto doc link?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you auto-doc link to a specific method?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Entities::from_json_str] i think

pub fn from_json_value(
value: serde_json::Value,
schema: Option<&Schema>,
) -> Result<Self, EntitiesError> {
let schema = schema.map(|s| cedar_policy_validator::CoreSchema::new(&s.0));
let eparser = cedar_policy_core::entities::EntityJsonParser::new(
schema.as_ref(),
Extensions::all_available(),
cedar_policy_core::entities::TCComputation::ComputeNow,
);
eparser.single_from_json_value(value).map(Self)
}

/// Parse an entity from a JSON string
/// If a schema is provided, it is handled identically to
/// [Entities](https://docs.rs/cedar-policy/latest/cedar_policy/struct.Entities.html#method.from_json_str)
pub fn from_json_str(
src: impl AsRef<str>,
schema: Option<&Schema>,
) -> Result<Self, EntitiesError> {
let schema = schema.map(|s| cedar_policy_validator::CoreSchema::new(&s.0));
let eparser = cedar_policy_core::entities::EntityJsonParser::new(
schema.as_ref(),
Extensions::all_available(),
cedar_policy_core::entities::TCComputation::ComputeNow,
);
eparser.single_from_json_str(src).map(Self)
}

/// Parse an entity from a JSON reader
/// If a schema is provided, it is handled identically to
/// [Entities](https://docs.rs/cedar-policy/latest/cedar_policy/struct.Entities.html#method.from_json_str)
pub fn from_json_file(f: impl Read, schema: Option<&Schema>) -> Result<Self, EntitiesError> {
let schema = schema.map(|s| cedar_policy_validator::CoreSchema::new(&s.0));
let eparser = cedar_policy_core::entities::EntityJsonParser::new(
schema.as_ref(),
Extensions::all_available(),
cedar_policy_core::entities::TCComputation::ComputeNow,
);
eparser.single_from_json_file(f).map(Self)
}

/// Dump an `Entity` object into an entity JSON file.
///
/// The resulting JSON will be suitable for parsing in via
/// `from_json_*`, and will be parse-able even with no [`Schema`].
///
/// To read an `Entity` object from JSON , use
/// [`from_json_file`], [`from_json_value`], or [`from_json_str`].
pub fn write_to_json(&self, f: impl std::io::Write) -> Result<(), EntitiesError> {
self.0.write_to_json(f)
}

/// Dump an `Entity` object into an in-memory JSON object.
///
/// The resulting JSON will be suitable for parsing in via
/// `from_json_*`, and will be parse-able even with no `Schema`.
///
/// To read an `Entity` object from JSON , use
/// [`from_json_file`], [`from_json_value`], or [`from_json_str`].
pub fn to_json_value(&self) -> Result<serde_json::Value, EntitiesError> {
self.0.to_json_value()
}

/// Dump an `Entity` object into a JSON string.
///
/// The resulting JSON will be suitable for parsing in via
/// `from_json_*`, and will be parse-able even with no `Schema`.
///
/// To read an `Entity` object from JSON , use
/// [`from_json_file`], [`from_json_value`], or [`from_json_str`].
pub fn to_json_string(&self) -> Result<String, EntitiesError> {
self.0.to_json_string()
}
}

impl std::fmt::Display for Entity {
Expand Down
Loading