private bool IsProcedural(out IProceduralEntityResource proceduralResource, out IEntityResource entityResource, out IEntityResourceProviderInternal provider) { proceduralResource = null; entityResource = null; provider = null; if (IResource is IEntityResource _entityResource) { entityResource = _entityResource; } else { return(false); } if (!EntityResourceProviders.TryGetValue(entityResource.Provider, out provider) || !(provider is IProceduralEntityResourceProvider)) { return(false); } var resource = entityResource; if (provider.SelectProceduralResources().FirstOrDefault(r => r.Name == resource.Name) is IProceduralEntityResource _dynamicResource) { proceduralResource = _dynamicResource; } else { return(false); } return(true); }
internal static bool IsValid(IEntityResource resource, out string reason) { if (resource.InterfaceType != null) { var interfaceName = resource.InterfaceType.RESTarTypeName(); var members = resource.InterfaceType.GetDeclaredProperties(); if (members.ContainsKey("objectno")) { reason = $"Invalid Interface '{interfaceName}' assigned to resource '{resource.Name}'. " + "Interface contained a property with a reserved name: 'ObjectNo'"; return(false); } if (members.ContainsKey("objectid")) { reason = $"Invalid Interface '{interfaceName}' assigned to resource '{resource.Name}'. " + "Interface contained a property with a reserved name: 'ObjectID'"; return(false); } } if (resource.Type.ImplementsGenericInterface(typeof(IProfiler <>))) { reason = $"Invalid IProfiler interface implementation for resource type '{resource.Name}'. " + "Starcounter database resources use their default profilers, and cannot implement IProfiler"; return(false); } reason = null; return(true); }
internal static ResourceProfile Make <T>(IEntityResource <T> resource, Func <IEnumerable <T>, long> byteCounter) where T : class { var sqlName = typeof(T).RESTarTypeName().Fnuttify(); var domain = SELECT <T>(sqlName); var domainCount = COUNT(sqlName); long totalBytes, sampleSize; if (domainCount <= singleSampleCutoff) { sampleSize = domainCount; totalBytes = byteCounter(domain); } else { var step = domainCount / singleSampleCutoff; var sample = domain.Where((item, index) => index % step == 0).ToList(); sampleSize = sample.Count; var total = byteCounter(sample) / decimal.Divide(sampleSize, domainCount); totalBytes = decimal.ToInt64(total); } return(new ResourceProfile { Resource = resource.Name, NumberOfEntities = domainCount, ApproximateSize = new ResourceSize(totalBytes), SampleSize = sampleSize }); }
/// <summary> /// Creates profiles for Starcounter tables /// </summary> public static ResourceProfile Profile(IEntityResource <T> resource) => ResourceProfile.Make(resource, rows => { var resourceSQLName = typeof(T).RESTarTypeName(); var scColumns = Db.SQL <Column>(ColumnByTable, resourceSQLName).Select(c => c.Name).ToList(); var columns = resource.Members.Values.Where(p => scColumns.Contains(p.Name)).ToList(); return(rows.Sum(e => columns.Sum(p => p.ByteCount(e)) + 16)); });
internal Rename(IEntityResource resource, string keys, out ICollection <string> dynamicDomain) { keys.Split(',').ForEach(keyString => { var(termKey, newName) = keyString.TSplit(keys.Contains("->") ? "->" : "-%3E"); Add(resource.MakeOutputTerm(termKey.ToLower(), null), newName); }); dynamicDomain = Values; }
public async Task ResourceAuthenticate <T>(IRequest <T> request, IEntityResource <T> resource) where T : class { if (request.Context.Client.ResourceAuthMappings.ContainsKey(resource)) { return; } var authResults = await resource.AuthenticateAsync(request).ConfigureAwait(false); if (authResults.Success) { request.Context.Client.ResourceAuthMappings[resource] = default; } else { throw new FailedResourceAuthentication(authResults.FailedReason); } }
internal static bool IsValid(IEntityResource resource, TypeCache typeCache, out string reason) { if (resource.InterfaceType != null) { var interfaceName = resource.InterfaceType.GetRESTableTypeName(); var members = typeCache.GetDeclaredProperties(resource.InterfaceType); if (members.ContainsKey("objectno")) { reason = $"Invalid Interface '{interfaceName}' assigned to resource '{resource.Name}'. " + "Interface contained a property with a reserved name: 'ObjectNo'"; return(false); } if (members.ContainsKey("objectid")) { reason = $"Invalid Interface '{interfaceName}' assigned to resource '{resource.Name}'. " + "Interface contained a property with a reserved name: 'ObjectID'"; return(false); } } reason = null; return(true); }
internal OrderBy(IEntityResource resource, Term term) { Resource = resource; Term = term; }
internal static MetaConditions Parse(IReadOnlyCollection <IUriCondition> uriMetaConditions, IEntityResource resource, TermFactory termFactory) { if (uriMetaConditions?.Any() != true) { return(null); } var renames = uriMetaConditions.Where(c => c.Key.EqualsNoCase("rename")); var others = uriMetaConditions.Where(c => !c.Key.EqualsNoCase("rename")); var metaConditions = new MetaConditions { Empty = false }; ICollection <string> dynamicDomain = default; void make(IEnumerable <IUriCondition> conditions) { foreach (var condition in conditions) { var(key, op, valueLiteral) = (condition.Key, condition.Operator, condition.ValueLiteral); if (op != EQUALS) { throw new InvalidSyntax(InvalidMetaConditionOperator, "Invalid operator for meta-condition. One and only one '=' is allowed"); } if (!Enum.TryParse(key, true, out RESTableMetaCondition metaCondition)) { throw new InvalidSyntax(InvalidMetaConditionKey, $"Invalid meta-condition '{key}'. Available meta-conditions: " + $"{string.Join(", ", EnumMember<RESTableMetaCondition>.Names)}"); } var expectedType = metaCondition.GetExpectedType(); if (valueLiteral == "∞") { valueLiteral = int.MaxValue.ToString(); } else if (valueLiteral == "-∞") { valueLiteral = int.MinValue.ToString(); } var(first, length) = (valueLiteral.FirstOrDefault(), valueLiteral.Length); switch (first) { case '\'': case '\"': if (length > 1 && valueLiteral[length - 1] == first) { valueLiteral = valueLiteral.Substring(1, length - 2); } break; } object value; try { value = Convert.ChangeType(valueLiteral, expectedType); } catch { throw new InvalidSyntax(InvalidMetaConditionValueType, $"Invalid data type for value '{valueLiteral}' assigned to meta-condition '{key}'. Expected {GetTypeString(expectedType)}."); } switch (metaCondition) { case RESTableMetaCondition.Unsafe: metaConditions.Unsafe = (bool)value; break; case RESTableMetaCondition.Limit: metaConditions.Limit = (int)value; break; case RESTableMetaCondition.Offset: metaConditions.Offset = (int)value; break; case RESTableMetaCondition.Order_asc: { var term = termFactory.MakeOutputTerm(resource, (string)value, dynamicDomain); metaConditions.OrderBy = new OrderByAscending(resource, term); break; } case RESTableMetaCondition.Order_desc: { var term = termFactory.MakeOutputTerm(resource, (string)value, dynamicDomain); metaConditions.OrderBy = new OrderByDescending(resource, term); break; } case RESTableMetaCondition.Select: { var selectKeys = (string)value; var domain = dynamicDomain; var terms = selectKeys .Split(',') .Distinct() .Select(selectKey => termFactory.MakeOutputTerm(resource, selectKey, domain)); metaConditions.Select = new Select(terms); break; } case RESTableMetaCondition.Add: { var addKeys = (string)value; var domain = dynamicDomain; var terms = addKeys .ToLower() .Split(',') .Distinct() .Select(addKey => termFactory.MakeOutputTerm(resource, addKey, domain)); metaConditions.Add = new Add(terms); break; } case RESTableMetaCondition.Rename: { var renameKeys = (string)value; var terms = renameKeys.Split(',').Select(keyString => { var(termKey, newName) = keyString.TSplit(renameKeys.Contains("->") ? "->" : "-%3E"); return ( termFactory.MakeOutputTerm(resource, termKey.ToLowerInvariant(), null), newName ); }); metaConditions.Rename = new Rename(terms, out dynamicDomain); break; } case RESTableMetaCondition.Distinct: if ((bool)value) { metaConditions.Distinct = new Distinct(); } break; case RESTableMetaCondition.Search: metaConditions.Search = new Search((string)value); break; case RESTableMetaCondition.Search_regex: metaConditions.Search = new RegexSearch((string)value); break; case RESTableMetaCondition.Safepost: metaConditions.SafePost = (string)value; break; default: throw new ArgumentOutOfRangeException(); } } } make(renames); make(others); metaConditions.Processors = new IProcessor[] { metaConditions.Add, metaConditions.Rename, metaConditions.Select }.Where(p => p != null).ToArray(); metaConditions.HasProcessors = metaConditions.Processors.Any(); metaConditions.CanUseExternalCounter = metaConditions.Search == null && metaConditions.Distinct == null && metaConditions.Limit.Number == -1 && metaConditions.Offset.Number == 0; if (metaConditions.OrderBy != null) { if (metaConditions.Rename?.Any(p => p.Key.Key.EqualsNoCase(metaConditions.OrderBy.Key)) == true && !metaConditions.Rename.Any(p => p.Value.EqualsNoCase(metaConditions.OrderBy.Key))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, $"The {(metaConditions.OrderBy is OrderByAscending ? RESTableMetaCondition.Order_asc : RESTableMetaCondition.Order_desc)} " + "meta-condition cannot refer to a property x that is to be renamed " + "unless some other property is renamed to x"); } } if (metaConditions.Select != null && metaConditions.Rename != null) { if (metaConditions.Select.Any(pc => metaConditions.Rename.Any(p => p.Key.Key.EqualsNoCase(pc.Key)) && !metaConditions.Rename.Any(p => p.Value.EqualsNoCase(pc.Key)))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, "A 'Select' meta-condition cannot refer to a property x that is " + "to be renamed unless some other property is renamed to x. Use the " + "new property name instead."); } } return(metaConditions); }
internal static IAsyncEnumerable <T> Validate <T>(this IAsyncEnumerable <T> entities, IEntityResource <T> resource, RESTableContext context) where T : class { return(resource.Validate(entities, context)); }
/// <inheritdoc /> protected override bool IsValid(IEntityResource resource, out string reason) => StarcounterOperations <object> .IsValid(resource, out reason);
internal static void RunResourceAuthentication <T>(this IRequest <T> request, IEntityResource <T> resource) where T : class { if (request.Context.Client.ResourceAuthMappings.ContainsKey(resource)) { return; } var authResults = resource.Authenticate(request); if (authResults.Success) { request.Context.Client.ResourceAuthMappings[resource] = default; } else { throw new FailedResourceAuthentication(authResults.Reason); } }
internal static MetaConditions Parse(IReadOnlyCollection <IUriCondition> uriMetaConditions, IEntityResource resource) { if (!uriMetaConditions.Any()) { return(null); } var renames = uriMetaConditions.Where(c => c.Key.EqualsNoCase("rename")); var regular = uriMetaConditions.Where(c => !c.Key.EqualsNoCase("rename")); var mc = new MetaConditions { Empty = false }; ICollection <string> dynamicDomain = default; void make(IEnumerable <IUriCondition> conds) => conds.ForEach(cond => { var(key, op, valueLiteral) = (cond.Key, cond.Operator, cond.ValueLiteral); if (op != EQUALS) { throw new InvalidSyntax(InvalidMetaConditionOperator, "Invalid operator for meta-condition. One and only one '=' is allowed"); } if (!Enum.TryParse(key, true, out RESTarMetaCondition metaCondition)) { throw new InvalidSyntax(InvalidMetaConditionKey, $"Invalid meta-condition '{key}'. Available meta-conditions: {AllMetaConditions}"); } var expectedType = metaCondition.GetExpectedType(); switch (valueLiteral) { case null: case "null": case "": return; case "∞": valueLiteral = int.MaxValue.ToString(); break; case "-∞": valueLiteral = int.MinValue.ToString(); break; } var(first, length) = (valueLiteral.FirstOrDefault(), valueLiteral.Length); switch (first) { case '\'': case '\"': if (length > 1 && valueLiteral[length - 1] == first) { valueLiteral = valueLiteral.Substring(1, length - 2); } break; } dynamic value; try { value = Convert.ChangeType(valueLiteral, expectedType) ?? throw new Exception(); } catch { throw new InvalidSyntax(InvalidMetaConditionValueType, $"Invalid data type assigned to meta-condition '{key}'. Expected {GetTypeString(expectedType)}."); } switch (metaCondition) { case RESTarMetaCondition.Unsafe: mc.Unsafe = value; break; case RESTarMetaCondition.Limit: mc.Limit = (Limit)(int)value; break; case RESTarMetaCondition.Offset: mc.Offset = (Offset)(int)value; break; case RESTarMetaCondition.Order_asc: mc.OrderBy = new OrderByAscending(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Order_desc: mc.OrderBy = new OrderByDescending(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Select: mc.Select = new Select(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Add: mc.Add = new Add(resource, (string)value, dynamicDomain); break; case RESTarMetaCondition.Rename: mc.Rename = new Rename(resource, (string)value, out dynamicDomain); break; case RESTarMetaCondition.Distinct: if ((bool)value) { mc.Distinct = new Distinct(); } break; case RESTarMetaCondition.Search: mc.Search = new Search((string)value); break; case RESTarMetaCondition.Search_regex: mc.Search = new RegexSearch((string)value); break; case RESTarMetaCondition.Safepost: mc.SafePost = value; break; case RESTarMetaCondition.Format: var formatName = (string)value; var format = DbOutputFormat.GetByName(formatName) ?? throw new InvalidSyntax(UnknownFormatter, $"Could not find any output format by '{formatName}'. See RESTar.Admin.OutputFormat " + "for available output formats"); mc.Formatter = format.Format; break; default: throw new ArgumentOutOfRangeException(); } }); make(renames); make(regular); mc.Processors = new IProcessor[] { mc.Add, mc.Rename, mc.Select }.Where(p => p != null).ToArray(); mc.HasProcessors = mc.Processors.Any(); mc.CanUseExternalCounter = mc.Search == null && mc.Distinct == null && mc.Limit.Number == -1 && mc.Offset.Number == 0; if (mc.OrderBy != null) { if (mc.Rename?.Any(p => p.Key.Key.EqualsNoCase(mc.OrderBy.Key)) == true && !mc.Rename.Any(p => p.Value.EqualsNoCase(mc.OrderBy.Key))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, $"The {(mc.OrderBy is OrderByAscending ? RESTarMetaCondition.Order_asc : RESTarMetaCondition.Order_desc)} " + "meta-condition cannot refer to a property x that is to be renamed " + "unless some other property is renamed to x"); } } if (mc.Select != null && mc.Rename != null) { if (mc.Select.Any(pc => mc.Rename.Any(p => p.Key.Key.EqualsNoCase(pc.Key)) && !mc.Rename.Any(p => p.Value.EqualsNoCase(pc.Key)))) { throw new InvalidSyntax(InvalidMetaConditionSyntax, "A 'Select' meta-condition cannot refer to a property x that is " + "to be renamed unless some other property is renamed to x. Use the " + "new property name instead."); } } return(mc); }
public void SetEntityResource(IEntityResource resource) => EntityResource = resource;
protected Task OnDeleteResource(IEntityResource resource) { Collection.Remove((T)resource); HandleModificationState.EntityDeleted((T)resource); return(Task.CompletedTask); }
/// <inheritdoc /> protected override bool IsValid(IEntityResource resource, out string reason) { reason = null; return(true); }
/// <inheritdoc /> public OrderByAscending(IEntityResource resource, string key, ICollection <string> dynamicMembers) : base(resource, key, dynamicMembers) { }
internal OrderBy(IEntityResource resource, string key, ICollection <string> dynamicMembers) { Resource = resource; Term = resource.MakeOutputTerm(key, dynamicMembers); }
/// <summary> /// Creates profiles for DDictionary tables /// </summary> public static ResourceProfile Profile(IEntityResource <T> resource) { return(ResourceProfile.Make(resource, rows => rows.Sum(row => row.KeyValuePairs.Sum(kvp => kvp.ByteCount) + 16))); }
private static ResourceProfile DDProfiler <T>(IEntityResource <T> r) where T : DDictionary => DDictionaryOperations <T> .Profile(r);
protected override ResourceProfile DefaultProfile <T>(IEntityResource <T> resource) => StarcounterOperations <T> .Profile(resource);
internal Select(IEntityResource resource, string keys, ICollection <string> dynDomain) => keys
/// <inheritdoc /> protected override ResourceProfile DefaultProfile <T>(IEntityResource <T> resource) => DDictionaryOperations <T> .Profile(resource);
private static ResourceProfile ScProfiler <T>(IEntityResource <T> r) where T : class => StarcounterOperations <T> .Profile(r);
internal static IEnumerable <T> Validate <T>(this IEnumerable <T> e, IEntityResource <T> resource) where T : class => resource.Validate(e);
public OrderByDescending(IEntityResource resource, Term term) : base(resource, term) { }
/// <summary> /// Output terms are terms that refer to properties in RESTable output. If they refer to /// a property in the dynamic domain, they are not cached. /// </summary> public Term MakeOutputTerm(IEntityResource target, string key, ICollection <string> dynamicDomain) => dynamicDomain == null ? MakeOrGetCachedTerm(target.Type, key, ".", target.OutputBindingRule) : Parse(target.Type, key, ".", target.OutputBindingRule, dynamicDomain);