Giter Site home page Giter Site logo

Comments (15)

staabm avatar staabm commented on June 2, 2024

interessting stuff... the addNull is there because you added it with #478 for the case of aggregate functions, to enforce it can get null :)

I need to think about it

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

I wonder whether these addNull's are correct or whether we should leave this decision to the SQL AST type inference

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

the AST cannot know this I think. fetchSingle will return first column from first row.

For example using your database structure.

$this->database->fetchSingle('select adaid from ada')

AST will tell me that adaid is int<0,max> and never null, right? But fetchSIngle will correctly return int<0,max>|null because it will be null when ada is empty.

But in case

$this->database->fetchSingle('select count(*) from ada')

right now it will return int|null but in reality it should never be null

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

shouldn't the dibi api then also return null for $this->database->fetchSingle('select count(*) from ada') when ada is empty? (I am asking stupid questions since I never used dibi)

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

no, because it will never be null, it will be some number (the count), in case of empty table 0

Screenshot 2023-03-16 at 9 18 58

Screenshot 2023-03-16 at 9 19 12

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

the motivation behind this is that I started using new phpstan rules https://github.com/shipmonk-rnd/phpstan-rules, ru and it now throws phptan error that I am comparing int|null > int in code

$count = $this->database->fetchSingle('select adaid from ada');

if ($count > 0) {
    ....
}

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

I see thx.

per your comment

$count = $this->database->fetchSingle('select adaid from ada');
if ($count > 0) {
    ....
}

can return null, so it will not help you against the error the shipmonk rule is reporting.

it would only help for similar logik with a different query (like your count case):

$count = $this->database->fetchSingle('select count(adaid) from ada');
if ($count > 0) {
    ....
}

right?

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

yes, my bad, was copying the query and chose the wrong one. should have been the count query

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

do other apis like mysqli, mysql, pdo etc also return null when 'select adaid from ada' is used on a empty table?

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

i do not work with other apis but I havent seen a method that works like fetchSingle - that returns only the first column from the first row only. They usually have methods to fetch row, fetch assoc but not fetchOneSingle field.

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

After my first morning coffee, I think there is an easy solution:

within the class which implements your database access implement

public function fetchCount($query): int {
  $count = $this->fetchSingle($query);
  if ($count === null) {
    throw new RuntimeException('count() can never be null');
  }
  return $count;
}

and use it instead of what you have right now:

$count = $db->fetchCount('select count(adaid) from ada');

I don't think we can solve it in phpstan-dba itself. I will close the issue now. feel free to comment/discuss further though.

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

well there certainly are some dirty workaround that would solve it phpstan-dba, first one coming to mind

--- a/vendor/staabm/phpstan-dba/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php
+++ b/vendor/staabm/phpstan-dba/src/Extensions/DibiConnectionFetchDynamicReturnTypeExtension.php
@@ -88,7 +88,7 @@ final class DibiConnectionFetchDynamicReturnTypeExtension implements DynamicMeth
                 return null;
             }
 
-            $fetchResultType = $this->reduceResultType($methodReflection, $resultType);
+            $fetchResultType = $this->reduceResultType($methodReflection, $resultType, $queryString);
             if (null === $fetchResultType) {
                 return null;
             }
@@ -106,7 +106,7 @@ final class DibiConnectionFetchDynamicReturnTypeExtension implements DynamicMeth
         return null;
     }
 
-    private function reduceResultType(MethodReflection $methodReflection, Type $resultType): ?Type
+    private function reduceResultType(MethodReflection $methodReflection, Type $resultType, string $queryString): ?Type
     {
         $methodName = $methodReflection->getName();
 
@@ -117,6 +117,10 @@ final class DibiConnectionFetchDynamicReturnTypeExtension implements DynamicMeth
         } elseif ('fetchPairs' === $methodName && $resultType instanceof ConstantArrayType && 2 === \count($resultType->getValueTypes())) {
             return new ArrayType($resultType->getValueTypes()[0], $resultType->getValueTypes()[1]);
         } elseif ('fetchSingle' === $methodName && $resultType instanceof ConstantArrayType && 1 === \count($resultType->getValueTypes())) {
+            if (str_starts_with($queryString, 'select count(')) {
+                return $resultType->getValueTypes()[0];
+            }
+
             return TypeCombinator::addNull($resultType->getValueTypes()[0]);
         }

but its too hacky to be merged, I guess :)

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

but its too hacky to be merged, I guess :)

absolutely. ;)

and my above example is pretty clean on your end

from phpstan-dba.

jakubvojacek avatar jakubvojacek commented on June 2, 2024

yes i guess i will do that since I use my fork of dibi anyway. But might have to do custom phpstan rule that will check query and if it starts with select count(, it will scream if used with fetchSingle instead of fetchCount (since I know I'd forget to use it sometimes)

Ok thanks 👍

from phpstan-dba.

staabm avatar staabm commented on June 2, 2024

phpstan will cry at you because of the NULL value anyway - but sure why not :)

from phpstan-dba.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.