예제 #1
0
        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);
        }
예제 #3
0
        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));
 });
예제 #5
0
 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;
 }
예제 #6
0
        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);
            }
        }
예제 #7
0
        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);
        }
예제 #8
0
 internal OrderBy(IEntityResource resource, Term term)
 {
     Resource = resource;
     Term     = term;
 }
예제 #9
0
        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);
        }
예제 #10
0
 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);
예제 #12
0
        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);
            }
        }
예제 #13
0
        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);
        }
예제 #14
0
 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);
 }
예제 #17
0
 /// <inheritdoc />
 public OrderByAscending(IEntityResource resource, string key, ICollection <string> dynamicMembers) : base(resource, key, dynamicMembers)
 {
 }
예제 #18
0
 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)));
 }
예제 #20
0
 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);
예제 #22
0
 internal Select(IEntityResource resource, string keys, ICollection <string> dynDomain) => keys
 /// <inheritdoc />
 protected override ResourceProfile DefaultProfile <T>(IEntityResource <T> resource) => DDictionaryOperations <T> .Profile(resource);
예제 #24
0
 private static ResourceProfile ScProfiler <T>(IEntityResource <T> r) where T : class => StarcounterOperations <T> .Profile(r);
예제 #25
0
 internal static IEnumerable <T> Validate <T>(this IEnumerable <T> e, IEntityResource <T> resource) where T : class => resource.Validate(e);
예제 #26
0
 public OrderByDescending(IEntityResource resource, Term term) : base(resource, term)
 {
 }
예제 #27
0
 /// <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);